فهرست منبع

*** empty log message ***

David Rose 25 سال پیش
والد
کامیت
8735480f77

+ 1 - 0
pandatool/src/egg-palettize/Sources.pp

@@ -22,6 +22,7 @@
     palettizer.cxx palettizer.h \
     sourceTextureImage.cxx sourceTextureImage.h \
     textureImage.cxx textureImage.h \
+    textureMemoryCounter.cxx textureMemoryCounter.h \
     texturePlacement.cxx texturePlacement.h \
     texturePosition.cxx texturePosition.h \
     textureProperties.cxx textureProperties.h textureReference.cxx \

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

@@ -69,7 +69,7 @@ EggPalettize() : EggMultiFilter(true) {
     ("s", "", 0, 
      "Do not process anything, but report statistics on palette "
      "and texture utilization.",
-     &EggPalettize::dispatch_none, &_statistics_only);
+     &EggPalettize::dispatch_none, &_report_statistics);
 
   // We redefine -d using add_option() instead of redescribe_option()
   // so it gets listed along with these other options that relate.
@@ -515,6 +515,11 @@ run() {
     exit(0);
   }
 
+  if (_report_statistics) {
+    pal->report_statistics();
+    exit(0);
+  }
+
   bool okflag = true;
 
   pal->read_txa_file(_txa_filename);

+ 1 - 1
pandatool/src/egg-palettize/eggPalettize.h

@@ -44,7 +44,7 @@ private:
   // The following values control behavior specific to this session.
   // They're not saved for future sessions.
   bool _report_pi;
-  bool _statistics_only;
+  bool _report_statistics;
   bool _all_textures; 
   bool _optimal;
   bool _redo_all;

+ 117 - 3
pandatool/src/egg-palettize/paletteGroup.cxx

@@ -7,6 +7,7 @@
 #include "palettePage.h"
 #include "texturePlacement.h"
 #include "textureImage.h"
+#include "palettizer.h"
 
 #include <indent.h>
 #include <datagram.h>
