Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

pandatool/src/egg-palettize/palettizer.cxx

Go to the documentation of this file.
00001 // Filename: palettizer.cxx
00002 // Created by:  drose (01Dec00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "palettizer.h"
00020 #include "eggFile.h"
00021 #include "textureImage.h"
00022 #include "pal_string_utils.h"
00023 #include "paletteGroup.h"
00024 #include "filenameUnifier.h"
00025 #include "textureMemoryCounter.h"
00026 
00027 #include <pnmImage.h>
00028 #include <pnmFileTypeRegistry.h>
00029 #include <pnmFileType.h>
00030 #include <eggData.h>
00031 #include <datagram.h>
00032 #include <datagramIterator.h>
00033 #include <bamReader.h>
00034 #include <bamWriter.h>
00035 #include <indent.h>
00036 
00037 Palettizer *pal = (Palettizer *)NULL;
00038 
00039 // This number is written out as the first number to the pi file, to
00040 // indicate the version of egg-palettize that wrote it out.  This
00041 // allows us to easily update egg-palettize to write out additional
00042 // information to its pi file, without having it increment the bam
00043 // version number for all bam and boo files anywhere in the world.
00044 int Palettizer::_pi_version = 10;
00045 // Updated to version 8 on 3/20/03 to remove extensions from texture key names.
00046 // Updated to version 9 on 4/13/03 to add a few properties in various places.
00047 // Updated to version 10 on 4/15/03 to add _alpha_file_channel.
00048 
00049 int Palettizer::_min_pi_version = 8;
00050 // Dropped support for versions 7 and below on 7/14/03.
00051 
00052 int Palettizer::_read_pi_version = 0;
00053 
00054 TypeHandle Palettizer::_type_handle;
00055 
00056 ostream &operator << (ostream &out, Palettizer::RemapUV remap) {
00057   switch (remap) {
00058   case Palettizer::RU_never:
00059     return out << "never";
00060 
00061   case Palettizer::RU_group:
00062     return out << "per group";
00063 
00064   case Palettizer::RU_poly:
00065     return out << "per polygon";
00066 
00067   case Palettizer::RU_invalid:
00068     return out << "(invalid)";
00069   }
00070 
00071   return out << "**invalid**(" << (int)remap << ")";
00072 }
00073 
00074 
00075 // This STL function object is used in report_statistics(), below.
00076 class SortGroupsByDependencyOrder {
00077 public:
00078   bool operator ()(PaletteGroup *a, PaletteGroup *b) {
00079     if (a->get_dependency_order() != b->get_dependency_order()) {
00080       return a->get_dependency_order() < b->get_dependency_order();
00081     }
00082     return a->get_name() < b->get_name();
00083   }
00084 };
00085 
00086 // And this one is used in report_pi().
00087 class SortGroupsByPreference {
00088 public:
00089   bool operator ()(PaletteGroup *a, PaletteGroup *b) {
00090     return !a->is_preferred_over(*b);
00091   }
00092 };
00093 
00094 ////////////////////////////////////////////////////////////////////
00095 //     Function: Palettizer::Constructor
00096 //       Access: Public
00097 //  Description:
00098 ////////////////////////////////////////////////////////////////////
00099 Palettizer::
00100 Palettizer() {
00101   _map_dirname = "%g";
00102   _shadow_dirname = "shadow";
00103   _margin = 2;
00104   _omit_solitary = false;
00105   _coverage_threshold = 2.5;
00106   _aggressively_clean_mapdir = true;
00107   _force_power_2 = true;
00108   _color_type = PNMFileTypeRegistry::get_ptr()->get_type_from_extension("rgb");
00109   _alpha_type = (PNMFileType *)NULL;
00110   _shadow_color_type = (PNMFileType *)NULL;
00111   _shadow_alpha_type = (PNMFileType *)NULL;
00112   _pal_x_size = _pal_y_size = 512;
00113 
00114   _round_uvs = true;
00115   _round_unit = 0.1;
00116   _round_fuzz = 0.01;
00117   _remap_uv = RU_poly;
00118   _remap_char_uv = RU_poly;
00119 }
00120 
00121 ////////////////////////////////////////////////////////////////////
00122 //     Function: Palettizer::report_pi
00123 //       Access: Public
00124 //  Description: Output a verbose description of all the palettization
00125 //               information to standard output, for the user's
00126 //               perusal.
00127 ////////////////////////////////////////////////////////////////////
00128 void Palettizer::
00129 report_pi() const {
00130   // Start out with the cross links and back counts; some of these are
00131   // nice to report.
00132   EggFiles::const_iterator efi;
00133   for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
00134     (*efi).second->build_cross_links();
00135   }
00136 
00137   cout
00138     << "\nparams\n"
00139     << "  map directory: " << _map_dirname << "\n"
00140     << "  shadow directory: "
00141     << FilenameUnifier::make_user_filename(_shadow_dirname) << "\n"
00142     << "  egg relative directory: "
00143     << FilenameUnifier::make_user_filename(_rel_dirname) << "\n"
00144     << "  palettize size: " << _pal_x_size << " by " << _pal_y_size << "\n"
00145     << "  margin: " << _margin << "\n"
00146     << "  coverage threshold: " << _coverage_threshold << "\n"
00147     << "  force textures to power of 2: " << yesno(_force_power_2) << "\n"
00148     << "  aggressively clean the map directory: "
00149     << yesno(_aggressively_clean_mapdir) << "\n"
00150     << "  round UV area: " << yesno(_round_uvs) << "\n";
00151   if (_round_uvs) {
00152     cout << "  round UV area to nearest " << _round_unit << " with fuzz "
00153          << _round_fuzz << "\n";
00154   }
00155   cout << "  remap UV's: " << _remap_uv << "\n"
00156        << "  remap UV's for characters: " << _remap_char_uv << "\n";
00157 
00158   if (_color_type != (PNMFileType *)NULL) {
00159     cout << "  generate image files of type: "
00160          << _color_type->get_suggested_extension();
00161     if (_alpha_type != (PNMFileType *)NULL) {
00162       cout << "," << _alpha_type->get_suggested_extension();
00163     }
00164     cout << "\n";
00165   }
00166 
00167   if (_shadow_color_type != (PNMFileType *)NULL) {
00168     cout << "  generate shadow palette files of type: "
00169          << _shadow_color_type->get_suggested_extension();
00170     if (_shadow_alpha_type != (PNMFileType *)NULL) {
00171       cout << "," << _shadow_alpha_type->get_suggested_extension();
00172     }
00173     cout << "\n";
00174   }
00175 
00176   cout << "\ntexture source pathnames and assignments\n";
00177   Textures::const_iterator ti;
00178   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00179     TextureImage *texture = (*ti).second;
00180     if (texture->is_used()) {
00181       cout << "  " << texture->get_name() << ":\n";
00182       texture->write_source_pathnames(cout, 4);
00183     }
00184   }
00185 
00186   cout << "\negg files and textures referenced\n";
00187   EggFiles::const_iterator ei;
00188   for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
00189     EggFile *egg_file = (*ei).second;
00190     egg_file->write_description(cout, 2);
00191     egg_file->write_texture_refs(cout, 4);
00192   }
00193 
00194   // Sort the palette groups into order of preference, so that the
00195   // more specific ones appear at the bottom.
00196   pvector<PaletteGroup *> sorted_groups;
00197   Groups::const_iterator gi;
00198   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00199     sorted_groups.push_back((*gi).second);
00200   }
00201   sort(sorted_groups.begin(), sorted_groups.end(),
00202        SortGroupsByPreference());
00203 
00204   cout << "\npalette groups\n";
00205   pvector<PaletteGroup *>::iterator si;
00206   for (si = sorted_groups.begin(); si != sorted_groups.end(); ++si) {
00207     PaletteGroup *group = (*si);
00208     if (si != sorted_groups.begin()) {
00209       cout << "\n";
00210     }
00211     cout << "  " << group->get_name()
00212       //         << " (" << group->get_dirname_order() << "," << group->get_dependency_order() << ")"
00213          << ": " << group->get_groups() << "\n";
00214     group->write_image_info(cout, 4);
00215   }
00216 
00217   cout << "\ntextures\n";
00218   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00219     TextureImage *texture = (*ti).second;
00220     texture->write_scale_info(cout, 2);
00221   }
00222 
00223   cout << "\nsurprises\n";
00224   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00225     TextureImage *texture = (*ti).second;
00226     if (texture->is_surprise()) {
00227       cout << "  " << texture->get_name() << "\n";
00228     }
00229   }
00230   for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
00231     EggFile *egg_file = (*ei).second;
00232     if (egg_file->is_surprise()) {
00233       cout << "  " << egg_file->get_name() << "\n";
00234     }
00235   }
00236 
00237   cout << "\n";
00238 }
00239 
00240 ////////////////////////////////////////////////////////////////////
00241 //     Function: Palettizer::report_statistics
00242 //       Access: Public
00243 //  Description: Output a report of the palettization effectiveness,
00244 //               texture memory utilization, and so on.
00245 ////////////////////////////////////////////////////////////////////
00246 void Palettizer::
00247 report_statistics() const {
00248   // Sort the groups into order by dependency order, for the user's
00249   // convenience.
00250   pvector<PaletteGroup *> sorted_groups;
00251 
00252   Groups::const_iterator gi;
00253   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00254     sorted_groups.push_back((*gi).second);
00255   }
00256 
00257   sort(sorted_groups.begin(), sorted_groups.end(),
00258        SortGroupsByDependencyOrder());
00259 
00260   Placements overall_placements;
00261 
00262   pvector<PaletteGroup *>::const_iterator si;
00263   for (si = sorted_groups.begin();
00264        si != sorted_groups.end();
00265        ++si) {
00266     PaletteGroup *group = (*si);
00267 
00268     Placements placements;
00269     group->get_placements(placements);
00270     if (!placements.empty()) {
00271       group->get_placements(overall_placements);
00272 
00273       cout << "\n" << group->get_name() << ", by itself:\n";
00274       compute_statistics(cout, 2, placements);
00275 
00276       PaletteGroups complete;
00277       complete.make_complete(group->get_groups());
00278 
00279       if (complete.size() > 1) {
00280         Placements complete_placements;
00281         group->get_complete_placements(complete_placements);
00282         if (complete_placements.size() != placements.size()) {
00283           cout << "\n" << group->get_name()
00284                << ", with dependents (" << complete << "):\n";
00285           compute_statistics(cout, 2, complete_placements);
00286         }
00287       }
00288     }
00289   }
00290 
00291   cout << "\nOverall:\n";
00292   compute_statistics(cout, 2, overall_placements);
00293 
00294   cout << "\n";
00295 }
00296 
00297 
00298 ////////////////////////////////////////////////////////////////////
00299 //     Function: Palettizer::read_txa_file
00300 //       Access: Public
00301 //  Description: Reads in the .txa file and keeps it ready for
00302 //               matching textures and egg files.
00303 ////////////////////////////////////////////////////////////////////
00304 void Palettizer::
00305 read_txa_file(const Filename &txa_filename) {
00306   // Clear out the group dependencies, in preparation for reading them
00307   // again from the .txa file.
00308   Groups::iterator gi;
00309   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00310     PaletteGroup *group = (*gi).second;
00311     group->clear_depends();
00312   }
00313 
00314   // Also reset _shadow_color_type.
00315   _shadow_color_type = (PNMFileType *)NULL;
00316   _shadow_alpha_type = (PNMFileType *)NULL;
00317 
00318   if (!_txa_file.read(txa_filename)) {
00319     exit(1);
00320   }
00321 
00322   if (_color_type == (PNMFileType *)NULL) {
00323     nout << "No valid output image file type available; cannot run.\n"
00324          << "Use :imagetype command in .txa file.\n";
00325     exit(1);
00326   }
00327 
00328   // Compute the correct dependency level and order for each group.
00329   // This will help us when we assign the textures to their groups.
00330   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00331     PaletteGroup *group = (*gi).second;
00332     group->reset_dependency_level();
00333   }
00334 
00335   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00336     PaletteGroup *group = (*gi).second;
00337     group->set_dependency_level(1);
00338   }
00339 
00340   bool any_changed;
00341   do {
00342     any_changed = false;
00343     for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00344       PaletteGroup *group = (*gi).second;
00345       if (group->set_dependency_order()) {
00346         any_changed = true;
00347       }
00348     }
00349   } while (any_changed);
00350 }
00351 
00352 ////////////////////////////////////////////////////////////////////
00353 //     Function: Palettizer::all_params_set
00354 //       Access: Public
00355 //  Description: Called after all command line parameters have been
00356 //               set up, this is a hook to do whatever initialization
00357 //               is necessary.
00358 ////////////////////////////////////////////////////////////////////
00359 void Palettizer::
00360 all_params_set() {
00361   // Make sure the palettes have their shadow images set up properly.
00362   Groups::iterator gi;
00363   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00364     PaletteGroup *group = (*gi).second;
00365     group->setup_shadow_images();
00366   }
00367 }
00368 
00369 ////////////////////////////////////////////////////////////////////
00370 //     Function: Palettizer::process_command_line_eggs
00371 //       Access: Public
00372 //  Description: Processes all the textures named in the
00373 //               _command_line_eggs, placing them on the appropriate
00374 //               palettes or whatever needs to be done with them.
00375 //
00376 //               If force_texture_read is true, it forces each texture
00377 //               image file to be read (and thus legitimately checked
00378 //               for grayscaleness etc.) before placing.
00379 ////////////////////////////////////////////////////////////////////
00380 void Palettizer::
00381 process_command_line_eggs(bool force_texture_read, const Filename &state_filename) {
00382   _command_line_textures.clear();
00383 
00384   // Start by scanning all the egg files we read up on the command
00385   // line.
00386   CommandLineEggs::const_iterator ei;
00387   for (ei = _command_line_eggs.begin();
00388        ei != _command_line_eggs.end();
00389        ++ei) {
00390     EggFile *egg_file = (*ei);
00391 
00392     egg_file->scan_textures();
00393     egg_file->get_textures(_command_line_textures);
00394 
00395     egg_file->pre_txa_file();
00396     _txa_file.match_egg(egg_file);
00397     egg_file->post_txa_file();
00398   }
00399 
00400   // Now that all of our egg files are read in, build in all the cross
00401   // links and back pointers and stuff.
00402   EggFiles::const_iterator efi;
00403   for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
00404     (*efi).second->build_cross_links();
00405   }
00406 
00407   // Now match each of the textures mentioned in those egg files
00408   // against a line in the .txa file.
00409   CommandLineTextures::iterator ti;
00410   for (ti = _command_line_textures.begin();
00411        ti != _command_line_textures.end();
00412        ++ti) {
00413     TextureImage *texture = *ti;
00414 
00415     if (force_texture_read || texture->is_newer_than(state_filename)) {
00416       // If we're forcing a redo, or the texture image has changed,
00417       // re-read the complete image.
00418       texture->read_source_image();
00419     } else {
00420       // Otherwise, just the header is sufficient.
00421       texture->read_header();
00422     }
00423 
00424     texture->pre_txa_file();
00425     _txa_file.match_texture(texture);
00426     texture->post_txa_file();
00427   }
00428 
00429   // And now, assign each of the current set of textures to an
00430   // appropriate group or groups.
00431   for (ti = _command_line_textures.begin();
00432        ti != _command_line_textures.end();
00433        ++ti) {
00434     TextureImage *texture = *ti;
00435     texture->assign_groups();
00436   }
00437 
00438   // And then the egg files need to sign up for a particular
00439   // TexturePlacement, so we can determine some more properties about
00440   // how the textures are placed (for instance, how big the UV range
00441   // is for a particular TexturePlacement).
00442   for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
00443     (*efi).second->choose_placements();
00444   }
00445 
00446   // Now that *that's* done, we need to make sure the various
00447   // TexturePlacements require the right size for their textures.
00448   for (ti = _command_line_textures.begin();
00449        ti != _command_line_textures.end();
00450        ++ti) {
00451     TextureImage *texture = *ti;
00452     texture->determine_placement_size();
00453   }
00454 
00455   // Now that each texture has been assigned to a suitable group,
00456   // make sure the textures are placed on specific PaletteImages.
00457   Groups::iterator gi;
00458   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00459     PaletteGroup *group = (*gi).second;
00460     group->update_unknown_textures(_txa_file);
00461     group->place_all();
00462   }
00463 }
00464 
00465 ////////////////////////////////////////////////////////////////////
00466 //     Function: Palettizer::process_all
00467 //       Access: Public
00468 //  Description: Reprocesses all textures known.
00469 //
00470 //               If force_texture_read is true, it forces each texture
00471 //               image file to be read (and thus legitimately checked
00472 //               for grayscaleness etc.) before placing.
00473 ////////////////////////////////////////////////////////////////////
00474 void Palettizer::
00475 process_all(bool force_texture_read, const Filename &state_filename) {
00476   // First, clear all the basic properties on the source texture
00477   // images, so we can reapply them from the complete set of egg files
00478   // and thereby ensure they are up-to-date.
00479   Textures::iterator ti;
00480   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00481     TextureImage *texture = (*ti).second;
00482     texture->clear_source_basic_properties();
00483   }
00484 
00485   // If there *were* any egg files on the command line, deal with
00486   // them.
00487   CommandLineEggs::const_iterator ei;
00488   for (ei = _command_line_eggs.begin();
00489        ei != _command_line_eggs.end();
00490        ++ei) {
00491     EggFile *egg_file = (*ei);
00492 
00493     egg_file->scan_textures();
00494     egg_file->get_textures(_command_line_textures);
00495   }
00496 
00497   // Then match up all the egg files we know about with the .txa file.
00498   EggFiles::const_iterator efi;
00499   for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
00500     EggFile *egg_file = (*efi).second;
00501 
00502     egg_file->pre_txa_file();
00503     _txa_file.match_egg(egg_file);
00504     egg_file->post_txa_file();
00505   }
00506 
00507   // Now that all of our egg files are read in, build in all the cross
00508   // links and back pointers and stuff.
00509   for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
00510     (*efi).second->build_cross_links();
00511 
00512     // Also make sure each egg file's properties are applied to the
00513     // source image (since we reset all the source image properties,
00514     // above).
00515     (*efi).second->apply_properties_to_source();
00516   }
00517 
00518   // Now match each of the textures in the world against a line in the
00519   // .txa file.
00520   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00521     TextureImage *texture = (*ti).second;
00522 
00523     if (force_texture_read || texture->is_newer_than(state_filename)) {
00524       texture->read_source_image();
00525     }
00526 
00527     texture->pre_txa_file();
00528     _txa_file.match_texture(texture);
00529     texture->post_txa_file();
00530   }
00531 
00532   // And now, assign each texture to an appropriate group or groups.
00533   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00534     TextureImage *texture = (*ti).second;
00535     texture->assign_groups();
00536   }
00537 
00538   // And then the egg files need to sign up for a particular
00539   // TexturePlacement, so we can determine some more properties about
00540   // how the textures are placed (for instance, how big the UV range
00541   // is for a particular TexturePlacement).
00542   for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
00543     (*efi).second->choose_placements();
00544   }
00545 
00546   // Now that *that's* done, we need to make sure the various
00547   // TexturePlacements require the right size for their textures.
00548   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00549     TextureImage *texture = (*ti).second;
00550     texture->determine_placement_size();
00551   }
00552 
00553   // Now that each texture has been assigned to a suitable group,
00554   // make sure the textures are placed on specific PaletteImages.
00555   Groups::iterator gi;
00556   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00557     PaletteGroup *group = (*gi).second;
00558     group->update_unknown_textures(_txa_file);
00559     group->place_all();
00560   }
00561 }
00562 
00563 ////////////////////////////////////////////////////////////////////
00564 //     Function: Palettizer::optimal_resize
00565 //       Access: Public
00566 //  Description: Attempts to resize each PalettteImage down to its
00567 //               smallest possible size.
00568 ////////////////////////////////////////////////////////////////////
00569 void Palettizer::
00570 optimal_resize() {
00571   Groups::iterator gi;
00572   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00573     PaletteGroup *group = (*gi).second;
00574     group->optimal_resize();
00575   }
00576 }
00577 
00578 ////////////////////////////////////////////////////////////////////
00579 //     Function: Palettizer::reset_images
00580 //       Access: Public
00581 //  Description: Throws away all of the current PaletteImages, so that
00582 //               new ones may be created (and the packing made more
00583 //               optimal).
00584 ////////////////////////////////////////////////////////////////////
00585 void Palettizer::
00586 reset_images() {
00587   Groups::iterator gi;
00588   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00589     PaletteGroup *group = (*gi).second;
00590     group->reset_images();
00591   }
00592 }
00593 
00594 ////////////////////////////////////////////////////////////////////
00595 //     Function: Palettizer::generate_images
00596 //       Access: Public
00597 //  Description: Actually generates the appropriate palette and
00598 //               unplaced texture images into the map directories.  If
00599 //               redo_all is true, this forces a regeneration of each
00600 //               image file.
00601 ////////////////////////////////////////////////////////////////////
00602 void Palettizer::
00603 generate_images(bool redo_all) {
00604   Groups::iterator gi;
00605   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00606     PaletteGroup *group = (*gi).second;
00607     group->update_images(redo_all);
00608   }
00609 
00610   Textures::iterator ti;
00611   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00612     TextureImage *texture = (*ti).second;
00613     texture->copy_unplaced(redo_all);
00614   }
00615 }
00616 
00617 ////////////////////////////////////////////////////////////////////
00618 //     Function: Palettizer::read_stale_eggs
00619 //       Access: Public
00620 //  Description: Reads in any egg file that is known to be stale, even
00621 //               if it was not listed on the command line, so that it
00622 //               may be updated and written out when write_eggs() is
00623 //               called.  If redo_all is true, this even reads egg
00624 //               files that were not flagged as stale.
00625 //
00626 //               Returns true if successful, or false if there was
00627 //               some error.
00628 ////////////////////////////////////////////////////////////////////
00629 bool Palettizer::
00630 read_stale_eggs(bool redo_all) {
00631   bool okflag = true;
00632   
00633   pvector<EggFiles::iterator> invalid_eggs;
00634 
00635   EggFiles::iterator ei;
00636   for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
00637     EggFile *egg_file = (*ei).second;
00638     if (!egg_file->has_data() &&
00639         (egg_file->is_stale() || redo_all)) {
00640       if (!egg_file->read_egg()) {
00641         invalid_eggs.push_back(ei);
00642 
00643       } else {
00644         egg_file->scan_textures();
00645         egg_file->choose_placements();
00646       }
00647     }
00648   }
00649 
00650   // Now eliminate all the invalid egg files.
00651   pvector<EggFiles::iterator>::iterator ii;
00652   for (ii = invalid_eggs.begin(); ii != invalid_eggs.end(); ++ii) {
00653     EggFiles::iterator ei = (*ii);
00654     EggFile *egg_file = (*ei).second;
00655     nout << "Removing " << (*ei).first << "\n";
00656     egg_file->remove_egg();
00657     _egg_files.erase(ei);
00658   }
00659 
00660   return okflag;
00661 }
00662 
00663 ////////////////////////////////////////////////////////////////////
00664 //     Function: Palettizer::write_eggs
00665 //       Access: Public
00666 //  Description: Adjusts the egg files to reference the newly
00667 //               generated textures, and writes them out.  Returns
00668 //               true if successful, or false if there was some error.
00669 ////////////////////////////////////////////////////////////////////
00670 bool Palettizer::
00671 write_eggs() {
00672   bool okflag = true;
00673 
00674   EggFiles::iterator ei;
00675   for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
00676     EggFile *egg_file = (*ei).second;
00677     if (egg_file->has_data()) {
00678       egg_file->update_egg();
00679       if (!egg_file->write_egg()) {
00680         okflag = false;
00681       }
00682     }
00683   }
00684 
00685   return okflag;
00686 }
00687 
00688 ////////////////////////////////////////////////////////////////////
00689 //     Function: Palettizer::get_egg_file
00690 //       Access: Public
00691 //  Description: Returns the EggFile with the given name.  If there is
00692 //               no EggFile with the indicated name, creates one.
00693 //               This is the key name used to sort the egg files,
00694 //               which is typically the basename of the filename.
00695 ////////////////////////////////////////////////////////////////////
00696 EggFile *Palettizer::
00697 get_egg_file(const string &name) {
00698   EggFiles::iterator ei = _egg_files.find(name);
00699   if (ei != _egg_files.end()) {
00700     return (*ei).second;
00701   }
00702 
00703   EggFile *file = new EggFile;
00704   file->set_name(name);
00705   _egg_files.insert(EggFiles::value_type(name, file));
00706   return file;
00707 }
00708 
00709 ////////////////////////////////////////////////////////////////////
00710 //     Function: Palettizer::remove_egg_file
00711 //       Access: Public
00712 //  Description: Removes the named egg file from the database, if it
00713 //               exists.  Returns true if the egg file was found,
00714 //               false if it was not.
00715 ////////////////////////////////////////////////////////////////////
00716 bool Palettizer::
00717 remove_egg_file(const string &name) {
00718   EggFiles::iterator ei = _egg_files.find(name);
00719   if (ei != _egg_files.end()) {
00720     EggFile *file = (*ei).second;
00721     file->remove_egg();
00722     _egg_files.erase(ei);
00723     return true;
00724   }
00725 
00726   return false;
00727 }
00728 
00729 ////////////////////////////////////////////////////////////////////
00730 //     Function: Palettizer::get_palette_group
00731 //       Access: Public
00732 //  Description: Returns the PaletteGroup with the given name.  If
00733 //               there is no PaletteGroup with the indicated name,
00734 //               creates one.
00735 ////////////////////////////////////////////////////////////////////
00736 PaletteGroup *Palettizer::
00737 get_palette_group(const string &name) {
00738   Groups::iterator gi = _groups.find(name);
00739   if (gi != _groups.end()) {
00740     return (*gi).second;
00741   }
00742 
00743   PaletteGroup *group = new PaletteGroup;
00744   group->set_name(name);
00745   _groups.insert(Groups::value_type(name, group));
00746   return group;
00747 }
00748 
00749 ////////////////////////////////////////////////////////////////////
00750 //     Function: Palettizer::test_palette_group
00751 //       Access: Public
00752 //  Description: Returns the PaletteGroup with the given name.  If
00753 //               there is no PaletteGroup with the indicated name,
00754 //               returns NULL.
00755 ////////////////////////////////////////////////////////////////////
00756 PaletteGroup *Palettizer::
00757 test_palette_group(const string &name) const {
00758   Groups::const_iterator gi = _groups.find(name);
00759   if (gi != _groups.end()) {
00760     return (*gi).second;
00761   }
00762 
00763   return (PaletteGroup *)NULL;
00764 }
00765 
00766 ////////////////////////////////////////////////////////////////////
00767 //     Function: Palettizer::get_default_group
00768 //       Access: Public
00769 //  Description: Returns the default group to which an egg file should
00770 //               be assigned if it is not mentioned in the .txa file.
00771 ////////////////////////////////////////////////////////////////////
00772 PaletteGroup *Palettizer::
00773 get_default_group() {
00774   PaletteGroup *default_group = get_palette_group(_default_groupname);
00775   if (!_default_groupdir.empty() && !default_group->has_dirname()) {
00776     default_group->set_dirname(_default_groupdir);
00777   }
00778   return default_group;
00779 }
00780 
00781 ////////////////////////////////////////////////////////////////////
00782 //     Function: Palettizer::get_texture
00783 //       Access: Public
00784 //  Description: Returns the TextureImage with the given name.  If
00785 //               there is no TextureImage with the indicated name,
00786 //               creates one.  This is the key name used to sort the
00787 //               textures, which is typically the basename of the
00788 //               primary filename.
00789 ////////////////////////////////////////////////////////////////////
00790 TextureImage *Palettizer::
00791 get_texture(const string &name) {
00792   Textures::iterator ti = _textures.find(name);
00793   if (ti != _textures.end()) {
00794     return (*ti).second;
00795   }
00796 
00797   TextureImage *image = new TextureImage;
00798   image->set_name(name);
00799   //  image->set_filename(name);
00800   _textures.insert(Textures::value_type(name, image));
00801   return image;
00802 }
00803 
00804 ////////////////////////////////////////////////////////////////////
00805 //     Function: Palettizer::yesno
00806 //       Access: Private, Static
00807 //  Description: A silly function to return "yes" or "no" based on a
00808 //               bool flag for nicely formatted output.
00809 ////////////////////////////////////////////////////////////////////
00810 const char *Palettizer::
00811 yesno(bool flag) {
00812   return flag ? "yes" : "no";
00813 }
00814 
00815 ////////////////////////////////////////////////////////////////////
00816 //     Function: Palettizer::string_remap
00817 //       Access: Public, Static
00818 //  Description: Returns the RemapUV code corresponding to the
00819 //               indicated string, or RU_invalid if the string is
00820 //               invalid.
00821 ////////////////////////////////////////////////////////////////////
00822 Palettizer::RemapUV Palettizer::
00823 string_remap(const string &str) {
00824   if (str == "never") {
00825     return RU_never;
00826 
00827   } else if (str == "group") {
00828     return RU_group;
00829 
00830   } else if (str == "poly") {
00831     return RU_poly;
00832 
00833   } else {
00834     return RU_invalid;
00835   }
00836 }
00837 
00838 ////////////////////////////////////////////////////////////////////
00839 //     Function: Palettizer::compute_statistics
00840 //       Access: Private
00841 //  Description: Determines how much memory, etc. is required by the
00842 //               indicated set of texture placements, and reports this
00843 //               to the indicated output stream.
00844 ////////////////////////////////////////////////////////////////////
00845 void Palettizer::
00846 compute_statistics(ostream &out, int indent_level,
00847                    const Palettizer::Placements &placements) const {
00848   TextureMemoryCounter counter;
00849 
00850   Placements::const_iterator pi;
00851   for (pi = placements.begin(); pi != placements.end(); ++pi) {
00852     TexturePlacement *placement = (*pi);
00853     counter.add_placement(placement);
00854   }
00855 
00856   counter.report(out, indent_level);
00857 }
00858 
00859 ////////////////////////////////////////////////////////////////////
00860 //     Function: Palettizer::register_with_read_factory
00861 //       Access: Public, Static
00862 //  Description: Registers the current object as something that can be
00863 //               read from a Bam file.
00864 ////////////////////////////////////////////////////////////////////
00865 void Palettizer::
00866 register_with_read_factory() {
00867   BamReader::get_factory()->
00868     register_factory(get_class_type(), make_Palettizer);
00869 }
00870 
00871 ////////////////////////////////////////////////////////////////////
00872 //     Function: Palettizer::write_datagram
00873 //       Access: Public, Virtual
00874 //  Description: Fills the indicated datagram up with a binary
00875 //               representation of the current object, in preparation
00876 //               for writing to a Bam file.
00877 ////////////////////////////////////////////////////////////////////
00878 void Palettizer::
00879 write_datagram(BamWriter *writer, Datagram &datagram) {
00880   TypedWritable::write_datagram(writer, datagram);
00881 
00882   datagram.add_int32(_pi_version);
00883   datagram.add_string(_map_dirname);
00884   datagram.add_string(FilenameUnifier::make_bam_filename(_shadow_dirname));
00885   datagram.add_string(FilenameUnifier::make_bam_filename(_rel_dirname));
00886   datagram.add_int32(_pal_x_size);
00887   datagram.add_int32(_pal_y_size);
00888   datagram.add_int32(_margin);
00889   datagram.add_bool(_omit_solitary);
00890   datagram.add_float64(_coverage_threshold);
00891   datagram.add_bool(_force_power_2);
00892   datagram.add_bool(_aggressively_clean_mapdir);
00893   datagram.add_bool(_round_uvs);
00894   datagram.add_float64(_round_unit);
00895   datagram.add_float64(_round_fuzz);
00896   datagram.add_int32((int)_remap_uv);
00897   datagram.add_int32((int)_remap_char_uv);
00898 
00899   writer->write_pointer(datagram, _color_type);
00900   writer->write_pointer(datagram, _alpha_type);
00901   writer->write_pointer(datagram, _shadow_color_type);
00902   writer->write_pointer(datagram, _shadow_alpha_type);
00903 
00904   datagram.add_int32(_egg_files.size());
00905   EggFiles::const_iterator ei;
00906   for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
00907     writer->write_pointer(datagram, (*ei).second);
00908   }
00909 
00910   // We don't write _command_line_eggs; that's specific to each
00911   // session.
00912 
00913   datagram.add_int32(_groups.size());
00914   Groups::const_iterator gi;
00915   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00916     writer->write_pointer(datagram, (*gi).second);
00917   }
00918 
00919   datagram.add_int32(_textures.size());
00920   Textures::const_iterator ti;
00921   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00922     writer->write_pointer(datagram, (*ti).second);
00923   }
00924 }
00925 
00926 ////////////////////////////////////////////////////////////////////
00927 //     Function: Palettizer::complete_pointers
00928 //       Access: Public, Virtual
00929 //  Description: Called after the object is otherwise completely read
00930 //               from a Bam file, this function's job is to store the
00931 //               pointers that were retrieved from the Bam file for
00932 //               each pointer object written.  The return value is the
00933 //               number of pointers processed from the list.
00934 ////////////////////////////////////////////////////////////////////
00935 int Palettizer::
00936 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00937   int index = TypedWritable::complete_pointers(p_list, manager);
00938 
00939   if (p_list[index] != (TypedWritable *)NULL) {
00940     DCAST_INTO_R(_color_type, p_list[index], index);
00941   }
00942   index++;
00943 
00944   if (p_list[index] != (TypedWritable *)NULL) {
00945     DCAST_INTO_R(_alpha_type, p_list[index], index);
00946   }
00947   index++;
00948 
00949   if (p_list[index] != (TypedWritable *)NULL) {
00950     DCAST_INTO_R(_shadow_color_type, p_list[index], index);
00951   }
00952   index++;
00953 
00954   if (p_list[index] != (TypedWritable *)NULL) {
00955     DCAST_INTO_R(_shadow_alpha_type, p_list[index], index);
00956   }
00957   index++;
00958 
00959   int i;
00960   for (i = 0; i < _num_egg_files; i++) {
00961     EggFile *egg_file;
00962     DCAST_INTO_R(egg_file, p_list[index], index);
00963     _egg_files.insert(EggFiles::value_type(egg_file->get_name(), egg_file));
00964     index++;
00965   }
00966 
00967   for (i = 0; i < _num_groups; i++) {
00968     PaletteGroup *group;
00969     DCAST_INTO_R(group, p_list[index], index);
00970     _groups.insert(Groups::value_type(group->get_name(), group));
00971     index++;
00972   }
00973 
00974   for (i = 0; i < _num_textures; i++) {
00975     TextureImage *texture;
00976     DCAST_INTO_R(texture, p_list[index], index);
00977 
00978     _textures.insert(Textures::value_type(texture->get_name(), texture));
00979     index++;
00980   }
00981 
00982   return index;
00983 }
00984 
00985 ////////////////////////////////////////////////////////////////////
00986 //     Function: Palettizer::make_Palettizer
00987 //       Access: Protected
00988 //  Description: This method is called by the BamReader when an object
00989 //               of this type is encountered in a Bam file; it should
00990 //               allocate and return a new object with all the data
00991 //               read.
00992 ////////////////////////////////////////////////////////////////////
00993 TypedWritable* Palettizer::
00994 make_Palettizer(const FactoryParams &params) {
00995   Palettizer *me = new Palettizer;
00996   DatagramIterator scan;
00997   BamReader *manager;
00998 
00999   parse_params(params, scan, manager);
01000   me->fillin(scan, manager);
01001   return me;
01002 }
01003 
01004 ////////////////////////////////////////////////////////////////////
01005 //     Function: Palettizer::fillin
01006 //       Access: Protected
01007 //  Description: Reads the binary data from the given datagram
01008 //               iterator, which was written by a previous call to
01009 //               write_datagram().
01010 ////////////////////////////////////////////////////////////////////
01011 void Palettizer::
01012 fillin(DatagramIterator &scan, BamReader *manager) {
01013   TypedWritable::fillin(scan, manager);
01014 
01015   _read_pi_version = scan.get_int32();
01016   _map_dirname = scan.get_string();
01017   _shadow_dirname = FilenameUnifier::get_bam_filename(scan.get_string());
01018   _rel_dirname = FilenameUnifier::get_bam_filename(scan.get_string());
01019   FilenameUnifier::set_rel_dirname(_rel_dirname);
01020   _pal_x_size = scan.get_int32();
01021   _pal_y_size = scan.get_int32();
01022   _margin = scan.get_int32();
01023   _omit_solitary = scan.get_bool();
01024   _coverage_threshold = scan.get_float64();
01025   _force_power_2 = scan.get_bool();
01026   _aggressively_clean_mapdir = scan.get_bool();
01027   _round_uvs = scan.get_bool();
01028   _round_unit = scan.get_float64();
01029   _round_fuzz = scan.get_float64();
01030   _remap_uv = (RemapUV)scan.get_int32();
01031   _remap_char_uv = (RemapUV)scan.get_int32();
01032 
01033   manager->read_pointer(scan);  // _color_type
01034   manager->read_pointer(scan);  // _alpha_type
01035   manager->read_pointer(scan);  // _shadow_color_type
01036   manager->read_pointer(scan);  // _shadow_alpha_type
01037 
01038   _num_egg_files = scan.get_int32();
01039   manager->read_pointers(scan, _num_egg_files);
01040 
01041   _num_groups = scan.get_int32();
01042   manager->read_pointers(scan, _num_groups);
01043 
01044   _num_textures = scan.get_int32();
01045   manager->read_pointers(scan, _num_textures);
01046 }
01047 

Generated on Fri May 2 03:18:05 2003 for Panda-Tool by doxygen1.3