David Rose пре 25 година
родитељ
комит
6f70e0a28f

+ 11 - 2
pandatool/src/egg-palettize/eggFile.cxx

@@ -7,6 +7,8 @@
 #include "textureImage.h"
 #include "paletteGroup.h"
 #include "texturePlacement.h"
+#include "textureReference.h"
+#include "sourceTextureImage.h"
 #include "palettizer.h"
 #include "filenameUnifier.h"
 
@@ -242,8 +244,9 @@ is_stale() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: EggFile::build_cross_links
 //       Access: Public
-//  Description: Calls TextureImage::note_egg_file() for each texture
-//               the egg file references, and
+//  Description: Calls TextureImage::note_egg_file() and
+//               SourceTextureImage::increment_egg_count() for each
+//               texture the egg file references, and
 //               PaletteGroup::increment_egg_count() for each palette
 //               group it wants.  This sets up some of the back
 //               references to support determining an ideal texture
@@ -265,6 +268,12 @@ build_cross_links() {
   Textures::const_iterator ti;
   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
     (*ti)->get_texture()->note_egg_file(this);
+
+    // Actually, this may count the same egg file multiple times for a
+    // particular SourceTextureImage, since a given texture may be
+    // reference multiples times within an egg file.  No harm done,
+    // however.
+    (*ti)->get_source()->increment_egg_count();
   }
 
   PaletteGroups::const_iterator gi;

+ 18 - 2
pandatool/src/egg-palettize/eggPalettize.cxx

@@ -358,14 +358,30 @@ run() {
     okflag = false;
   }
 
-  if (!state_file.open_write(state_filename) ||
+  // Make up a temporary filename to write the state file to, then
+  // move the state file into place.  We do this in case the user
+  // interrupts us (or we core dump) before we're done; that way we
+  // won't leave the state file incompletely written.
+  string dirname = state_filename.get_dirname();
+  if (dirname.empty()) {
+    dirname = ".";
+  }
+  char *name = tempnam(dirname.c_str(), "pi");
+  Filename temp_filename(name);
+
+  if (!state_file.open_write(temp_filename) ||
       !state_file.write_object(pal)) {
-    nout << "Unable to write palettization information to " << state_filename
+    nout << "Unable to write palettization information to " << temp_filename
 	 << "\n";
     exit(1);
   }
 
   state_file.close();
+  if (!temp_filename.rename_to(state_filename)) {
+    nout << "Unable to rename temporary file " << temp_filename << " to "
+	 << state_filename << "\n";
+    exit(1);
+  }
 
   if (!okflag) {
     exit(1);

+ 13 - 13
pandatool/src/egg-palettize/palettizer.cxx

@@ -218,6 +218,13 @@ process_command_line_eggs(bool force_texture_read) {
     egg_file->post_txa_file();
   }
 
+  // Now that all of our egg files are read in, build in all the cross
+  // links and back pointers and stuff.
+  EggFiles::const_iterator efi;
+  for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
+    (*efi).second->build_cross_links();
+  }
+
   // Now match each of the textures mentioned in those egg files
   // against a line in the .txa file.
   CommandLineTextures::iterator ti;
@@ -235,13 +242,6 @@ process_command_line_eggs(bool force_texture_read) {
     texture->post_txa_file();
   }
 
-  // Now that all of our data is read in, build in all the cross links
-  // and back pointers and stuff.
-  EggFiles::const_iterator efi;
-  for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
-    (*efi).second->build_cross_links();
-  }
-
   // And now, assign each of the current set of textures to an
   // appropriate group or groups.
   for (ti = _command_line_textures.begin(); 
@@ -310,6 +310,12 @@ process_all(bool force_texture_read) {
     egg_file->post_txa_file();
   }
 
+  // Now that all of our egg files are read in, build in all the cross
+  // links and back pointers and stuff.
+  for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
+    (*efi).second->build_cross_links();
+  }
+
   // Now match each of the textures in the world against a line in the
   // .txa file.
   Textures::iterator ti;
@@ -325,12 +331,6 @@ process_all(bool force_texture_read) {
     texture->post_txa_file();
   }
 
-  // Now that all of our data is read in, build in all the cross links
-  // and back pointers and stuff.
-  for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
-    (*efi).second->build_cross_links();
-  }
-
   // And now, assign each texture to an appropriate group or groups.
   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
     TextureImage *texture = (*ti).second;

+ 30 - 2
pandatool/src/egg-palettize/sourceTextureImage.cxx

@@ -5,6 +5,7 @@
 
 #include "sourceTextureImage.h"
 #include "textureImage.h"