@@ -25,6 +26,7 @@ PaletteGroup::
 PaletteGroup() {
   _egg_count = 0;
   _dependency_level = 0;
+  _dependency_order = 0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -73,6 +75,7 @@ void PaletteGroup::
 clear_depends() {
   _dependent.clear();
   _dependency_level = 0;
+  _dependency_order = 0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -102,6 +105,59 @@ get_groups() const {
   return _dependent;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PaletteGroup::get_placements
+//       Access: Public
+//  Description: Adds the set of TexturePlacements associated with
+//               this group to the indicated vector.  The vector is
+//               not cleared before this operation; if the user wants
+//               to retrieve the set of placements particular to this
+//               group only, it is the user's responsibility to clear
+//               the vector first.
+////////////////////////////////////////////////////////////////////
+void PaletteGroup::
+get_placements(vector<TexturePlacement *> &placements) const {
+  Placements::iterator pi;
+  for (pi = _placements.begin(); pi != _placements.end(); ++pi) {
+    placements.push_back(*pi);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PaletteGroup::get_complete_placements
+//       Access: Public
+//  Description: Adds the set of TexturePlacements associated with
+//               this group and all dependent groups to the indicated
+//               vector.  See get_placements().
+////////////////////////////////////////////////////////////////////
+void PaletteGroup::
+get_complete_placements(vector<TexturePlacement *> &placements) const {
+  PaletteGroups complete;
+  complete.make_complete(_dependent);
+
+  PaletteGroups::iterator gi;
+  for (gi = complete.begin(); gi != complete.end(); ++gi) {
+    PaletteGroup *group = (*gi);
+    group->get_placements(placements);
+  }
+
+  get_placements(placements);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PaletteGroup::reset_dependency_level
+//       Access: Public
+//  Description: Unconditionally sets the dependency level and order
+//               of this group to zero, in preparation for a later
+//               call to set_dependency_level().  See
+//               set_dependency_level().
+////////////////////////////////////////////////////////////////////
+void PaletteGroup::
+reset_dependency_level() {
+  _dependency_level = 0;
+  _dependency_order = 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PaletteGroup::set_dependency_level
 //       Access: Public
@@ -120,9 +176,42 @@ set_dependency_level(int level) {
     _dependency_level = level;
     PaletteGroups::iterator gi;
     for (gi = _dependent.begin(); gi != _dependent.end(); ++gi) {
-      (*gi)->set_dependency_level(level + 1);
+      PaletteGroup *group = (*gi);
+      group->set_dependency_level(level + 1);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PaletteGroup::set_dependency_order
+//       Access: Public
+//  Description: Updates the dependency order of this group.  This
+//               number is the inverse of the dependency level, and
+//               can be used to rank the groups in order so that all
+//               the groups that a given group depends on will appear
+//               first in the list.  See get_dependency_order().
+//
+//               This function returns true if anything was changed,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool PaletteGroup::
+set_dependency_order() {
+  bool any_changed = false;
+
+  PaletteGroups::iterator gi;
+  for (gi = _dependent.begin(); gi != _dependent.end(); ++gi) {
+    PaletteGroup *group = (*gi);
+    if (group->set_dependency_order()) {
+      any_changed = true;
+    }
+
+    if (_dependency_order <= group->get_dependency_order()) {
+      _dependency_order = group->get_dependency_order() + 1;
+      any_changed = true;
     }
   }
+
+  return any_changed;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -151,6 +240,26 @@ get_dependency_level() const {
   return _dependency_level;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PaletteGroup::get_dependency_order
+//       Access: Public
+//  Description: Returns the dependency order of this group.  This is
+//               similar in principle to the dependency level, but it
+//               represents the inverse concept: if group a depends on
+//               group b, then a->get_dependency_order() >
+//               b->get_dependency_order().
+//
+//               This is not exactly the same thing as n -
+//               get_dependency_level().  In particular, this can be
+//               used to sort the groups into an ordering such that
+//               all the groups that group a depends on appear before
+//               group a in the list.
+////////////////////////////////////////////////////////////////////
+int PaletteGroup::
+get_dependency_order() const {
+  return _dependency_order;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PaletteGroup::increment_egg_count
 //       Access: Public
@@ -392,8 +501,8 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
   datagram.add_string(_dirname);
   _dependent.write_datagram(writer, datagram);
 
-  // We don't write out _dependency_level.  It's best to recompute
-  // that each time.
+  datagram.add_int32(_dependency_level);
+  datagram.add_int32(_dependency_order);
 
   datagram.add_uint32(_placements.size());
   Placements::const_iterator pli;
@@ -504,6 +613,11 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   _dirname = scan.get_string();
   _dependent.fillin(scan, manager);
 
+  if (Palettizer::_read_pi_version >= 3) {
+    _dependency_level = scan.get_int32();
+    _dependency_order = scan.get_int32();
+  }
+
   _num_placements = scan.get_uint32();
   manager->read_pointers(scan, this, _num_placements);
 

+ 8 - 0
pandatool/src/egg-palettize/paletteGroup.h

@@ -15,6 +15,7 @@
 #include <typedWriteable.h>
 
 #include <set>
+#include <vector>
 
 class EggFile;
 class TexturePlacement;
@@ -44,8 +45,14 @@ public:
   void group_with(PaletteGroup *other);
   const PaletteGroups &get_groups() const;
 
+  void get_placements(vector<TexturePlacement *> &placements) const;
+  void get_complete_placements(vector<TexturePlacement *> &placements) const;
+
+  void reset_dependency_level();
   void set_dependency_level(int level);
+  bool set_dependency_order();
   int get_dependency_level() const;
+  int get_dependency_order() const;
 
   void increment_egg_count();
   int get_egg_count() const;
@@ -69,6 +76,7 @@ private:
   int _egg_count;
   PaletteGroups _dependent;
   int _dependency_level;
+  int _dependency_order;
 
   typedef set<TexturePlacement *> Placements;
   Placements _placements;

+ 25 - 0
pandatool/src/egg-palettize/paletteImage.cxx

@@ -207,6 +207,31 @@ is_empty() const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PaletteImage::count_utilization
+//       Access: Public
+//  Description: Returns the fraction of the PaletteImage that is
+//               actually used by any textures.  This is 1.0 if every
+//               pixel in the PaletteImage is used, or 0.0 if none
+//               are.  Normally it will be somewhere in between.
+////////////////////////////////////////////////////////////////////
+double PaletteImage::
+count_utilization() const {
+  int used_pixels = 0;
+
+  Placements::const_iterator pi;
+  for (pi = _placements.begin(); pi != _placements.end(); ++pi) {
+    TexturePlacement *placement = (*pi);
+
+    int texture_pixels = placement->get_x_size() * placement->get_y_size();
+    used_pixels += texture_pixels;
+  }
+
+  int total_pixels = get_x_size() * get_y_size();
+
+  return (double)used_pixels / (double)total_pixels;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PaletteImage::place
 //       Access: Public

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

@@ -34,6 +34,7 @@ public:
   PalettePage *get_page() const;
 
   bool is_empty() const;
+  double count_utilization() const;
 
   bool place(TexturePlacement *placement);
   void unplace(TexturePlacement *placement);

+ 119 - 10
pandatool/src/egg-palettize/palettizer.cxx

@@ -9,6 +9,7 @@
 #include "pal_string_utils.h"
 #include "paletteGroup.h"
 #include "filenameUnifier.h"
+#include "textureMemoryCounter.h"
 
 #include <pnmImage.h>
 #include <pnmFileTypeRegistry.h>
@@ -18,6 +19,7 @@
 #include <datagramIterator.h>
 #include <bamReader.h>
 #include <bamWriter.h>
+#include <indent.h>
 
 Palettizer *pal = (Palettizer *)NULL;
 
@@ -26,9 +28,10 @@ Palettizer *pal = (Palettizer *)NULL;
 // allows us to easily update egg-palettize to write out additional
 // information to its pi file, without having it increment the bam
 // version number for all bam and boo files anywhere in the world.
-int Palettizer::_pi_version = 2;
+int Palettizer::_pi_version = 3;
 // 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.
 
 int Palettizer::_read_pi_version = 0;
 
@@ -52,6 +55,18 @@ ostream &operator << (ostream &out, Palettizer::RemapUV remap) {
   return out << "**invalid**(" << (int)remap << ")";
 }
 
+
+// This STL function object is used in report_statistics(), below.
+class SortGroupsByDependencyOrder {
+public:
+  bool operator ()(PaletteGroup *a, PaletteGroup *b) {
+    if (a->get_dependency_order() != b->get_dependency_order()) {
+      return a->get_dependency_order() < b->get_dependency_order();
+    }
+    return a->get_name() < b->get_name();
+  }
+};
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Palettizer::Constructor
 //       Access: Public
@@ -178,6 +193,63 @@ report_pi() const {
   cout << "\n";
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Palettizer::report_statistics
+//       Access: Public
+//  Description: Output a report of the palettization effectiveness,
+//               texture memory utilization, and so on.
+////////////////////////////////////////////////////////////////////
+void Palettizer::
+report_statistics() const {
+  // Sort the groups into order by dependency order, for the user's
+  // convenience.
+  vector<PaletteGroup *> sorted_groups;
+
+  Groups::const_iterator gi;
+  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
+    sorted_groups.push_back((*gi).second);
+  }
+
+  sort(sorted_groups.begin(), sorted_groups.end(), 
+       SortGroupsByDependencyOrder());
+
+  Placements overall_placements;
+
+  vector<PaletteGroup *>::const_iterator sgi;
+  for (sgi = sorted_groups.begin();
+       sgi != sorted_groups.end();
+       ++sgi) {
+    PaletteGroup *group = (*sgi);
+
+    Placements placements;
+    group->get_placements(placements);
+    if (!placements.empty()) {
+      group->get_placements(overall_placements);
+
+      cout << "\n" << group->get_name() << ", by itself:\n";
+      compute_statistics(cout, 2, placements);
+
+      PaletteGroups complete;
+      complete.make_complete(group->get_groups());
+
+      if (complete.size() > 1) {
+	Placements complete_placements;
+	group->get_complete_placements(complete_placements);
+	if (complete_placements.size() != placements.size()) {
+	  cout << "\n" << group->get_name() 
+	       << ", with dependents (" << complete << "):\n";
+	  compute_statistics(cout, 2, complete_placements);
+	}
+      }
+    }
+  }
+
+  cout << "\nOverall:\n";
+  compute_statistics(cout, 2, overall_placements);
+
+  cout << "\n";
+}
+
 
 ////////////////////////////////////////////////////////////////////
 //     Function: Palettizer::read_txa_file
@@ -209,12 +281,28 @@ read_txa_file(const Filename &txa_filename) {
     exit(1);
   }
 
-  // Compute the correct dependency level for each group.  This will
-  // help us when we assign the textures to their groups.
+  // Compute the correct dependency level and order for each group.
+  // This will help us when we assign the textures to their groups.
+  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
+    PaletteGroup *group = (*gi).second;
+    group->reset_dependency_level();
+  }
+
   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
     PaletteGroup *group = (*gi).second;
     group->set_dependency_level(1);
   }
+
+  bool any_changed;
+  do {
+    any_changed = false;
+    for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
+      PaletteGroup *group = (*gi).second;
+      if (group->set_dependency_order()) {
+	any_changed = true;
+      }
+    }
+  } while (any_changed);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -617,6 +705,17 @@ get_texture(const string &name) {
   return image;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Palettizer::yesno
+//       Access: Private, Static
+//  Description: A silly function to return "yes" or "no" based on a
+//               bool flag for nicely formatted output.
+////////////////////////////////////////////////////////////////////
+const char *Palettizer::
+yesno(bool flag) {
+  return flag ? "yes" : "no";
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Palettizer::string_remap
 //       Access: Public, Static
@@ -641,14 +740,24 @@ string_remap(const string &str) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: Palettizer::yesno
-//       Access: Private, Static
-//  Description: A silly function to return "yes" or "no" based on a
-//               bool flag for nicely formatted output.
+//     Function: Palettizer::compute_statistics
+//       Access: Private
+//  Description: Determines how much memory, etc. is required by the
+//               indicated set of texture placements, and reports this
+//               to the indicated output stream.
 ////////////////////////////////////////////////////////////////////
-const char *Palettizer::
-yesno(bool flag) {
-  return flag ? "yes" : "no";
+void Palettizer::
+compute_statistics(ostream &out, int indent_level,
+		   const Palettizer::Placements &placements) const {
+  TextureMemoryCounter counter;
+
+  Placements::const_iterator pi;
+  for (pi = placements.begin(); pi != placements.end(); ++pi) {
+    TexturePlacement *placement = (*pi);
+    counter.add_placement(placement);
+  }
+
+  counter.report(out, indent_level);
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -20,6 +20,7 @@ class PNMFileType;
 class EggFile;
 class PaletteGroup;
 class TextureImage;
+class TexturePlacement;
 
 ////////////////////////////////////////////////////////////////////
 // 	 Class : Palettizer
@@ -34,6 +35,8 @@ public:
   Palettizer();
 
   void report_pi() const;
+  void report_statistics() const;
+
   void read_txa_file(const Filename &txa_filename);
   void all_params_set();
   void process_command_line_eggs(bool force_texture_read);
@@ -94,6 +97,10 @@ public:
   PNMFileType *_shadow_alpha_type;
 
 private:
+  typedef vector<TexturePlacement *> Placements;
+  void compute_statistics(ostream &out, int indent_level,
+			  const Placements &placements) const;
+
   typedef map<string, EggFile *> EggFiles;
   EggFiles _egg_files;
 

+ 233 - 0
pandatool/src/egg-palettize/textureMemoryCounter.cxx

@@ -0,0 +1,233 @@
+// Filename: textureMemoryCounter.cxx
+// Created by:  drose (19Dec00)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "textureMemoryCounter.h"
+#include "paletteImage.h"
+#include "textureImage.h"
+#include "destTextureImage.h"
+#include "omitReason.h"
+#include "texturePlacement.h"
+
+#include <indent.h>
+#include <math.h>
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureMemoryCounter::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+TextureMemoryCounter::
+TextureMemoryCounter() {
+  reset();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureMemoryCounter::reset
+//       Access: Public
+//  Description: Resets the count to zero.
+////////////////////////////////////////////////////////////////////
+void TextureMemoryCounter::
+reset() {
+  _num_textures = 0;
+  _num_unplaced = 0;
+  _num_placed = 0;
+  _num_palettes = 0;
+
+  _bytes = 0;
+  _unused_bytes = 0;
+  _duplicate_bytes = 0;
+  _textures.clear();
+  _palettes.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureMemoryCounter::add_placement
+//       Access: Public
+//  Description: Adds the indicated TexturePlacement to the counter.
+////////////////////////////////////////////////////////////////////
+void TextureMemoryCounter::
+add_placement(TexturePlacement *placement) {
+  TextureImage *texture = placement->get_texture();
+  nassertv(texture != (TextureImage *)NULL);
+
+  if (placement->get_omit_reason() == OR_none) {
+    PaletteImage *image = placement->get_image();
+    nassertv(image != (PaletteImage *)NULL);
+    add_palette(image);
+
+    int bytes = count_bytes(image, placement->get_placed_x_size(), 
+			    placement->get_placed_y_size());
+    add_texture(texture, bytes);
+    _num_placed++;
+    
+  } else {
+    DestTextureImage *dest = placement->get_dest();
+    nassertv(dest != (DestTextureImage *)NULL);
+
+    int bytes = count_bytes(dest);
+    add_texture(texture, bytes);
+
+    _bytes += bytes;
+    _num_unplaced++;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureMemoryCounter::report
+//       Access: Public
+//  Description: Reports the measured texture memory usage.
+////////////////////////////////////////////////////////////////////
+void TextureMemoryCounter::
+report(ostream &out, int indent_level) {
+  indent(out, indent_level)
+    << _num_placed << " of " << _num_textures << " textures appear on "
+    << _num_palettes << " palette images with " << _num_unplaced
+    << " unplaced.\n";
+
+  indent(out, indent_level)
+    << (_bytes + 512) / 1024 << "k estimated texture memory required.\n";
+
+  if (_bytes != 0) {
+    indent(out, indent_level + 2)
+      << "Of this, "
+      << floor(1000.0 * (double)_unused_bytes / (double)_bytes + 0.5) / 10.0
+      << "% is wasted because of unused palette space.\n";
+    
+    if (_duplicate_bytes != 0) {
+      indent(out, indent_level + 2)
+	<< "And " << 100.0 * (double)_duplicate_bytes / (double)_bytes
+	<< "% is wasted because of a texture appearing in multiple places.\n";
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureMemoryCounter::add_palette
+//       Access: Private
+//  Description: Adds the indicated PaletteImage to the count.  If
+//               this is called twice for a given PaletteImage it does
+//               nothing.
+////////////////////////////////////////////////////////////////////
+void TextureMemoryCounter::
+add_palette(PaletteImage *image) {
+  bool inserted = _palettes.insert(image).second;
+  if (!inserted) {
+    // We've already added this palette image.
+    return;
+  }
+
+  int bytes = count_bytes(image);
+  double wasted = 1.0 - image->count_utilization();
+
+  _bytes += bytes;
+  _unused_bytes += (int)(wasted * bytes);
+  _num_palettes++;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureMemoryCounter::add_texture
+//       Access: Private
+//  Description: Adds the given TextureImage to the counter.  If the
+//               texture image has already been added, this counts the
+//               smaller of the two as duplicate bytes.
+////////////////////////////////////////////////////////////////////
+void TextureMemoryCounter::
+add_texture(TextureImage *texture, int bytes) {
+  pair<Textures::iterator, bool> result;
+  result = _textures.insert(Textures::value_type(texture, bytes));
+  if (result.second) {
+    // If it was inserted, no problem--no duplicates.
+    _num_textures++;
+    return;
+  }
+
+  // If it was not inserted, we have a duplicate.
+  Textures::iterator ti = result.first;
+
+  _duplicate_bytes += min(bytes, (*ti).second);
+  (*ti).second = max(bytes, (*ti).second);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureMemoryCounter::count_bytes
+//       Access: Private
+//  Description: Attempts to estimate the number of bytes the given
+//               image file will use in texture memory.
+////////////////////////////////////////////////////////////////////
+int TextureMemoryCounter::
+count_bytes(ImageFile *image) {
+  return count_bytes(image, image->get_x_size(), image->get_y_size());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureMemoryCounter::count_bytes
+//       Access: Private
+//  Description: Attempts to estimate the number of bytes the given
+//               image file will use in texture memory.
+////////////////////////////////////////////////////////////////////
+int TextureMemoryCounter::
+count_bytes(ImageFile *image, int x_size, int y_size) {
+  int pixels = x_size * y_size;
+
+  // Try to guess the number of bytes per pixel this texture will
+  // consume in texture memory, based on its requested format.  This
+  // is only a loose guess, because this depends of course on the
+  // pecularities of the particular rendering engine.
+  int bpp = 0;
+  switch (image->get_properties()._format) {
+  case EggTexture::F_rgba12:
+    bpp = 6;
+    break;
+    
+  case EggTexture::F_rgba:
+  case EggTexture::F_rgbm:
+  case EggTexture::F_rgba8:
+    bpp = 4;
+    break;
+
+  case EggTexture::F_rgb:
+  case EggTexture::F_rgb12:
+    bpp = 3;
+    break;
+
+  case EggTexture::F_rgba4:
+  case EggTexture::F_rgba5:
+  case EggTexture::F_rgb8:
+  case EggTexture::F_rgb5:
+  case EggTexture::F_luminance_alpha:
+  case EggTexture::F_luminance_alphamask:
+    bpp = 2;
+    break;
+
+  case EggTexture::F_rgb332:
+  case EggTexture::F_red:
+  case EggTexture::F_green:
+  case EggTexture::F_blue:
+  case EggTexture::F_alpha:
+  case EggTexture::F_luminance:
+    bpp = 1;
+    break;
+
+  default:
+    bpp = image->get_num_channels();
+  }
+
+  int bytes = pixels * bpp;
+
+  // If we're mipmapping, it's worth 1/3 more bytes.
+  switch (image->get_properties()._magfilter) {
+  case EggTexture::FT_nearest_mipmap_nearest:
+  case EggTexture::FT_linear_mipmap_nearest:
+  case EggTexture::FT_nearest_mipmap_linear:
+  case EggTexture::FT_linear_mipmap_linear:
+    bytes = (bytes * 4) / 3;
+    break;
+
+  default:
+    break;
+  }
+
+  return bytes;
+}

+ 58 - 0
pandatool/src/egg-palettize/textureMemoryCounter.h

@@ -0,0 +1,58 @@
+// Filename: textureMemoryCounter.h
+// Created by:  drose (19Dec00)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef TEXTUREMEMORYCOUNTER_H
+#define TEXTUREMEMORYCOUNTER_H
+
+#include <pandatoolbase.h>
+
+class ImageFile;
+class PaletteImage;
+class TextureImage;
+class DestTextureImage;
+class TexturePlacement;
+
+#include <map>
+#include <set>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : TextureMemoryCounter
+// Description : This class is used to gather statistics on texture
+//               memory usage, etc.  It adds up the total texture
+//               memory required by a number of image files, and
+//               reports it at the end.
+////////////////////////////////////////////////////////////////////
+class TextureMemoryCounter {
+public:
+  TextureMemoryCounter();
+
+  void reset();
+  void add_placement(TexturePlacement *placement);
+
+  void report(ostream &out, int indent_level);
+
+private:
+  void add_palette(PaletteImage *image);
+  void add_texture(TextureImage *texture, int bytes);
+  int count_bytes(ImageFile *image);
+  int count_bytes(ImageFile *image, int x_size, int y_size);
+
+  int _num_textures;
+  int _num_placed;
+  int _num_unplaced;
+  int _num_palettes;
+
+  int _bytes;
+  int _unused_bytes;
+  int _duplicate_bytes;
+
+  typedef map<TextureImage *, int> Textures;
+  Textures _textures;
+
+  typedef set<PaletteImage *> Palettes;
+  Palettes _palettes;
+};
+
+#endif