diff --git a/pandatool/src/egg-palettize/eggPalettize.cxx b/pandatool/src/egg-palettize/eggPalettize.cxx index 0ffb52fb46..21235c6a56 100644 --- a/pandatool/src/egg-palettize/eggPalettize.cxx +++ b/pandatool/src/egg-palettize/eggPalettize.cxx @@ -103,6 +103,17 @@ EggPalettize() : EggMultiFilter(true) { "ever been palettized, not just the egg files that appear on " "the command line.", &EggPalettize::dispatch_none, &_all_textures); + add_option + ("egg", "", 0, + "Regenerate all egg files that need modification, even those that " + "aren't named on the command line.", + &EggPalettize::dispatch_none, &_redo_eggs); + add_option + ("redo", "", 0, + "Force a regeneration of each image from its original source(s). " + "When used in conjunction with -egg, this also forces each egg file to " + "be regenerated.", + &EggPalettize::dispatch_none, &_redo_all); add_option ("opt", "", 0, "Force an optimal packing. By default, textures are added to " @@ -111,20 +122,6 @@ EggPalettize() : EggMultiFilter(true) { "to be rebuilt if necessary to optimize the packing, but this " "may invalidate other egg files which share this palette.", &EggPalettize::dispatch_none, &_force_optimal); - add_option - ("redo", "", 0, - "Force a redo of everything. This is useful in case something " - "has gotten out of sync and the old palettes are just bad.", - &EggPalettize::dispatch_none, &_force_redo_all); - add_option - ("R", "", 0, - "Resize mostly-empty palettes to their minimal size.", - &EggPalettize::dispatch_none, &_optimal_resize); - add_option - ("egg", "", 0, - "Regenerate all egg files that need modification, even those that " - "aren't named on the command line.", - &EggPalettize::dispatch_none, &_redo_eggs); add_option ("nolock", "", 0, @@ -327,6 +324,16 @@ run() { pal->_command_line_eggs.push_back(egg_file); } + if (_force_optimal) { + // If we're asking for an optimal packing, throw away the old + // packing and start fresh. + pal->reset_images(); + _all_textures = true; + + // Also turn off the rounding-up of UV's for this purpose. + pal->_round_uvs = false; + } + if (_all_textures) { pal->process_all(); } else { @@ -334,12 +341,12 @@ run() { } if (_redo_eggs) { - if (!pal->read_stale_eggs()) { + if (!pal->read_stale_eggs(_redo_all)) { okflag = false; } } - pal->generate_images(); + pal->generate_images(_redo_all); if (!pal->write_eggs()) { okflag = false; diff --git a/pandatool/src/egg-palettize/eggPalettize.h b/pandatool/src/egg-palettize/eggPalettize.h index 1833c68576..f73df4497e 100644 --- a/pandatool/src/egg-palettize/eggPalettize.h +++ b/pandatool/src/egg-palettize/eggPalettize.h @@ -45,8 +45,7 @@ private: bool _statistics_only; bool _all_textures; bool _force_optimal; - bool _force_redo_all; - bool _optimal_resize; + bool _redo_all; bool _redo_eggs; bool _dont_lock_pi; diff --git a/pandatool/src/egg-palettize/imageFile.cxx b/pandatool/src/egg-palettize/imageFile.cxx index 74f25e622b..728893eb5b 100644 --- a/pandatool/src/egg-palettize/imageFile.cxx +++ b/pandatool/src/egg-palettize/imageFile.cxx @@ -196,8 +196,9 @@ exists() const { return false; } if (_properties._alpha_type != (PNMFileType *)NULL && - _properties.uses_alpha()) { - if (_alpha_filename.exists()) { + _properties.uses_alpha() && + !_alpha_filename.empty()) { + if (!_alpha_filename.exists()) { return false; } } diff --git a/pandatool/src/egg-palettize/paletteGroup.cxx b/pandatool/src/egg-palettize/paletteGroup.cxx index dcead03a62..401d92827f 100644 --- a/pandatool/src/egg-palettize/paletteGroup.cxx +++ b/pandatool/src/egg-palettize/paletteGroup.cxx @@ -306,6 +306,22 @@ write_image_info(ostream &out, int indent_level) const { } } +//////////////////////////////////////////////////////////////////// +// Function: PaletteGroup::reset_images +// Access: Public +// Description: Throws away all of the current PaletteImages, so that +// new ones may be created (and the packing made more +// optimal). +//////////////////////////////////////////////////////////////////// +void PaletteGroup:: +reset_images() { + Pages::iterator pai; + for (pai = _pages.begin(); pai != _pages.end(); ++pai) { + PalettePage *page = (*pai).second; + page->reset_images(); + } +} + //////////////////////////////////////////////////////////////////// // Function: PaletteGroup::update_images // Access: Public @@ -313,11 +329,11 @@ write_image_info(ostream &out, int indent_level) const { // it. //////////////////////////////////////////////////////////////////// void PaletteGroup:: -update_images() { +update_images(bool redo_all) { Pages::iterator pai; for (pai = _pages.begin(); pai != _pages.end(); ++pai) { PalettePage *page = (*pai).second; - page->update_images(); + page->update_images(redo_all); } } diff --git a/pandatool/src/egg-palettize/paletteGroup.h b/pandatool/src/egg-palettize/paletteGroup.h index 930fe450af..ad1e1f4ab4 100644 --- a/pandatool/src/egg-palettize/paletteGroup.h +++ b/pandatool/src/egg-palettize/paletteGroup.h @@ -59,7 +59,8 @@ public: void place_all(); void write_image_info(ostream &out, int indent_level = 0) const; - void update_images(); + void reset_images(); + void update_images(bool redo_all); private: string _dirname; diff --git a/pandatool/src/egg-palettize/paletteImage.cxx b/pandatool/src/egg-palettize/paletteImage.cxx index 17c815894e..d56168a344 100644 --- a/pandatool/src/egg-palettize/paletteImage.cxx +++ b/pandatool/src/egg-palettize/paletteImage.cxx @@ -9,6 +9,7 @@ #include "texturePlacement.h" #include "palettizer.h" #include "textureImage.h" +#include "filenameUnifier.h" #include #include @@ -245,6 +246,7 @@ check_solitary() { placement->omit_solitary(); } else { + // Zero or multiple. Placements::const_iterator pi; for (pi = _placements.begin(); pi != _placements.end(); ++pi) { TexturePlacement *placement = (*pi); @@ -271,14 +273,38 @@ write_placements(ostream &out, int indent_level) const { } } +//////////////////////////////////////////////////////////////////// +// Function: PaletteImage::reset_image +// Access: Public +// Description: Unpacks each texture that has been placed on this +// image, resetting the image to empty. +//////////////////////////////////////////////////////////////////// +void PaletteImage:: +reset_image() { + // We need a copy so we can modify this list as we traverse it. + Placements copy_placements = _placements; + Placements::const_iterator pi; + for (pi = copy_placements.begin(); pi != copy_placements.end(); ++pi) { + TexturePlacement *placement = (*pi); + placement->force_replace(); + } + + _placements.clear(); + _cleared_regions.clear(); + unlink(); + _new_image = true; +} + //////////////////////////////////////////////////////////////////// // Function: PaletteImage::update_image // Access: Public // Description: If the palette has changed since it was last written -// out, updates the image and writes out a new one. +// out, updates the image and writes out a new one. If +// redo_all is true, regenerates the image from scratch +// and writes it out again, whether it needed it or not. //////////////////////////////////////////////////////////////////// void PaletteImage:: -update_image() { +update_image(bool redo_all) { if (is_empty() && pal->_aggressively_clean_mapdir) { // If the palette image is 'empty', ensure that it doesn't exist. // No need to clutter up the map directory. @@ -287,6 +313,12 @@ update_image() { return; } + if (redo_all) { + // If we're redoing everything, throw out the old image anyway. + unlink(); + _new_image = true; + } + // Do we need to update? bool needs_update = _new_image || !exists() || @@ -411,7 +443,7 @@ get_image() { } } - nout << "Generating new " << get_filename() << "\n"; + nout << "Generating new " << FilenameUnifier::make_user_filename(get_filename()) << "\n"; // We won't be using this any more. _cleared_regions.clear(); diff --git a/pandatool/src/egg-palettize/paletteImage.h b/pandatool/src/egg-palettize/paletteImage.h index 53dc98222b..c06104330c 100644 --- a/pandatool/src/egg-palettize/paletteImage.h +++ b/pandatool/src/egg-palettize/paletteImage.h @@ -40,7 +40,8 @@ public: void check_solitary(); void write_placements(ostream &out, int indent_level = 0) const; - void update_image(); + void reset_image(); + void update_image(bool redo_all); private: bool find_hole(int &x, int &y, int x_size, int y_size) const; diff --git a/pandatool/src/egg-palettize/palettePage.cxx b/pandatool/src/egg-palettize/palettePage.cxx index 23f0ee49c7..045f389e13 100644 --- a/pandatool/src/egg-palettize/palettePage.cxx +++ b/pandatool/src/egg-palettize/palettePage.cxx @@ -190,6 +190,25 @@ write_image_info(ostream &out, int indent_level) const { } } +//////////////////////////////////////////////////////////////////// +// Function: PalettePage::reset_images +// Access: Public +// Description: Throws away all of the current PaletteImages, so that +// new ones may be created (and the packing made more +// optimal). +//////////////////////////////////////////////////////////////////// +void PalettePage:: +reset_images() { + Images::iterator ii; + for (ii = _images.begin(); ii != _images.end(); ++ii) { + PaletteImage *image = (*ii); + image->reset_image(); + delete image; + } + + _images.clear(); +} + //////////////////////////////////////////////////////////////////// // Function: PalettePage::update_images // Access: Public @@ -197,11 +216,11 @@ write_image_info(ostream &out, int indent_level) const { // it. //////////////////////////////////////////////////////////////////// void PalettePage:: -update_images() { +update_images(bool redo_all) { Images::iterator ii; for (ii = _images.begin(); ii != _images.end(); ++ii) { PaletteImage *image = (*ii); - image->update_image(); + image->update_image(redo_all); } } diff --git a/pandatool/src/egg-palettize/palettePage.h b/pandatool/src/egg-palettize/palettePage.h index 106740ecea..beb9799af3 100644 --- a/pandatool/src/egg-palettize/palettePage.h +++ b/pandatool/src/egg-palettize/palettePage.h @@ -41,7 +41,8 @@ public: void unplace(TexturePlacement *placement); void write_image_info(ostream &out, int indent_level = 0) const; - void update_images(); + void reset_images(); + void update_images(bool redo_all); private: PaletteGroup *_group; diff --git a/pandatool/src/egg-palettize/palettizer.cxx b/pandatool/src/egg-palettize/palettizer.cxx index df2fb3c81c..0d9296cb4f 100644 --- a/pandatool/src/egg-palettize/palettizer.cxx +++ b/pandatool/src/egg-palettize/palettizer.cxx @@ -346,23 +346,41 @@ process_all() { } //////////////////////////////////////////////////////////////////// -// Function: Palettizer::generate_images +// Function: Palettizer::reset_images // Access: Public -// Description: Actually generates the appropriate palette and -// unplaced texture images into the map directories. +// Description: Throws away all of the current PaletteImages, so that +// new ones may be created (and the packing made more +// optimal). //////////////////////////////////////////////////////////////////// void Palettizer:: -generate_images() { +reset_images() { Groups::iterator gi; for (gi = _groups.begin(); gi != _groups.end(); ++gi) { PaletteGroup *group = (*gi).second; - group->update_images(); + group->reset_images(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: Palettizer::generate_images +// Access: Public +// Description: Actually generates the appropriate palette and +// unplaced texture images into the map directories. If +// redo_all is true, this forces a regeneration of each +// image file. +//////////////////////////////////////////////////////////////////// +void Palettizer:: +generate_images(bool redo_all) { + Groups::iterator gi; + for (gi = _groups.begin(); gi != _groups.end(); ++gi) { + PaletteGroup *group = (*gi).second; + group->update_images(redo_all); } Textures::iterator ti; for (ti = _textures.begin(); ti != _textures.end(); ++ti) { TextureImage *texture = (*ti).second; - texture->copy_unplaced(); + texture->copy_unplaced(redo_all); } } @@ -372,17 +390,21 @@ generate_images() { // Description: Reads in any egg file that is known to be stale, even // if it was not listed on the command line, so that it // may be updated and written out when write_eggs() is -// called. Returns true if successful, or false if -// there was some error. +// called. If redo_all is true, this even reads egg +// files that were not flagged as stale. +// +// Returns true if successful, or false if there was +// some error. //////////////////////////////////////////////////////////////////// bool Palettizer:: -read_stale_eggs() { +read_stale_eggs(bool redo_all) { bool okflag = true; EggFiles::iterator ei; for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) { EggFile *egg_file = (*ei).second; - if (!egg_file->has_data() && egg_file->is_stale()) { + if (!egg_file->has_data() && + (egg_file->is_stale() || redo_all)) { if (!egg_file->read_egg()) { okflag = false; diff --git a/pandatool/src/egg-palettize/palettizer.h b/pandatool/src/egg-palettize/palettizer.h index 2fcc5823e5..a1ccdfd51c 100644 --- a/pandatool/src/egg-palettize/palettizer.h +++ b/pandatool/src/egg-palettize/palettizer.h @@ -37,8 +37,9 @@ public: void read_txa_file(const Filename &txa_filename); void process_command_line_eggs(); void process_all(); - void generate_images(); - bool read_stale_eggs(); + void reset_images(); + void generate_images(bool redo_all); + bool read_stale_eggs(bool redo_all); bool write_eggs(); EggFile *get_egg_file(const string &name); diff --git a/pandatool/src/egg-palettize/textureImage.cxx b/pandatool/src/egg-palettize/textureImage.cxx index 4c9287b603..b25f6c6ce4 100644 --- a/pandatool/src/egg-palettize/textureImage.cxx +++ b/pandatool/src/egg-palettize/textureImage.cxx @@ -270,6 +270,12 @@ post_txa_file() { (_properties._num_channels == 3 || _properties._num_channels == 4)) { consider_grayscale(); } + + // Also consider downgrading from alpha to non-alpha. + if (_properties._got_num_channels && + (_properties._num_channels == 2 || _properties._num_channels == 4)) { + consider_unalpha(); + } } if (_request._format != EggTexture::F_unspecified) { @@ -426,9 +432,12 @@ get_preferred_source() { // it has been unplaced. Also removes the old filenames // for previous sessions where it was unplaced, but is // no longer. +// +// If redo_all is true, this recopies the texture +// whether it needed to or not. //////////////////////////////////////////////////////////////////// void TextureImage:: -copy_unplaced() { +copy_unplaced(bool redo_all) { // First, we need to build up the set of DestTextureImages that // represents the files we need to generate. Dests generate; @@ -458,12 +467,19 @@ copy_unplaced() { } } - // Now remove the old files that we previously generated, but we - // don't need any more. - remove_old_dests(generate, _dests); + if (redo_all) { + // If we're redoing everything, we remove everything first and + // then recopy it again. + Dests empty; + remove_old_dests(empty, _dests); + copy_new_dests(generate, empty); - // And then copy in the new ones. - copy_new_dests(generate, _dests); + } else { + // Otherwise, we only remove and recopy the things that changed + // between this time and last time. + remove_old_dests(generate, _dests); + copy_new_dests(generate, _dests); + } // Clean up the old set. Dests::iterator di; @@ -697,6 +713,38 @@ consider_grayscale() { _properties._num_channels -= 2; } +//////////////////////////////////////////////////////////////////// +// Function: TextureImage::consider_unalpha +// Access: Private +// Description: Examines the actual contents of the image to +// determine if its alpha channel should be eliminated +// (e.g. it's completely white, and therefore +// pointless). +//////////////////////////////////////////////////////////////////// +void TextureImage:: +consider_unalpha() { + const PNMImage &source = read_source_image(); + if (!source.is_valid()) { + return; + } + + if (!source.has_alpha()) { + return; + } + + for (int y = 0; y < source.get_y_size(); y++) { + for (int x = 0; x < source.get_x_size(); x++) { + if (source.get_alpha_val(x, y) != source.get_maxval()) { + // Here's a non-white pixel; the alpha channel is meaningful. + return; + } + } + } + + // All alpha pixels in the image were white! + _properties._num_channels--; +} + //////////////////////////////////////////////////////////////////// // Function: TextureImage::remove_old_dests // Access: Private diff --git a/pandatool/src/egg-palettize/textureImage.h b/pandatool/src/egg-palettize/textureImage.h index 248ed9e82d..4f735739a1 100644 --- a/pandatool/src/egg-palettize/textureImage.h +++ b/pandatool/src/egg-palettize/textureImage.h @@ -63,7 +63,7 @@ public: SourceTextureImage *get_preferred_source(); - void copy_unplaced(); + void copy_unplaced(bool redo_all); const PNMImage &read_source_image(); const PNMImage &get_dest_image(); @@ -82,6 +82,7 @@ private: void assign_to_groups(const PaletteGroups &groups); void consider_grayscale(); + void consider_unalpha(); void remove_old_dests(const Dests &a, const Dests &b); void copy_new_dests(const Dests &a, const Dests &b);