diff --git a/pandatool/src/egg-palettize/Sources.pp b/pandatool/src/egg-palettize/Sources.pp index 6dc0f8b25f..26960315aa 100644 --- a/pandatool/src/egg-palettize/Sources.pp +++ b/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 \ diff --git a/pandatool/src/egg-palettize/eggPalettize.cxx b/pandatool/src/egg-palettize/eggPalettize.cxx index 3c4f472c83..8746334cf2 100644 --- a/pandatool/src/egg-palettize/eggPalettize.cxx +++ b/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); diff --git a/pandatool/src/egg-palettize/eggPalettize.h b/pandatool/src/egg-palettize/eggPalettize.h index 308197003d..74cb608ec8 100644 --- a/pandatool/src/egg-palettize/eggPalettize.h +++ b/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; diff --git a/pandatool/src/egg-palettize/paletteGroup.cxx b/pandatool/src/egg-palettize/paletteGroup.cxx index b602e1f299..e9c5d1af3c 100644 --- a/pandatool/src/egg-palettize/paletteGroup.cxx +++ b/pandatool/src/egg-palettize/paletteGroup.cxx @@ -7,6 +7,7 @@ #include "palettePage.h" #include "texturePlacement.h" #include "textureImage.h" +#include "palettizer.h" #include #include @@ -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 &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 &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,11 +176,44 @@ 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; +} + //////////////////////////////////////////////////////////////////// // Function: PaletteGroup::get_dependency_level // Access: Public @@ -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); diff --git a/pandatool/src/egg-palettize/paletteGroup.h b/pandatool/src/egg-palettize/paletteGroup.h index 2392256904..ccf4c99f6e 100644 --- a/pandatool/src/egg-palettize/paletteGroup.h +++ b/pandatool/src/egg-palettize/paletteGroup.h @@ -15,6 +15,7 @@ #include #include +#include class EggFile; class TexturePlacement; @@ -44,8 +45,14 @@ public: void group_with(PaletteGroup *other); const PaletteGroups &get_groups() const; + void get_placements(vector &placements) const; + void get_complete_placements(vector &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 Placements; Placements _placements; diff --git a/pandatool/src/egg-palettize/paletteImage.cxx b/pandatool/src/egg-palettize/paletteImage.cxx index 786057195f..e79c5833d1 100644 --- a/pandatool/src/egg-palettize/paletteImage.cxx +++ b/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 diff --git a/pandatool/src/egg-palettize/paletteImage.h b/pandatool/src/egg-palettize/paletteImage.h index 1d320b452a..23640c0c79 100644 --- a/pandatool/src/egg-palettize/paletteImage.h +++ b/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); diff --git a/pandatool/src/egg-palettize/palettizer.cxx b/pandatool/src/egg-palettize/palettizer.cxx index 3724689784..cc731ea093 100644 --- a/pandatool/src/egg-palettize/palettizer.cxx +++ b/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 #include @@ -18,6 +19,7 @@ #include #include #include +#include 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 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::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); } //////////////////////////////////////////////////////////////////// diff --git a/pandatool/src/egg-palettize/palettizer.h b/pandatool/src/egg-palettize/palettizer.h index 4ba4242ac5..005aa6ee77 100644 --- a/pandatool/src/egg-palettize/palettizer.h +++ b/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 Placements; + void compute_statistics(ostream &out, int indent_level, + const Placements &placements) const; + typedef map EggFiles; EggFiles _egg_files; diff --git a/pandatool/src/egg-palettize/textureMemoryCounter.cxx b/pandatool/src/egg-palettize/textureMemoryCounter.cxx new file mode 100644 index 0000000000..7383d5e3d8 --- /dev/null +++ b/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 +#include + +//////////////////////////////////////////////////////////////////// +// 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 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; +} diff --git a/pandatool/src/egg-palettize/textureMemoryCounter.h b/pandatool/src/egg-palettize/textureMemoryCounter.h new file mode 100644 index 0000000000..9ce15a3f46 --- /dev/null +++ b/pandatool/src/egg-palettize/textureMemoryCounter.h @@ -0,0 +1,58 @@ +// Filename: textureMemoryCounter.h +// Created by: drose (19Dec00) +// +//////////////////////////////////////////////////////////////////// + +#ifndef TEXTUREMEMORYCOUNTER_H +#define TEXTUREMEMORYCOUNTER_H + +#include + +class ImageFile; +class PaletteImage; +class TextureImage; +class DestTextureImage; +class TexturePlacement; + +#include +#include + +//////////////////////////////////////////////////////////////////// +// 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 Textures; + Textures _textures; + + typedef set Palettes; + Palettes _palettes; +}; + +#endif