Browse Source

respect egg files that request a format using fewer channels than an image actually contains

David Rose 23 years ago
parent
commit
0387fd286f

+ 34 - 1
pandatool/src/egg-palettize/eggFile.cxx

@@ -28,6 +28,7 @@
 #include "eggData.h"
 #include "eggData.h"
 #include "eggGroup.h"
 #include "eggGroup.h"
 #include "eggTextureCollection.h"
 #include "eggTextureCollection.h"
+#include "eggComment.h"
 #include "datagram.h"
 #include "datagram.h"
 #include "datagramIterator.h"
 #include "datagramIterator.h"
 #include "bamReader.h"
 #include "bamReader.h"
@@ -60,8 +61,10 @@ EggFile() {
 void EggFile::
 void EggFile::
 from_command_line(EggData *data,
 from_command_line(EggData *data,
                   const Filename &source_filename,
                   const Filename &source_filename,
-                  const Filename &dest_filename) {
+                  const Filename &dest_filename,
+                  const string &egg_comment) {
   _data = data;
   _data = data;
+  remove_backstage(_data);
 
 
   // We save the current directory at the time the egg file appeared
   // We save the current directory at the time the egg file appeared
   // on the command line, so that we'll later be able to properly
   // on the command line, so that we'll later be able to properly
@@ -73,6 +76,11 @@ from_command_line(EggData *data,
   _dest_filename = dest_filename;
   _dest_filename = dest_filename;
   _dest_filename.make_absolute();
   _dest_filename.make_absolute();
 
 
+  // We also save the command line that loaded this egg file, so we
+  // can continue to write it as a comment to the beginning of the egg
+  // file, should we need to rewrite it later.
+  _egg_comment = egg_comment;
+
   // We save the default PaletteGroup at this point, because the egg
   // We save the default PaletteGroup at this point, because the egg
   // file inherits the default group that was in effect when it was
   // file inherits the default group that was in effect when it was
   // specified on the command line.
   // specified on the command line.
@@ -311,6 +319,23 @@ build_cross_links() {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggFile::apply_properties_to_source
+//       Access: Public
+//  Description: Calls apply_properties_to_source() for each texture
+//               reference, updating all the referenced source
+//               textures with the complete set of property
+//               information from this egg file.
+////////////////////////////////////////////////////////////////////
+void EggFile::
+apply_properties_to_source() {
+  Textures::const_iterator ti;
+  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
+    TextureReference *reference = (*ti);
+    reference->apply_properties_to_source();
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggFile::choose_placements
 //     Function: EggFile::choose_placements
 //       Access: Public
 //       Access: Public
@@ -452,6 +477,10 @@ read_egg() {
   _data = data;
   _data = data;
   remove_backstage(_data);
   remove_backstage(_data);
 
 
+  // Replace the comment that shows how we first generated the egg
+  // file.
+  _data->insert(_data->begin(), new EggComment("", _egg_comment));
+
   return true;
   return true;
 }
 }
 
 
@@ -582,6 +611,7 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
   datagram.add_string(FilenameUnifier::make_bam_filename(_current_directory));
   datagram.add_string(FilenameUnifier::make_bam_filename(_current_directory));
   datagram.add_string(FilenameUnifier::make_bam_filename(_source_filename));
   datagram.add_string(FilenameUnifier::make_bam_filename(_source_filename));
   datagram.add_string(FilenameUnifier::make_bam_filename(_dest_filename));
   datagram.add_string(FilenameUnifier::make_bam_filename(_dest_filename));
+  datagram.add_string(_egg_comment);
 
 
   datagram.add_uint32(_textures.size());
   datagram.add_uint32(_textures.size());
   Textures::iterator ti;
   Textures::iterator ti;
@@ -664,6 +694,9 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   _current_directory = FilenameUnifier::get_bam_filename(scan.get_string());
   _current_directory = FilenameUnifier::get_bam_filename(scan.get_string());
   _source_filename = FilenameUnifier::get_bam_filename(scan.get_string());
   _source_filename = FilenameUnifier::get_bam_filename(scan.get_string());
   _dest_filename = FilenameUnifier::get_bam_filename(scan.get_string());
   _dest_filename = FilenameUnifier::get_bam_filename(scan.get_string());
+  if (Palettizer::_read_pi_version >= 9) {
+    _egg_comment = scan.get_string();
+  }
 
 
   _num_textures = scan.get_uint32();
   _num_textures = scan.get_uint32();
   manager->read_pointers(scan, _num_textures);
   manager->read_pointers(scan, _num_textures);

+ 4 - 2
pandatool/src/egg-palettize/eggFile.h

@@ -30,7 +30,6 @@
 
 
 #include "pset.h"
 #include "pset.h"
 
 
-class SourceTextureImage;
 class EggData;
 class EggData;
 class TextureImage;
 class TextureImage;
 
 
@@ -48,7 +47,8 @@ public:
 
 
   void from_command_line(EggData *data,
   void from_command_line(EggData *data,
                          const Filename &source_filename,
                          const Filename &source_filename,
-                         const Filename &dest_filename);
+                         const Filename &dest_filename,
+                         const string &egg_comment);
 
 
   void scan_textures();
   void scan_textures();
   void get_textures(pset<TextureImage *> &result) const;
   void get_textures(pset<TextureImage *> &result) const;
@@ -67,6 +67,7 @@ public:
   bool is_stale() const;
   bool is_stale() const;
 
 
   void build_cross_links();
   void build_cross_links();
+  void apply_properties_to_source();
   void choose_placements();
   void choose_placements();
 
 
   bool has_data() const;
   bool has_data() const;
@@ -87,6 +88,7 @@ private:
   Filename _current_directory;
   Filename _current_directory;
   Filename _source_filename;
   Filename _source_filename;
   Filename _dest_filename;
   Filename _dest_filename;
+  string _egg_comment;
 
 
   typedef pvector<TextureReference *> Textures;
   typedef pvector<TextureReference *> Textures;
   Textures _textures;
   Textures _textures;

+ 17 - 1
pandatool/src/egg-palettize/eggPalettize.cxx

@@ -290,6 +290,11 @@ describe_input_file() {
             "match the number of channels.  As above, any valid egg texture "
             "match the number of channels.  As above, any valid egg texture "
             "format may be used, e.g. force-rgba12, force-rgb5, etc.\n\n");
             "format may be used, e.g. force-rgba12, force-rgb5, etc.\n\n");
 
 
+  show_text("  generic", 10,
+            "Specifies that any image format requested by an egg file "
+            "that requests a particular bitdepth should be replaced by "
+            "its generic equivalent, e.g. rgba8 should become rgba.\n\n");
+
   show_text("  (alpha mode)", 10,
   show_text("  (alpha mode)", 10,
             "A particular alpha mode may be applied to a texture by naming "
             "A particular alpha mode may be applied to a texture by naming "
             "the alpha mode.  This may be any valid egg alpha mode, e.g. "
             "the alpha mode.  This may be any valid egg alpha mode, e.g. "
@@ -571,6 +576,15 @@ run() {
            << "than this one.  You will need to update your egg-palettize.\n";
            << "than this one.  You will need to update your egg-palettize.\n";
       exit(1);
       exit(1);
     }
     }
+
+    if (pal->_read_pi_version < pal->_min_pi_version) {
+      nout << FilenameUnifier::make_user_filename(state_filename)
+           << " was written by an old version of egg-palettize.\n\n"
+           << "You will need to make undo-pal (or simply remove the file "
+           << FilenameUnifier::make_user_filename(state_filename)
+           << " and try again).\n\n";
+      exit(1);
+    }
   }
   }
 
 
   if (_report_pi) {
   if (_report_pi) {
@@ -624,6 +638,7 @@ run() {
   }
   }
 
 
   // And process the egg files named for addition.
   // And process the egg files named for addition.
+  string egg_comment = get_exec_command();
   Eggs::const_iterator ei;
   Eggs::const_iterator ei;
   for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
   for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
     EggData *egg_data = (*ei);
     EggData *egg_data = (*ei);
@@ -632,7 +647,8 @@ run() {
     string name = source_filename.get_basename();
     string name = source_filename.get_basename();
 
 
     EggFile *egg_file = pal->get_egg_file(name);
     EggFile *egg_file = pal->get_egg_file(name);
-    egg_file->from_command_line(egg_data, source_filename, dest_filename);
+    egg_file->from_command_line(egg_data, source_filename, dest_filename,
+                                egg_comment);
 
 
     pal->_command_line_eggs.push_back(egg_file);
     pal->_command_line_eggs.push_back(egg_file);
   }
   }

+ 16 - 6
pandatool/src/egg-palettize/imageFile.cxx

@@ -130,6 +130,19 @@ get_properties() const {
   return _properties;
   return _properties;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: ImageFile::clear_basic_properties
+//       Access: Public
+//  Description: Resets the properties to a neutral state, for
+//               instance in preparation for calling
+//               update_properties() with all the known contributing
+//               properties.
+////////////////////////////////////////////////////////////////////
+void ImageFile::
+clear_basic_properties() {
+  _properties.clear_basic();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ImageFile::update_properties
 //     Function: ImageFile::update_properties
 //       Access: Public
 //       Access: Public
@@ -392,8 +405,7 @@ update_egg_tex(EggTexture *egg_tex) const {
 
 
   egg_tex->set_filename(FilenameUnifier::make_egg_filename(_filename));
   egg_tex->set_filename(FilenameUnifier::make_egg_filename(_filename));
 
 
-  if (_properties._alpha_type != (PNMFileType *)NULL &&
-      _properties.uses_alpha() &&
+  if (_properties.uses_alpha() &&
       !_alpha_filename.empty()) {
       !_alpha_filename.empty()) {
     egg_tex->set_alpha_filename(FilenameUnifier::make_egg_filename(_alpha_filename));
     egg_tex->set_alpha_filename(FilenameUnifier::make_egg_filename(_alpha_filename));
   } else {
   } else {
@@ -411,10 +423,8 @@ update_egg_tex(EggTexture *egg_tex) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void ImageFile::
 void ImageFile::
 output_filename(ostream &out) const {
 output_filename(ostream &out) const {
-  out << FilenameUnifier::make_user_filename(_filename);
-  if (_properties._alpha_type != (PNMFileType *)NULL &&
-      _properties.uses_alpha() &&
-      !_alpha_filename.empty()) {
+  out << FilenameUnifier::make_user_filename(_filename); 
+  if (_properties.uses_alpha() && !_alpha_filename.empty()) {
     out << " " << FilenameUnifier::make_user_filename(_alpha_filename);
     out << " " << FilenameUnifier::make_user_filename(_alpha_filename);
   }
   }
 }
 }

+ 1 - 0
pandatool/src/egg-palettize/imageFile.h

@@ -50,6 +50,7 @@ public:
   int get_num_channels() const;
   int get_num_channels() const;
 
 
   const TextureProperties &get_properties() const;
   const TextureProperties &get_properties() const;
+  void clear_basic_properties();
   void update_properties(const TextureProperties &properties);
   void update_properties(const TextureProperties &properties);
 
 
   void set_filename(PaletteGroup *group, const string &basename);
   void set_filename(PaletteGroup *group, const string &basename);

+ 41 - 29
pandatool/src/egg-palettize/paletteGroup.cxx

@@ -23,11 +23,13 @@
 #include "palettizer.h"
 #include "palettizer.h"
 #include "paletteImage.h"
 #include "paletteImage.h"
 
 
-#include <indent.h>
-#include <datagram.h>
-#include <datagramIterator.h>
-#include <bamReader.h>
-#include <bamWriter.h>
+#include "indent.h"
+#include "datagram.h"
+#include "datagramIterator.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "indirectCompareNames.h"
+#include "pvector.h"
 
 
 TypeHandle PaletteGroup::_type_handle;
 TypeHandle PaletteGroup::_type_handle;
 
 
@@ -491,29 +493,43 @@ write_image_info(ostream &out, int indent_level) const {
     page->write_image_info(out, indent_level);
     page->write_image_info(out, indent_level);
   }
   }
 
 
+  // Write out all the unplaced textures, in alphabetical order by name.
+  pvector<TexturePlacement *> placement_vector;
+  placement_vector.reserve(_placements.size());
   Placements::const_iterator pli;
   Placements::const_iterator pli;
   for (pli = _placements.begin(); pli != _placements.end(); ++pli) {
   for (pli = _placements.begin(); pli != _placements.end(); ++pli) {
     TexturePlacement *placement = (*pli);
     TexturePlacement *placement = (*pli);
     if (placement->get_omit_reason() != OR_none) {
     if (placement->get_omit_reason() != OR_none) {
-      indent(out, indent_level)
-        << placement->get_texture()->get_name()
-        << " unplaced because ";
-      switch (placement->get_omit_reason()) {
-      case OR_coverage:
-        out << "coverage (" << placement->get_uv_area() << ")";
-        break;
-
-      case OR_size:
-        out << "size (" << placement->get_x_size() << " "
-            << placement->get_y_size() << ")";
-        break;
-
-      default:
-        out << placement->get_omit_reason();
-      }
-      out << "\n";
+      placement_vector.push_back(placement);
     }
     }
   }
   }
+  sort(placement_vector.begin(), placement_vector.end(),
+       IndirectCompareNames<TexturePlacement>());
+
+  pvector<TexturePlacement *>::const_iterator pvi;
+  for (pvi = placement_vector.begin(); 
+       pvi != placement_vector.end();
+       ++pvi) {
+    TexturePlacement *placement = (*pvi);
+
+    indent(out, indent_level)
+      << placement->get_texture()->get_name()
+      << " unplaced because ";
+    switch (placement->get_omit_reason()) {
+    case OR_coverage:
+      out << "coverage (" << placement->get_uv_area() << ")";
+      break;
+      
+    case OR_size:
+      out << "size (" << placement->get_x_size() << " "
+          << placement->get_y_size() << ")";
+      break;
+      
+    default:
+      out << placement->get_omit_reason();
+    }
+    out << "\n";
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -716,13 +732,9 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   _dirname = scan.get_string();
   _dirname = scan.get_string();
   _dependent.fillin(scan, manager);
   _dependent.fillin(scan, manager);
 
 
-  if (Palettizer::_read_pi_version >= 3) {
-    _dependency_level = scan.get_int32();
-    _dependency_order = scan.get_int32();
-    if (Palettizer::_read_pi_version >= 4) {
-      _dirname_order = scan.get_int32();
-    }
-  }
+  _dependency_level = scan.get_int32();
+  _dependency_order = scan.get_int32();
+  _dirname_order = scan.get_int32();
 
 
   _num_placements = scan.get_uint32();
   _num_placements = scan.get_uint32();
   manager->read_pointers(scan, _num_placements);
   manager->read_pointers(scan, _num_placements);

+ 3 - 3
pandatool/src/egg-palettize/paletteGroup.h

@@ -19,13 +19,13 @@
 #ifndef PALETTEGROUP_H
 #ifndef PALETTEGROUP_H
 #define PALETTEGROUP_H
 #define PALETTEGROUP_H
 
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
 
 #include "paletteGroups.h"
 #include "paletteGroups.h"
 #include "textureProperties.h"
 #include "textureProperties.h"
 
 
-#include <namable.h>
-#include <typedWritable.h>
+#include "namable.h"
+#include "typedWritable.h"
 
 
 #include "pset.h"
 #include "pset.h"
 #include "pvector.h"
 #include "pvector.h"

+ 29 - 7
pandatool/src/egg-palettize/paletteGroups.cxx

@@ -24,6 +24,8 @@
 #include "datagramIterator.h"
 #include "datagramIterator.h"
 #include "bamReader.h"
 #include "bamReader.h"
 #include "bamWriter.h"
 #include "bamWriter.h"
+#include "indirectCompareNames.h"
+#include "pvector.h"
 
 
 TypeHandle PaletteGroups::_type_handle;
 TypeHandle PaletteGroups::_type_handle;
 
 
@@ -214,12 +216,22 @@ end() const {
 void PaletteGroups::
 void PaletteGroups::
 output(ostream &out) const {
 output(ostream &out) const {
   if (!_groups.empty()) {
   if (!_groups.empty()) {
-    Groups::const_iterator gi = _groups.begin();
-    out << (*gi)->get_name();
-    ++gi;
-    while (gi != _groups.end()) {
-      out << " " << (*gi)->get_name();
-      ++gi;
+    // Sort the group names into order by name for output.
+    pvector<PaletteGroup *> group_vector;
+    group_vector.reserve(_groups.size());
+    Groups::const_iterator gi;
+    for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
+      group_vector.push_back(*gi);
+    }
+    sort(group_vector.begin(), group_vector.end(),
+         IndirectCompareNames<PaletteGroup>());
+
+    pvector<PaletteGroup *>::const_iterator gvi = group_vector.begin();
+    out << (*gvi)->get_name();
+    ++gvi;
+    while (gvi != group_vector.end()) {
+      out << " " << (*gvi)->get_name();
+      ++gvi;
     }
     }
   }
   }
 }
 }
@@ -231,9 +243,19 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PaletteGroups::
 void PaletteGroups::
 write(ostream &out, int indent_level) const {
 write(ostream &out, int indent_level) const {
+  // Sort the group names into order by name for output.
+  pvector<PaletteGroup *> group_vector;
+  group_vector.reserve(_groups.size());
   Groups::const_iterator gi;
   Groups::const_iterator gi;
   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
-    indent(out, indent_level) << (*gi)->get_name() << "\n";
+    group_vector.push_back(*gi);
+  }
+  sort(group_vector.begin(), group_vector.end(),
+       IndirectCompareNames<PaletteGroup>());
+  
+  pvector<PaletteGroup *>::const_iterator gvi;
+  for (gvi = group_vector.begin(); gvi != group_vector.end(); ++gvi) {
+    indent(out, indent_level) << (*gvi)->get_name() << "\n";
   }
   }
 }
 }
 
 

+ 5 - 5
pandatool/src/egg-palettize/palettePage.cxx

@@ -22,11 +22,11 @@
 #include "paletteImage.h"
 #include "paletteImage.h"
 #include "paletteGroup.h"
 #include "paletteGroup.h"
 
 
-#include <indent.h>
-#include <datagram.h>
-#include <datagramIterator.h>
-#include <bamReader.h>
-#include <bamWriter.h>
+#include "indent.h"
+#include "datagram.h"
+#include "datagramIterator.h"
+#include "bamReader.h"
+#include "bamWriter.h"
 
 
 #include <algorithm>
 #include <algorithm>
 
 

+ 3 - 3
pandatool/src/egg-palettize/palettePage.h

@@ -19,12 +19,12 @@
 #ifndef PALETTEPAGE_H
 #ifndef PALETTEPAGE_H
 #define PALETTEPAGE_H
 #define PALETTEPAGE_H
 
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
 
 #include "textureProperties.h"
 #include "textureProperties.h"
 
 
-#include <namable.h>
-#include <typedWritable.h>
+#include "namable.h"
+#include "typedWritable.h"
 
 
 class PaletteGroup;
 class PaletteGroup;
 class PaletteImage;
 class PaletteImage;

+ 20 - 14
pandatool/src/egg-palettize/palettizer.cxx

@@ -41,15 +41,12 @@ Palettizer *pal = (Palettizer *)NULL;
 // allows us to easily update egg-palettize to write out additional
 // allows us to easily update egg-palettize to write out additional
 // information to its pi file, without having it increment the bam
 // information to its pi file, without having it increment the bam
 // version number for all bam and boo files anywhere in the world.
 // version number for all bam and boo files anywhere in the world.
-int Palettizer::_pi_version = 8;
-// Updated to version 1 on 12/11/00 to add _remap_char_uv.
-// Updated to version 2 on 12/19/00 to add TexturePlacement::_dest.
-// Updated to version 3 on 12/19/00 to add PaletteGroup::_dependency_order.
-// Updated to version 4 on 5/3/01 to add PaletteGroup::_dirname_order.
-// Updated to version 5 on 10/31/01 to add TextureProperties::_force_format.
-// Updated to version 6 on 3/14/02 to add TextureImage::_alpha_mode.
-// Updated to version 7 on 8/23/02 to add TextureProperties::_anisotropic_degree.
+int Palettizer::_pi_version = 9;
 // Updated to version 8 on 3/20/03 to remove extensions from texture key names.
 // Updated to version 8 on 3/20/03 to remove extensions from texture key names.
+// Updated to version 9 on 4/13/03 to add a few properties in various places.
+
+int Palettizer::_min_pi_version = 8;
+// Dropped support for versions 7 and below on 7/14/03.
 
 
 int Palettizer::_read_pi_version = 0;
 int Palettizer::_read_pi_version = 0;
 
 
@@ -475,6 +472,15 @@ process_command_line_eggs(bool force_texture_read, const Filename &state_filenam
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void Palettizer::
 void Palettizer::
 process_all(bool force_texture_read, const Filename &state_filename) {
 process_all(bool force_texture_read, const Filename &state_filename) {
+  // First, clear all the basic properties on the source texture
+  // images, so we can reapply them from the complete set of egg files
+  // and thereby ensure they are up-to-date.
+  Textures::iterator ti;
+  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
+    TextureImage *texture = (*ti).second;
+    texture->clear_source_basic_properties();
+  }
+
   // If there *were* any egg files on the command line, deal with
   // If there *were* any egg files on the command line, deal with
   // them.
   // them.
   CommandLineEggs::const_iterator ei;
   CommandLineEggs::const_iterator ei;
@@ -501,11 +507,15 @@ process_all(bool force_texture_read, const Filename &state_filename) {
   // links and back pointers and stuff.
   // links and back pointers and stuff.
   for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
   for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
     (*efi).second->build_cross_links();
     (*efi).second->build_cross_links();
+
+    // Also make sure each egg file's properties are applied to the
+    // source image (since we reset all the source image properties,
+    // above).
+    (*efi).second->apply_properties_to_source();
   }
   }
 
 
   // Now match each of the textures in the world against a line in the
   // Now match each of the textures in the world against a line in the
   // .txa file.
   // .txa file.
-  Textures::iterator ti;
   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
     TextureImage *texture = (*ti).second;
     TextureImage *texture = (*ti).second;
 
 
@@ -1017,11 +1027,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   _round_unit = scan.get_float64();
   _round_unit = scan.get_float64();
   _round_fuzz = scan.get_float64();
   _round_fuzz = scan.get_float64();
   _remap_uv = (RemapUV)scan.get_int32();
   _remap_uv = (RemapUV)scan.get_int32();
-  if (_read_pi_version < 1) {
-    _remap_char_uv = _remap_uv;
-  } else {
-    _remap_char_uv = (RemapUV)scan.get_int32();
-  }
+  _remap_char_uv = (RemapUV)scan.get_int32();
 
 
   manager->read_pointer(scan);  // _color_type
   manager->read_pointer(scan);  // _color_type
   manager->read_pointer(scan);  // _alpha_type
   manager->read_pointer(scan);  // _alpha_type

+ 1 - 0
pandatool/src/egg-palettize/palettizer.h

@@ -74,6 +74,7 @@ private:
 
 
 public:
 public:
   static int _pi_version;
   static int _pi_version;
+  static int _min_pi_version;
   static int _read_pi_version;
   static int _read_pi_version;
 
 
   enum RemapUV {
   enum RemapUV {

+ 4 - 4
pandatool/src/egg-palettize/sourceTextureImage.cxx

@@ -140,16 +140,16 @@ read_header() {
 
 
   _x_size = header.get_x_size();
   _x_size = header.get_x_size();
   _y_size = header.get_y_size();
   _y_size = header.get_y_size();
-  _properties._got_num_channels = true;
-  _properties._num_channels = header.get_num_channels();
+  int num_channels = header.get_num_channels();
 
 
   if (!_alpha_filename.empty() && _alpha_filename.exists()) {
   if (!_alpha_filename.empty() && _alpha_filename.exists()) {
     // Assume if we have an alpha filename, that we have an additional
     // Assume if we have an alpha filename, that we have an additional
     // alpha channel.
     // alpha channel.
-    if (_properties._num_channels == 1 || _properties._num_channels == 3) {
-      _properties._num_channels++;
+    if (num_channels == 1 || num_channels == 3) {
+      num_channels++;
     }
     }
   }
   }
+  _properties.set_num_channels(num_channels);
 
 
   _size_known = true;
   _size_known = true;
   _successfully_read_header = true;
   _successfully_read_header = true;

+ 71 - 47
pandatool/src/egg-palettize/textureImage.cxx

@@ -25,12 +25,14 @@
 #include "texturePlacement.h"
 #include "texturePlacement.h"
 #include "filenameUnifier.h"
 #include "filenameUnifier.h"
 
 
-#include <indent.h>
-#include <datagram.h>
-#include <datagramIterator.h>
-#include <bamReader.h>
-#include <bamWriter.h>
-#include <pnmFileType.h>
+#include "indent.h"
+#include "datagram.h"
+#include "datagramIterator.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "pnmFileType.h"
+#include "indirectCompareNames.h"
+#include "pvector.h"
 
 
 TypeHandle TextureImage::_type_handle;
 TypeHandle TextureImage::_type_handle;
 
 
@@ -235,7 +237,7 @@ force_replace() {
 //  Description: Marks all the egg files that reference this texture
 //  Description: Marks all the egg files that reference this texture
 //               stale.  Should be called only when the texture
 //               stale.  Should be called only when the texture
 //               properties change in some catastrophic way that will
 //               properties change in some catastrophic way that will
-//               required every egg file referencing it to be
+//               require every egg file referencing it to be
 //               regenerated, even if it is not palettized.
 //               regenerated, even if it is not palettized.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TextureImage::
 void TextureImage::
@@ -291,8 +293,7 @@ post_txa_file() {
       _size_known = true;
       _size_known = true;
       _x_size = source->get_x_size();
       _x_size = source->get_x_size();
       _y_size = source->get_y_size();
       _y_size = source->get_y_size();
-      _properties._got_num_channels = true;
-      _properties._num_channels = source->get_num_channels();
+      _properties.set_num_channels(source->get_num_channels());
     }
     }
   }
   }
 
 
@@ -303,26 +304,28 @@ post_txa_file() {
     _y_size = _request._y_size;
     _y_size = _request._y_size;
   }
   }
 
 
-  // Examine the image to determine if we can downgrade the number
-  // of channels, for instance from color to grayscale.
-  if (_properties._got_num_channels &&
-      (_properties._num_channels == 3 || _properties._num_channels == 4)) {
-    consider_grayscale();
-  }
-
-  // Also consider the alpha properties, and whether we should
-  // downgrade from alpha to non-alpha.
-  if (_properties._got_num_channels &&
-      (_properties._num_channels == 2 || _properties._num_channels == 4)) {
-    consider_alpha();
+  if (_properties.has_num_channels()) {
+    int num_channels = _properties.get_num_channels();
+    // Examine the image to determine if we can downgrade the number
+    // of channels, for instance from color to grayscale.
+    if (num_channels == 3 || num_channels == 4) {
+      consider_grayscale();
+    }
+    
+    // Also consider the alpha properties, and whether we should
+    // downgrade from alpha to non-alpha.
+    if (num_channels == 2 || num_channels == 4) {
+      consider_alpha();
+    }
   }
   }
 
 
   // However, if we got an explicit request for channels, honor that.
   // However, if we got an explicit request for channels, honor that.
   if (_request._got_num_channels) {
   if (_request._got_num_channels) {
-    _properties._got_num_channels = true;
-    _properties._num_channels = _request._num_channels;
+    _properties.set_num_channels(_request._num_channels);
   }
   }
 
 
+  _properties._generic_format = _request._generic_format;
+
   if (_request._format != EggTexture::F_unspecified) {
   if (_request._format != EggTexture::F_unspecified) {
     _properties._format = _request._format;
     _properties._format = _request._format;
     _properties._force_format = _request._force_format;
     _properties._force_format = _request._force_format;
@@ -365,11 +368,13 @@ post_txa_file() {
     _alpha_mode = _request._alpha_mode;
     _alpha_mode = _request._alpha_mode;
   }
   }
 
 
-  // On the other hand, if we don't use alpha, we shouldn't have an
-  // alpha mode.
-  if (_properties._got_num_channels &&
-      (_properties._num_channels == 1 || _properties._num_channels == 3)) {
-    _alpha_mode = EggRenderMode::AM_unspecified;
+  // On the other hand, if we don't have an alpha channel, we
+  // shouldn't have an alpha mode.
+  if (_properties.has_num_channels()) {
+    int num_channels = _properties.get_num_channels();
+    if (num_channels == 1 || num_channels == 3) {
+      _alpha_mode = EggRenderMode::AM_unspecified;
+    }
   }
   }
 
 
   // If we've changed the alpha mode, we should also mark the eggs
   // If we've changed the alpha mode, we should also mark the eggs
@@ -610,6 +615,23 @@ get_preferred_source() {
   return _preferred_source;
   return _preferred_source;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextureImage::clear_source_basic_properties
+//       Access: Public
+//  Description: Calls clear_basic_properties() on each source texture
+//               image used by this texture, to reset the properties
+//               in preparation for re-applying them from the set of
+//               all known egg files.
+////////////////////////////////////////////////////////////////////
+void TextureImage::
+clear_source_basic_properties() {
+  Sources::iterator si;
+  for (si = _sources.begin(); si != _sources.end(); ++si) {
+    SourceTextureImage *source = (*si).second;
+    source->clear_basic_properties();
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureImage::copy_unplaced
 //     Function: TextureImage::copy_unplaced
 //       Access: Public
 //       Access: Public
@@ -770,11 +792,21 @@ write_source_pathnames(ostream &out, int indent_level) const {
 
 
   // Now write out the group assignments.
   // Now write out the group assignments.
   if (!_egg_files.empty()) {
   if (!_egg_files.empty()) {
-    indent(out, indent_level)
-      << "Used by:\n";
+    // Sort the egg files into order by name for output.
+    pvector<EggFile *> egg_vector;
+    egg_vector.reserve(_egg_files.size());
     EggFiles::const_iterator ei;
     EggFiles::const_iterator ei;
     for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
     for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
-      EggFile *egg = (*ei);
+      egg_vector.push_back(*ei);
+    }
+    sort(egg_vector.begin(), egg_vector.end(),
+         IndirectCompareNames<EggFile>());
+
+    indent(out, indent_level)
+      << "Used by:\n";
+    pvector<EggFile *>::const_iterator evi;
+    for (evi = egg_vector.begin(); evi != egg_vector.end(); ++evi) {
+      EggFile *egg = (*evi);
       indent(out, indent_level + 2)
       indent(out, indent_level + 2)
         << egg->get_name() << " (";
         << egg->get_name() << " (";
       if (egg->get_explicit_groups().empty()) {
       if (egg->get_explicit_groups().empty()) {
@@ -994,12 +1026,12 @@ consider_grayscale() {
   // Since this isn't likely to change for a particular texture after
   // Since this isn't likely to change for a particular texture after
   // its creation, we save a bit of time by not performing this check
   // its creation, we save a bit of time by not performing this check
   // unless this is the first time we've ever seen this texture.  This
   // unless this is the first time we've ever seen this texture.  This
-  // will save us from having to load the texture images time we look
-  // at them.  On the other hand, if we've already loaded up the
+  // will save us from having to load the texture images each time we
+  // look at them.  On the other hand, if we've already loaded up the
   // image, then go ahead.
   // image, then go ahead.
   if (!_read_source_image && _ever_read_image) {
   if (!_read_source_image && _ever_read_image) {
     if (_forced_grayscale) {
     if (_forced_grayscale) {
-      _properties._num_channels -= 2;
+      _properties.force_grayscale();
     }
     }
     return;
     return;
   }
   }
@@ -1021,7 +1053,7 @@ consider_grayscale() {
   }
   }
 
 
   // All pixels in the image were grayscale!
   // All pixels in the image were grayscale!
-  _properties._num_channels -= 2;
+  _properties.force_grayscale();
   _forced_grayscale = true;
   _forced_grayscale = true;
 }
 }
 
 
@@ -1067,14 +1099,12 @@ consider_alpha() {
   if (_alpha_bits != 0) {
   if (_alpha_bits != 0) {
     if (_alpha_bits == AB_one) {
     if (_alpha_bits == AB_one) {
       // All alpha pixels are white; drop the alpha channel.
       // All alpha pixels are white; drop the alpha channel.
-      nassertv(_properties._num_channels == 2 || _properties._num_channels == 4);
-      _properties._num_channels--;
+      _properties.force_nonalpha();
 
 
     } else if (_alpha_bits == AB_zero) {
     } else if (_alpha_bits == AB_zero) {
       // All alpha pixels are invisible; this is probably a mistake.
       // All alpha pixels are invisible; this is probably a mistake.
       // Drop the alpha channel and complain.
       // Drop the alpha channel and complain.
-      nassertv(_properties._num_channels == 2 || _properties._num_channels == 4);
-      _properties._num_channels--;
+      _properties.force_nonalpha();
       if (_read_source_image) {
       if (_read_source_image) {
         nout << *this << " has an all-zero alpha channel; dropping alpha.\n";
         nout << *this << " has an all-zero alpha channel; dropping alpha.\n";
       }
       }
@@ -1343,14 +1373,8 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   _is_surprise = scan.get_bool();
   _is_surprise = scan.get_bool();
   _ever_read_image = scan.get_bool();
   _ever_read_image = scan.get_bool();
   _forced_grayscale = scan.get_bool();
   _forced_grayscale = scan.get_bool();
-  if (pal->_read_pi_version >= 6) {
-    _alpha_bits = scan.get_uint8();
-    _alpha_mode = (EggRenderMode::AlphaMode)scan.get_int16();
-  } else {
-    scan.get_uint8();
-    _alpha_bits = -1;
-    _alpha_mode = EggRenderMode::AM_unspecified;
-  }
+  _alpha_bits = scan.get_uint8();
+  _alpha_mode = (EggRenderMode::AlphaMode)scan.get_int16();
 
 
   _actual_assigned_groups.fillin(scan, manager);
   _actual_assigned_groups.fillin(scan, manager);
 
 

+ 1 - 0
pandatool/src/egg-palettize/textureImage.h

@@ -80,6 +80,7 @@ public:
                                  const Filename &alpha_filename);
                                  const Filename &alpha_filename);
 
 
   SourceTextureImage *get_preferred_source();
   SourceTextureImage *get_preferred_source();
+  void clear_source_basic_properties();
 
 
   void copy_unplaced(bool redo_all);
   void copy_unplaced(bool redo_all);
 
 

+ 23 - 16
pandatool/src/egg-palettize/texturePlacement.cxx

@@ -25,12 +25,12 @@
 #include "eggFile.h"
 #include "eggFile.h"
 #include "destTextureImage.h"
 #include "destTextureImage.h"
 
 
-#include <indent.h>
-#include <datagram.h>
-#include <datagramIterator.h>
-#include <bamReader.h>
-#include <bamWriter.h>
-#include <pnmImage.h>
+#include "indent.h"
+#include "datagram.h"
+#include "datagramIterator.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "pnmImage.h"
 
 
 TypeHandle TexturePlacement::_type_handle;
 TypeHandle TexturePlacement::_type_handle;
 
 
@@ -98,6 +98,17 @@ TexturePlacement::
   _group->unplace(this);
   _group->unplace(this);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePlacement::get_name
+//       Access: Public
+//  Description: Returns the name of the texture that this placement
+//               represents.
+////////////////////////////////////////////////////////////////////
+const string &TexturePlacement::
+get_name() const {
+  return _texture->get_name();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TexturePlacement::get_texture
 //     Function: TexturePlacement::get_texture
 //       Access: Public
 //       Access: Public
@@ -213,7 +224,7 @@ get_dest() const {
 //               file is unknown).
 //               file is unknown).
 //
 //
 //               After this returns true, get_x_size() and
 //               After this returns true, get_x_size() and
-//               get_y_size() can be safely called.
+//               get_y_size() may safely be called.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool TexturePlacement::
 bool TexturePlacement::
 determine_size() {
 determine_size() {
@@ -328,6 +339,7 @@ determine_size() {
     // explicitly, or because of its size or coverage, now it seems to
     // explicitly, or because of its size or coverage, now it seems to
     // fit.
     // fit.
     force_replace();
     force_replace();
+    mark_eggs_stale();
     _omit_reason = OR_working;
     _omit_reason = OR_working;
 
 
   } else if (is_placed()) {
   } else if (is_placed()) {
@@ -981,12 +993,10 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
   }
   }
   index++;
   index++;
 
 
-  if (Palettizer::_read_pi_version >= 2) {
-    if (p_list[index] != (TypedWritable *)NULL) {
-      DCAST_INTO_R(_dest, p_list[index], index);
-    }
-    index++;
+  if (p_list[index] != (TypedWritable *)NULL) {
+    DCAST_INTO_R(_dest, p_list[index], index);
   }
   }
+  index++;
 
 
   int i;
   int i;
   for (i = 0; i < _num_references; i++) {
   for (i = 0; i < _num_references; i++) {
@@ -1032,10 +1042,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   manager->read_pointer(scan);  // _texture
   manager->read_pointer(scan);  // _texture
   manager->read_pointer(scan);  // _group
   manager->read_pointer(scan);  // _group
   manager->read_pointer(scan);  // _image
   manager->read_pointer(scan);  // _image
-
-  if (Palettizer::_read_pi_version >= 2) {
-    manager->read_pointer(scan);  // _dest
-  }
+  manager->read_pointer(scan);  // _dest
 
 
   _has_uvs = scan.get_bool();
   _has_uvs = scan.get_bool();
   _size_known = scan.get_bool();
   _size_known = scan.get_bool();

+ 4 - 3
pandatool/src/egg-palettize/texturePlacement.h

@@ -19,13 +19,13 @@
 #ifndef TEXTUREPLACEMENT_H
 #ifndef TEXTUREPLACEMENT_H
 #define TEXTUREPLACEMENT_H
 #define TEXTUREPLACEMENT_H
 
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
 
 #include "omitReason.h"
 #include "omitReason.h"
 #include "texturePosition.h"
 #include "texturePosition.h"
 
 
-#include <typedWritable.h>
-#include <luse.h>
+#include "typedWritable.h"
+#include "luse.h"
 
 
 #include "pset.h"
 #include "pset.h"
 
 
@@ -54,6 +54,7 @@ public:
   TexturePlacement(TextureImage *texture, PaletteGroup *group);
   TexturePlacement(TextureImage *texture, PaletteGroup *group);
   ~TexturePlacement();
   ~TexturePlacement();
 
 
+  const string &get_name() const;
   TextureImage *get_texture() const;
   TextureImage *get_texture() const;
   const TextureProperties &get_properties() const;
   const TextureProperties &get_properties() const;
   PaletteGroup *get_group() const;
   PaletteGroup *get_group() const;

+ 184 - 39
pandatool/src/egg-palettize/textureProperties.cxx

@@ -18,7 +18,6 @@
 
 
 #include "textureProperties.h"
 #include "textureProperties.h"
 #include "palettizer.h"
 #include "palettizer.h"
-#include <stdio.h>
 #include "pnmFileType.h"
 #include "pnmFileType.h"
 #include "datagram.h"
 #include "datagram.h"
 #include "datagramIterator.h"
 #include "datagramIterator.h"
@@ -36,8 +35,10 @@ TextureProperties::
 TextureProperties() {
 TextureProperties() {
   _got_num_channels = false;
   _got_num_channels = false;
   _num_channels = 0;
   _num_channels = 0;
+  _effective_num_channels = 0;
   _format = EggTexture::F_unspecified;
   _format = EggTexture::F_unspecified;
   _force_format = false;
   _force_format = false;
+  _generic_format = false;
   _minfilter = EggTexture::FT_unspecified;
   _minfilter = EggTexture::FT_unspecified;
   _magfilter = EggTexture::FT_unspecified;
   _magfilter = EggTexture::FT_unspecified;
   _anisotropic_degree = 0;
   _anisotropic_degree = 0;
@@ -52,15 +53,17 @@ TextureProperties() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 TextureProperties::
 TextureProperties::
 TextureProperties(const TextureProperties &copy) :
 TextureProperties(const TextureProperties &copy) :
-  _got_num_channels(copy._got_num_channels),
-  _num_channels(copy._num_channels),
   _format(copy._format),
   _format(copy._format),
   _force_format(copy._force_format),
   _force_format(copy._force_format),
+  _generic_format(copy._generic_format),
   _minfilter(copy._minfilter),
   _minfilter(copy._minfilter),
   _magfilter(copy._magfilter),
   _magfilter(copy._magfilter),
   _anisotropic_degree(copy._anisotropic_degree),
   _anisotropic_degree(copy._anisotropic_degree),
   _color_type(copy._color_type),
   _color_type(copy._color_type),
-  _alpha_type(copy._alpha_type)
+  _alpha_type(copy._alpha_type),
+  _got_num_channels(copy._got_num_channels),
+  _num_channels(copy._num_channels),
+  _effective_num_channels(copy._effective_num_channels)
 {
 {
 }
 }
 
 
@@ -71,15 +74,34 @@ TextureProperties(const TextureProperties &copy) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TextureProperties::
 void TextureProperties::
 operator = (const TextureProperties &copy) {
 operator = (const TextureProperties &copy) {
-  _got_num_channels = copy._got_num_channels;
-  _num_channels = copy._num_channels;
-  _format = copy._format;
   _force_format = copy._force_format;
   _force_format = copy._force_format;
+  _generic_format = copy._generic_format;
   _minfilter = copy._minfilter;
   _minfilter = copy._minfilter;
   _magfilter = copy._magfilter;
   _magfilter = copy._magfilter;
   _anisotropic_degree = copy._anisotropic_degree;
   _anisotropic_degree = copy._anisotropic_degree;
   _color_type = copy._color_type;
   _color_type = copy._color_type;
   _alpha_type = copy._alpha_type;
   _alpha_type = copy._alpha_type;
+  _got_num_channels = copy._got_num_channels;
+  _num_channels = copy._num_channels;
+  _effective_num_channels = copy._effective_num_channels;
+  _format = copy._format;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureProperties::clear_basic
+//       Access: Public
+//  Description: Resets only the properties that might be changed by
+//               update_properties() to a neutral state.
+////////////////////////////////////////////////////////////////////
+void TextureProperties::
+clear_basic() {
+  if (!_force_format) {
+    _format = EggTexture::F_unspecified;
+  }
+
+  _minfilter = EggTexture::FT_unspecified;
+  _magfilter = EggTexture::FT_unspecified;
+  _anisotropic_degree = 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -102,7 +124,50 @@ has_num_channels() const {
 int TextureProperties::
 int TextureProperties::
 get_num_channels() const {
 get_num_channels() const {
   nassertr(_got_num_channels, 0);
   nassertr(_got_num_channels, 0);
-  return _num_channels;
+  return _effective_num_channels;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureProperties::set_num_channels
+//       Access: Public
+//  Description: Sets the number of channels (1 through 4)
+//               associated with the image, presumably after reading
+//               this information from the image header.
+////////////////////////////////////////////////////////////////////
+void TextureProperties::
+set_num_channels(int num_channels) {
+  _num_channels = num_channels;
+  _effective_num_channels = num_channels;
+  _got_num_channels = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureProperties::force_grayscale
+//       Access: Public
+//  Description: Sets the actual number of channels to indicate a
+//               grayscale image, presumably after discovering that
+//               the image contains no colored pixels.
+////////////////////////////////////////////////////////////////////
+void TextureProperties::
+force_grayscale() {
+  nassertv(_got_num_channels && _num_channels >= 3);
+  _num_channels -= 2;
+  _effective_num_channels = _num_channels;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureProperties::force_nonalpha
+//       Access: Public
+//  Description: Sets the actual number of channels to indicate an
+//               image with no alpha channel, presumably after
+//               discovering that the alpha channel contains no
+//               meaningful pixels.
+////////////////////////////////////////////////////////////////////
+void TextureProperties::
+force_nonalpha() {
+  nassertv(_got_num_channels && (_num_channels == 2 || _num_channels == 4));
+  _num_channels--;
+  _effective_num_channels = _num_channels;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -128,14 +193,6 @@ uses_alpha() const {
   default:
   default:
     return false;
     return false;
   }
   }
-
-  /*
-  if (!_force_format) {
-    return (_num_channels == 2 || _num_channels == 4);
-  }
-
-  return false;
-  */
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -153,7 +210,7 @@ get_string() const {
 
 
   if (_got_num_channels) {
   if (_got_num_channels) {
     ostringstream num;
     ostringstream num;
-    num << _num_channels;
+    num << _effective_num_channels;
     result += num.str();
     result += num.str();
   }
   }
 
 
@@ -176,6 +233,7 @@ update_properties(const TextureProperties &other) {
   if (!_got_num_channels) {
   if (!_got_num_channels) {
     _got_num_channels = other._got_num_channels;
     _got_num_channels = other._got_num_channels;
     _num_channels = other._num_channels;
     _num_channels = other._num_channels;
+    _effective_num_channels = _num_channels;
   }
   }
   if (_force_format) {
   if (_force_format) {
     // If we've forced our own format, it doesn't change.
     // If we've forced our own format, it doesn't change.
@@ -189,7 +247,6 @@ update_properties(const TextureProperties &other) {
   _magfilter = union_filter(_magfilter, other._magfilter);
   _magfilter = union_filter(_magfilter, other._magfilter);
 
 
   _anisotropic_degree = other._anisotropic_degree;
   _anisotropic_degree = other._anisotropic_degree;
-  // printf("set aniso degree to %d\n",_anisotropic_degree);
 
 
   if (_color_type == (PNMFileType *)NULL) {
   if (_color_type == (PNMFileType *)NULL) {
     _color_type = other._color_type;
     _color_type = other._color_type;
@@ -241,7 +298,44 @@ fully_define() {
     _got_num_channels = true;
     _got_num_channels = true;
   }
   }
 
 
-  // Make sure the format reflects the number of channels.
+  _effective_num_channels = _num_channels;
+
+  // Respect the _generic_format flag.  If this is set, it means the
+  // user has indicated that we should strip off any bitcount-specific
+  // formats and replace them with the more generic equivalents.
+  if (_generic_format) {
+    switch (_format) {
+    case EggTexture::F_unspecified:
+    case EggTexture::F_rgba:
+    case EggTexture::F_rgbm:
+    case EggTexture::F_rgb:
+    case EggTexture::F_red:
+    case EggTexture::F_green:
+    case EggTexture::F_blue:
+    case EggTexture::F_alpha:
+    case EggTexture::F_luminance:
+    case EggTexture::F_luminance_alpha:
+    case EggTexture::F_luminance_alphamask:
+      break;
+
+    case EggTexture::F_rgba12:
+    case EggTexture::F_rgba8:
+    case EggTexture::F_rgba4:
+    case EggTexture::F_rgba5:
+      _format = EggTexture::F_rgba;
+      break;
+
+    case EggTexture::F_rgb12:
+    case EggTexture::F_rgb8:
+    case EggTexture::F_rgb5:
+    case EggTexture::F_rgb332:
+      _format = EggTexture::F_rgb;
+      break;
+    }
+  }
+
+  // Make sure the format reflects the number of channels, although we
+  // accept a format that ignores an alpha channel.
   if (!_force_format) {
   if (!_force_format) {
     switch (_num_channels) {
     switch (_num_channels) {
     case 1:
     case 1:
@@ -253,6 +347,13 @@ fully_define() {
       case EggTexture::F_luminance:
       case EggTexture::F_luminance:
         break;
         break;
 
 
+        // These formats suggest an alpha channel; they are quietly
+        // replaced with non-alpha equivalents.
+      case EggTexture::F_luminance_alpha:
+      case EggTexture::F_luminance_alphamask:
+        _format = EggTexture::F_luminance;
+        break;
+
       default:
       default:
         _format = EggTexture::F_luminance;
         _format = EggTexture::F_luminance;
       }
       }
@@ -263,6 +364,14 @@ fully_define() {
       case EggTexture::F_luminance_alpha:
       case EggTexture::F_luminance_alpha:
       case EggTexture::F_luminance_alphamask:
       case EggTexture::F_luminance_alphamask:
         break;
         break;
+        
+        // These formats implicitly reduce the number of channels to 1.
+      case EggTexture::F_red:
+      case EggTexture::F_green:
+      case EggTexture::F_blue:
+      case EggTexture::F_alpha:
+      case EggTexture::F_luminance:
+        break;
 
 
       default:
       default:
         _format = EggTexture::F_luminance_alpha;
         _format = EggTexture::F_luminance_alpha;
@@ -278,6 +387,8 @@ fully_define() {
       case EggTexture::F_rgb332:
       case EggTexture::F_rgb332:
         break;
         break;
 
 
+        // These formats suggest an alpha channel; they are quietly
+        // replaced with non-alpha equivalents.
       case EggTexture::F_rgba8:
       case EggTexture::F_rgba8:
         _format = EggTexture::F_rgb8;
         _format = EggTexture::F_rgb8;
         break;
         break;
@@ -287,6 +398,14 @@ fully_define() {
         _format = EggTexture::F_rgb5;
         _format = EggTexture::F_rgb5;
         break;
         break;
 
 
+        // These formats implicitly reduce the number of channels to 1.
+      case EggTexture::F_red:
+      case EggTexture::F_green:
+      case EggTexture::F_blue:
+      case EggTexture::F_alpha:
+      case EggTexture::F_luminance:
+        break;
+
       default:
       default:
         _format = EggTexture::F_rgb;
         _format = EggTexture::F_rgb;
       }
       }
@@ -302,6 +421,30 @@ fully_define() {
       case EggTexture::F_rgba5:
       case EggTexture::F_rgba5:
         break;
         break;
 
 
+        // These formats implicitly reduce the number of channels to 3.
+      case EggTexture::F_rgb:
+      case EggTexture::F_rgb12:
+      case EggTexture::F_rgb8:
+      case EggTexture::F_rgb5:
+      case EggTexture::F_rgb332:
+        _effective_num_channels = 3;
+        break;
+
+        // These formats implicitly reduce the number of channels to 2.
+      case EggTexture::F_luminance_alpha:
+      case EggTexture::F_luminance_alphamask:
+        _effective_num_channels = 2;
+        break;
+
+        // These formats implicitly reduce the number of channels to 1.
+      case EggTexture::F_red:
+      case EggTexture::F_green:
+      case EggTexture::F_blue:
+      case EggTexture::F_alpha:
+      case EggTexture::F_luminance:
+        _effective_num_channels = 1;
+        break;
+
       default:
       default:
         _format = EggTexture::F_rgba;
         _format = EggTexture::F_rgba;
       }
       }
@@ -526,19 +669,18 @@ get_filter_string(EggTexture::FilterType filter_type) {
   return "x";
   return "x";
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextureProperties::get_anisotropic_degree_string
+//       Access: Private, Static
+//  Description: Returns a short string describing the anisotropic degree.
+////////////////////////////////////////////////////////////////////
 string TextureProperties::
 string TextureProperties::
 get_anisotropic_degree_string(int aniso_degree) {
 get_anisotropic_degree_string(int aniso_degree) {
-    if(aniso_degree<=1)
-        return "";
-     else {
-         char deg_str[20];
-
-           deg_str[0]='a';
-           deg_str[1]='n';
-           sprintf(deg_str+2,"%d",aniso_degree);
-           string result(deg_str);
-           return result;
-     }
+  if (aniso_degree <= 1) {
+    return "";
+  } else {
+    return string("an") + format_string(aniso_degree);
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -637,8 +779,10 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
   TypedWritable::write_datagram(writer, datagram);
   TypedWritable::write_datagram(writer, datagram);
   datagram.add_bool(_got_num_channels);
   datagram.add_bool(_got_num_channels);
   datagram.add_int32(_num_channels);
   datagram.add_int32(_num_channels);
+  datagram.add_int32(_effective_num_channels);
   datagram.add_int32((int)_format);
   datagram.add_int32((int)_format);
   datagram.add_bool(_force_format);
   datagram.add_bool(_force_format);
+  datagram.add_bool(_generic_format);
   datagram.add_int32((int)_minfilter);
   datagram.add_int32((int)_minfilter);
   datagram.add_int32((int)_magfilter);
   datagram.add_int32((int)_magfilter);
   datagram.add_int32(_anisotropic_degree);
   datagram.add_int32(_anisotropic_degree);
@@ -703,19 +847,20 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   TypedWritable::fillin(scan, manager);
   TypedWritable::fillin(scan, manager);
   _got_num_channels = scan.get_bool();
   _got_num_channels = scan.get_bool();
   _num_channels = scan.get_int32();
   _num_channels = scan.get_int32();
+  _effective_num_channels = _num_channels;
+  if (Palettizer::_read_pi_version >= 9) {
+    _effective_num_channels = scan.get_int32();
+  }
   _format = (EggTexture::Format)scan.get_int32();
   _format = (EggTexture::Format)scan.get_int32();
-  if (Palettizer::_read_pi_version >= 5) {
-    _force_format = scan.get_bool();
-  } else {
-    _force_format = false;
+  _force_format = scan.get_bool();
+  _generic_format = false;
+  if (Palettizer::_read_pi_version >= 9) {
+    _generic_format = scan.get_bool();
   }
   }
   _minfilter = (EggTexture::FilterType)scan.get_int32();
   _minfilter = (EggTexture::FilterType)scan.get_int32();
   _magfilter = (EggTexture::FilterType)scan.get_int32();
   _magfilter = (EggTexture::FilterType)scan.get_int32();
-  if (Palettizer::_read_pi_version >= 7) {
-    _anisotropic_degree = scan.get_int32();
-  } else {
-    _anisotropic_degree = 0;
-  }
+  _anisotropic_degree = scan.get_int32();
+
   manager->read_pointer(scan);  // _color_type
   manager->read_pointer(scan);  // _color_type
   manager->read_pointer(scan);  // _alpha_type
   manager->read_pointer(scan);  // _alpha_type
 }
 }

+ 12 - 3
pandatool/src/egg-palettize/textureProperties.h

@@ -41,8 +41,13 @@ public:
   TextureProperties(const TextureProperties &copy);
   TextureProperties(const TextureProperties &copy);
   void operator = (const TextureProperties &copy);
   void operator = (const TextureProperties &copy);
 
 
+  void clear_basic();
+
   bool has_num_channels() const;
   bool has_num_channels() const;
   int get_num_channels() const;
   int get_num_channels() const;
+  void set_num_channels(int num_channels);
+  void force_grayscale();
+  void force_nonalpha();
   bool uses_alpha() const;
   bool uses_alpha() const;
 
 
   string get_string() const;
   string get_string() const;
@@ -56,10 +61,9 @@ public:
   bool operator == (const TextureProperties &other) const;
   bool operator == (const TextureProperties &other) const;
   bool operator != (const TextureProperties &other) const;
   bool operator != (const TextureProperties &other) const;
 
 
-  bool _got_num_channels;
-  int _num_channels;
   EggTexture::Format _format;
   EggTexture::Format _format;
-  bool _force_format;
+  bool _force_format;  // true when format has been explicitly specified
+  bool _generic_format; // true if 'generic' keyword, meaning rgba8 -> rgba.
   EggTexture::FilterType _minfilter, _magfilter;
   EggTexture::FilterType _minfilter, _magfilter;
   int _anisotropic_degree;
   int _anisotropic_degree;
   PNMFileType *_color_type;
   PNMFileType *_color_type;
@@ -77,6 +81,11 @@ private:
 
 
   static EggTexture::FilterType union_filter(EggTexture::FilterType a,
   static EggTexture::FilterType union_filter(EggTexture::FilterType a,
                                              EggTexture::FilterType b);
                                              EggTexture::FilterType b);
+
+  bool _got_num_channels;
+  int _num_channels;
+  int _effective_num_channels;
+
   // The TypedWritable interface follows.
   // The TypedWritable interface follows.
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();

+ 29 - 4
pandatool/src/egg-palettize/textureReference.cxx

@@ -302,9 +302,20 @@ update_egg() {
   // image wants.
   // image wants.
   TextureImage *texture = get_texture();
   TextureImage *texture = get_texture();
   if (texture != (TextureImage *)NULL) {
   if (texture != (TextureImage *)NULL) {
-    EggRenderMode::AlphaMode am = texture->get_alpha_mode();
-    if (am != EggRenderMode::AM_unspecified) {
-      _egg_tex->set_alpha_mode(am);
+    if (texture->has_num_channels() && 
+        !_egg_tex->has_alpha_channel(texture->get_num_channels())) {
+      // The egg file doesn't want to use the alpha on the texture;
+      // leave it unspecified so the egg loader can figure out whether
+      // to enable alpha or not based on the object color.
+      _egg_tex->set_alpha_mode(EggRenderMode::AM_unspecified);
+
+    } else {
+      // The egg file does want alpha, so get the alpha mode from the
+      // texture.
+      EggRenderMode::AlphaMode am = texture->get_alpha_mode();
+      if (am != EggRenderMode::AM_unspecified) {
+        _egg_tex->set_alpha_mode(am);
+      }
     }
     }
   }
   }
 
 
@@ -356,6 +367,20 @@ update_egg() {
   update_uv_range(_egg_data, pal->_remap_uv);
   update_uv_range(_egg_data, pal->_remap_uv);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextureReference::apply_properties_to_source
+//       Access: Public
+//  Description: Applies the texture properties as read from the egg
+//               file to the source image's properties.  This updates
+//               the source image with the now-known properties
+//               indicated with in the tref block of the egg file.
+////////////////////////////////////////////////////////////////////
+void TextureReference::
+apply_properties_to_source() {
+  nassertv(_source_texture != (SourceTextureImage *)NULL);
+  _source_texture->update_properties(_properties);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureReference::output
 //     Function: TextureReference::output
 //       Access: Public
 //       Access: Public
@@ -377,7 +402,7 @@ write(ostream &out, int indent_level) const {
     << get_texture()->get_name();
     << get_texture()->get_name();
 
 
   if (_uses_alpha) {
   if (_uses_alpha) {
-    out << " alpha";
+    out << " (uses alpha)";
   }
   }
 
 
   if (_any_uvs) {
   if (_any_uvs) {

+ 1 - 0
pandatool/src/egg-palettize/textureReference.h

@@ -68,6 +68,7 @@ public:
 
 
   void mark_egg_stale();
   void mark_egg_stale();
   void update_egg();
   void update_egg();
+  void apply_properties_to_source();
 
 
   void output(ostream &out) const;
   void output(ostream &out) const;
   void write(ostream &out, int indent_level = 0) const;
   void write(ostream &out, int indent_level = 0) const;

+ 1 - 0
pandatool/src/egg-palettize/textureRequest.cxx

@@ -33,6 +33,7 @@ TextureRequest() {
   _num_channels = 0;
   _num_channels = 0;
   _format = EggTexture::F_unspecified;
   _format = EggTexture::F_unspecified;
   _force_format = false;
   _force_format = false;
+  _generic_format = false;
   _minfilter = EggTexture::FT_unspecified;
   _minfilter = EggTexture::FT_unspecified;
   _magfilter = EggTexture::FT_unspecified;
   _magfilter = EggTexture::FT_unspecified;
   _anisotropic_degree = 0;
   _anisotropic_degree = 0;

+ 1 - 0
pandatool/src/egg-palettize/textureRequest.h

@@ -46,6 +46,7 @@ public:
   int _num_channels;
   int _num_channels;
   EggTexture::Format _format;
   EggTexture::Format _format;
   bool _force_format;
   bool _force_format;
+  bool _generic_format;
   EggTexture::FilterType _minfilter;
   EggTexture::FilterType _minfilter;
   EggTexture::FilterType _magfilter;
   EggTexture::FilterType _magfilter;
   int _anisotropic_degree;
   int _anisotropic_degree;

+ 12 - 0
pandatool/src/egg-palettize/txaLine.cxx

@@ -42,6 +42,7 @@ TxaLine() {
   _num_channels = 0;
   _num_channels = 0;
   _format = EggTexture::F_unspecified;
   _format = EggTexture::F_unspecified;
   _force_format = false;
   _force_format = false;
+  _generic_format = false;
   _alpha_mode = EggRenderMode::AM_unspecified;
   _alpha_mode = EggRenderMode::AM_unspecified;
   _got_margin = false;
   _got_margin = false;
   _margin = 0;
   _margin = 0;
@@ -248,6 +249,12 @@ parse(const string &line) {
           return false;
           return false;
         }
         }
 
 
+      } else if (word == "generic") {
+        // Genericize the image format by replacing bitcount-specific
+        // formats with their generic equivalents, e.g. rgba8 becomes
+        // rgba.
+        _generic_format = true;
+
       } else {
       } else {
         // Maybe it's a group name.
         // Maybe it's a group name.
         PaletteGroup *group = pal->test_palette_group(word);
         PaletteGroup *group = pal->test_palette_group(word);
@@ -421,6 +428,11 @@ match_texture(TextureImage *texture) const {
   if (_format != EggTexture::F_unspecified) {
   if (_format != EggTexture::F_unspecified) {
     request._format = _format;
     request._format = _format;
     request._force_format = _force_format;
     request._force_format = _force_format;
+    request._generic_format = false;
+  }
+
+  if (_generic_format) {
+    request._generic_format = true;
   }
   }
 
 
   if (_alpha_mode != EggRenderMode::AM_unspecified) {
   if (_alpha_mode != EggRenderMode::AM_unspecified) {

+ 1 - 0
pandatool/src/egg-palettize/txaLine.h

@@ -70,6 +70,7 @@ private:
   int _num_channels;
   int _num_channels;
   EggTexture::Format _format;
   EggTexture::Format _format;
   bool _force_format;
   bool _force_format;
+  bool _generic_format;
   EggRenderMode::AlphaMode _alpha_mode;
   EggRenderMode::AlphaMode _alpha_mode;
 
 
   int _aniso_degree;
   int _aniso_degree;