+#include "filenameUnifier.h"
 
 #include <pnmImageHeader.h>
 #include <datagram.h>
@@ -24,6 +25,7 @@ SourceTextureImage::
 SourceTextureImage() {
   _texture = (TextureImage *)NULL;
 
+  _egg_count = 0;
   _read_header = false;
   _successfully_read_header = false;
 }
@@ -40,6 +42,7 @@ SourceTextureImage(TextureImage *texture, const Filename &filename,
 {
   _filename = filename;
   _alpha_filename = alpha_filename;
+  _egg_count = 0;
   _read_header = false;
   _successfully_read_header = false;
 }
@@ -55,6 +58,28 @@ get_texture() const {
   return _texture;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: SourceTextureImage::increment_egg_count
+//       Access: Public
+//  Description: Increments by one the number of egg files that are
+//               known to reference this SourceTextureImage.
+////////////////////////////////////////////////////////////////////
+void SourceTextureImage::
+increment_egg_count() {
+  _egg_count++;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SourceTextureImage::get_egg_count
+//       Access: Public
+//  Description: Returns the number of egg files that share this
+//               SourceTextureImage.
+////////////////////////////////////////////////////////////////////
+int SourceTextureImage::
+get_egg_count() const {
+  return _egg_count;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: SourceTextureImage::get_size
 //       Access: Public
@@ -105,7 +130,7 @@ read_header() {
   _properties._got_num_channels = true;
   _properties._num_channels = header.get_num_channels();
 
-  if (!_alpha_filename.empty()) {
+  if (!_alpha_filename.empty() && _alpha_filename.exists()) {
     // Assume if we have an alpha filename, that we have an additional
     // alpha channel.
     if (_properties._num_channels == 1 || _properties._num_channels == 3) {
@@ -144,6 +169,9 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
   ImageFile::write_datagram(writer, datagram);
   writer->write_pointer(datagram, _texture);
 
+  // We don't store _egg_count; instead, we count these up again each
+  // session.
+
   // We don't store _read_header or _successfully_read_header in the
   // Bam file; these are transitory and we need to reread the image
   // header for each session (in case the image files change between
@@ -175,7 +203,7 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 //               allocate and return a new object with all the data
 //               read.
 ////////////////////////////////////////////////////////////////////
-TypedWriteable* SourceTextureImage::
+TypedWriteable *SourceTextureImage::
 make_SourceTextureImage(const FactoryParams &params) {
   SourceTextureImage *me = new SourceTextureImage;
   BamReader *manager;

+ 5 - 1
pandatool/src/egg-palettize/sourceTextureImage.h

@@ -26,14 +26,18 @@ public:
 		     const Filename &alpha_filename);
 
   TextureImage *get_texture() const;
+
+  void increment_egg_count();
+  int get_egg_count() const;
   
   bool get_size();
   bool read_header();
 
 private:
+  TextureImage *_texture;
+  int _egg_count;
   bool _read_header;
   bool _successfully_read_header;
-  TextureImage *_texture;
 
   // The TypedWriteable interface follows.
 public:

+ 80 - 11
pandatool/src/egg-palettize/textureImage.cxx

@@ -9,6 +9,7 @@
 #include "eggFile.h"
 #include "paletteGroup.h"
 #include "texturePlacement.h"
+#include "filenameUnifier.h"
 
 #include <indent.h>
 #include <datagram.h>
@@ -377,7 +378,6 @@ is_surprise() const {
 }
 
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureImage::get_source
 //       Access: Public
@@ -389,7 +389,8 @@ is_surprise() const {
 ////////////////////////////////////////////////////////////////////
 SourceTextureImage *TextureImage::
 get_source(const Filename &filename, const Filename &alpha_filename) {
-  string key = filename.get_fullpath() + ":" + alpha_filename.get_fullpath();
+  string key = get_source_key(filename, alpha_filename);
+
   Sources::iterator si;
   si = _sources.find(key);
   if (si != _sources.end()) {
@@ -423,13 +424,65 @@ get_preferred_source() {
   }
 
   // Now examine all of the various source images available to us and
-  // pick the most suitable.
+  // pick the most suitable.  We base this on the following criteria:
+
+  // (1) A suitable source image must be referenced by at least one
+  // egg file, unless no source images are referenced by any egg file.
+
+  // (2) A larger source image is preferable to a smaller one.
+
+  // (3) Given two source images of the same size, the more recent one
+  // is preferable.
+
+  // Are any source images referenced by an egg file?
+
+  bool any_referenced = false;
+  Sources::iterator si;
+  for (si = _sources.begin(); si != _sources.end() && !any_referenced; ++si) {
+    SourceTextureImage *source = (*si).second;
+    if (source->get_egg_count() > 0) {
+      any_referenced = true;
+    }
+  }
+
+  SourceTextureImage *best = (SourceTextureImage *)NULL;
+  int best_size;
 
-  // **** For now, we arbitrarily pick the first one.
-  if (!_sources.empty()) {
-    _preferred_source = (*_sources.begin()).second;
+  for (si = _sources.begin(); si != _sources.end() && !any_referenced; ++si) {
+    SourceTextureImage *source = (*si).second;
+
+    if (source->get_egg_count() > 0 || !any_referenced) {
+      // Rule (1) passes.
+
+      if (source->exists() && source->get_size()) {
+	int source_size = source->get_x_size() * source->get_y_size();
+	if (best == (SourceTextureImage *)NULL) {
+	  best = source;
+	  best_size = source_size;
+
+	} else if (source_size > best_size) {
+	  // Rule (2) passes.
+	  best = source;
+	  best_size = source_size;
+
+	} else if (source_size == best_size && 
+		   source->get_filename().compare_timestamps(best->get_filename()) > 0) {
+	  // Rule (3) passes.
+	  best = source;
+	  best_size = source_size;
+	}
+      }
+    }
+  }
+
+  if (best == (SourceTextureImage *)NULL && !_sources.empty()) {
+    // If we didn't pick any that pass, it must be that all of them
+    // are unreadable.  In this case, it really doesn't matter which
+    // one we pick.
+    best = (*_sources.begin()).second;
   }
 
+  _preferred_source = best;
   return _preferred_source;
 }
 
@@ -880,6 +933,20 @@ copy_new_dests(const TextureImage::Dests &a, const TextureImage::Dests &b) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextureImage::get_source_key
+//       Access: Private
+//  Description: Returns the key that a SourceTextureImage should be
+//               stored in, given its one or two filenames.
+////////////////////////////////////////////////////////////////////
+string TextureImage::
+get_source_key(const Filename &filename, const Filename &alpha_filename) {
+  Filename f = FilenameUnifier::make_bam_filename(filename);
+  Filename a = FilenameUnifier::make_bam_filename(alpha_filename);
+
+  return f.get_fullpath() + ":" + a.get_fullpath();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureImage::register_with_read_factory
 //       Access: Public, Static
@@ -976,18 +1043,20 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
   for (i = 0; i < _num_sources; i++) {
     SourceTextureImage *source;
     DCAST_INTO_R(source, plist[index], index);
-    string key = source->get_filename().get_fullpath() + ":" + 
-      source->get_alpha_filename().get_fullpath();
+    string key = get_source_key(source->get_filename(), 
+				source->get_alpha_filename());
 
-    _sources.insert(Sources::value_type(key, source));
+    bool inserted = _sources.insert(Sources::value_type(key, source)).second;
     index++;
+    nassertr(inserted, index);
   }
 
   for (i = 0; i < _num_dests; i++) {
     DestTextureImage *dest;
     DCAST_INTO_R(dest, plist[index], index);
-    _dests.insert(Dests::value_type(dest->get_filename(), dest));
+    bool inserted = _dests.insert(Dests::value_type(dest->get_filename(), dest)).second;
     index++;
+    nassertr(inserted, index);
   }
 
   return index;
@@ -1001,7 +1070,7 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 //               allocate and return a new object with all the data
 //               read.
 ////////////////////////////////////////////////////////////////////
-TypedWriteable* TextureImage::
+TypedWriteable *TextureImage::
 make_TextureImage(const FactoryParams &params) {
   TextureImage *me = new TextureImage;
   BamReader *manager;

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

@@ -87,6 +87,9 @@ private:
   void remove_old_dests(const Dests &a, const Dests &b);
   void copy_new_dests(const Dests &a, const Dests &b);
 
+  string get_source_key(const Filename &filename, 
+			const Filename &alpha_filename);
+
 private:
   TextureRequest _request;
   TextureProperties _pre_txa_properties;

+ 1 - 1
pandatool/src/egg-palettize/txaLine.cxx

@@ -322,7 +322,7 @@ match_texture(TextureImage *texture) const {
       break;
 
     case ST_scale:
-      if (source->get_size()) {
+      if (source != (SourceTextureImage *)NULL && source->get_size()) {
 	request._got_size = true;
 	request._x_size = (int)(source->get_x_size() * _scale / 100.0);
 	request._y_size = (int)(source->get_y_size() * _scale / 100.0);