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

panda/src/egg/eggTextureCollection.cxx

Go to the documentation of this file.
00001 // Filename: eggTextureCollection.cxx
00002 // Created by:  drose (15Feb00)
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 "eggTextureCollection.h"
00020 #include "eggGroupNode.h"
00021 #include "eggPrimitive.h"
00022 #include "eggTexture.h"
00023 
00024 #include <nameUniquifier.h>
00025 
00026 #include <algorithm>
00027 
00028 ////////////////////////////////////////////////////////////////////
00029 //     Function: EggTextureCollection::Constructor
00030 //       Access: Public
00031 //  Description:
00032 ////////////////////////////////////////////////////////////////////
00033 EggTextureCollection::
00034 EggTextureCollection() {
00035 }
00036 
00037 ////////////////////////////////////////////////////////////////////
00038 //     Function: EggTextureCollection::Copy Constructor
00039 //       Access: Public
00040 //  Description:
00041 ////////////////////////////////////////////////////////////////////
00042 EggTextureCollection::
00043 EggTextureCollection(const EggTextureCollection &copy) :
00044   _textures(copy._textures),
00045   _ordered_textures(copy._ordered_textures)
00046 {
00047 }
00048 
00049 ////////////////////////////////////////////////////////////////////
00050 //     Function: EggTextureCollection::Copy Assignment Operator
00051 //       Access: Public
00052 //  Description:
00053 ////////////////////////////////////////////////////////////////////
00054 EggTextureCollection &EggTextureCollection::
00055 operator = (const EggTextureCollection &copy) {
00056   _textures = copy._textures;
00057   _ordered_textures = copy._ordered_textures;
00058   return *this;
00059 }
00060 
00061 ////////////////////////////////////////////////////////////////////
00062 //     Function: EggTextureCollection::Destructor
00063 //       Access: Public
00064 //  Description:
00065 ////////////////////////////////////////////////////////////////////
00066 EggTextureCollection::
00067 ~EggTextureCollection() {
00068 }
00069 
00070 ////////////////////////////////////////////////////////////////////
00071 //     Function: EggTextureCollection::clear
00072 //       Access: Public
00073 //  Description: Removes all textures from the collection.
00074 ////////////////////////////////////////////////////////////////////
00075 void EggTextureCollection::
00076 clear() {
00077   _textures.clear();
00078   _ordered_textures.clear();
00079 }
00080 
00081 ////////////////////////////////////////////////////////////////////
00082 //     Function: EggTextureCollection::extract_textures
00083 //       Access: Public
00084 //  Description: Walks the egg hierarchy beginning at the indicated
00085 //               node, and removes any EggTextures encountered in the
00086 //               hierarchy, adding them to the collection.  Returns
00087 //               the number of EggTextures encountered.
00088 ////////////////////////////////////////////////////////////////////
00089 int EggTextureCollection::
00090 extract_textures(EggGroupNode *node) {
00091   // Since this traversal is destructive, we'll handle it within the
00092   // EggGroupNode code.
00093   return node->find_textures(this);
00094 }
00095 
00096 ////////////////////////////////////////////////////////////////////
00097 //     Function: EggTextureCollection::insert_textures
00098 //       Access: Public
00099 //  Description: Adds a series of EggTexture nodes to the beginning of
00100 //               the indicated node to reflect each of the textures in
00101 //               the collection.  Returns an iterator representing the
00102 //               first position after the newly inserted textures.
00103 ////////////////////////////////////////////////////////////////////
00104 EggGroupNode::iterator EggTextureCollection::
00105 insert_textures(EggGroupNode *node) {
00106   return insert_textures(node, node->begin());
00107 }
00108 
00109 ////////////////////////////////////////////////////////////////////
00110 //     Function: EggTextureCollection::insert_textures
00111 //       Access: Public
00112 //  Description: Adds a series of EggTexture nodes to the beginning of
00113 //               the indicated node to reflect each of the textures in
00114 //               the collection.  Returns an iterator representing the
00115 //               first position after the newly inserted textures.
00116 ////////////////////////////////////////////////////////////////////
00117 EggGroupNode::iterator EggTextureCollection::
00118 insert_textures(EggGroupNode *node, EggGroupNode::iterator position) {
00119   OrderedTextures::iterator oti;
00120   for (oti = _ordered_textures.begin();
00121        oti != _ordered_textures.end();
00122        ++oti) {
00123     EggTexture *texture = (*oti);
00124     position = node->insert(position, texture);
00125   }
00126 
00127   return position;
00128 }
00129 
00130 ////////////////////////////////////////////////////////////////////
00131 //     Function: EggTextureCollection::find_used_textures
00132 //       Access: Public
00133 //  Description: Walks the egg hierarchy beginning at the indicated
00134 //               node, looking for textures that are referenced by
00135 //               primitives but are not already members of the
00136 //               collection, adding them to the collection.
00137 //
00138 //               If this is called following extract_textures(), it
00139 //               can be used to pick up any additional texture
00140 //               references that appeared in the egg hierarchy (but
00141 //               whose EggTexture node was not actually part of the
00142 //               hierarchy).
00143 //
00144 //               If this is called in lieu of extract_textures(), it
00145 //               will fill up the collection with all of the
00146 //               referenced textures (and only the referenced
00147 //               textures), without destructively removing the
00148 //               EggTextures from the hierarchy.
00149 //
00150 //               This also has the side effect of incrementing the
00151 //               internal usage count for a texture in the collection
00152 //               each time a texture reference is encountered.  This
00153 //               side effect is taken advantage of by
00154 //               remove_unused_textures().
00155 ////////////////////////////////////////////////////////////////////
00156 int EggTextureCollection::
00157 find_used_textures(EggNode *node) {
00158   int num_found = 0;
00159 
00160   if (node->is_of_type(EggPrimitive::get_class_type())) {
00161     EggPrimitive *primitive = DCAST(EggPrimitive, node);
00162     if (primitive->has_texture()) {
00163       EggTexture *tex = primitive->get_texture();
00164       Textures::iterator ti = _textures.find(tex);
00165       if (ti == _textures.end()) {
00166         // Here's a new texture!
00167         num_found++;
00168         _textures.insert(Textures::value_type(tex, 1));
00169         _ordered_textures.push_back(tex);
00170       } else {
00171         // Here's a texture we'd already known about.  Increment its
00172         // usage count.
00173         (*ti).second++;
00174       }
00175     }
00176 
00177   } else if (node->is_of_type(EggGroupNode::get_class_type())) {
00178     EggGroupNode *group = DCAST(EggGroupNode, node);
00179 
00180     EggGroupNode::iterator ci;
00181     for (ci = group->begin(); ci != group->end(); ++ci) {
00182       EggNode *child = *ci;
00183 
00184       num_found += find_used_textures(child);
00185     }
00186   }
00187 
00188   return num_found;
00189 }
00190 
00191 ////////////////////////////////////////////////////////////////////
00192 //     Function: EggTextureCollection::remove_unused_textures
00193 //       Access: Public
00194 //  Description: Removes any textures from the collection that aren't
00195 //               referenced by any primitives in the indicated egg
00196 //               hierarchy.  This also, incidentally, adds textures to
00197 //               the collection that had been referenced by primitives
00198 //               but had not previously appeared in the collection.
00199 ////////////////////////////////////////////////////////////////////
00200 void EggTextureCollection::
00201 remove_unused_textures(EggNode *node) {
00202   // We'll do this the easy way: First, we'll remove *all* the
00203   // textures from the collection, and then we'll add back only those
00204   // that appear in the hierarchy.
00205   clear();
00206   find_used_textures(node);
00207 }
00208 
00209 ////////////////////////////////////////////////////////////////////
00210 //     Function: EggTextureCollection::collapse_equivalent_textures
00211 //       Access: Public
00212 //  Description: Walks through the collection and collapses together
00213 //               any separate textures that are equivalent according
00214 //               to the indicated equivalence factor, eq (see
00215 //               EggTexture::is_equivalent_to()).  The return value is
00216 //               the number of textures removed.
00217 //
00218 //               This flavor of collapse_equivalent_textures()
00219 //               automatically adjusts all the primitives in the egg
00220 //               hierarchy to refer to the new texture pointers.
00221 ////////////////////////////////////////////////////////////////////
00222 int EggTextureCollection::
00223 collapse_equivalent_textures(int eq, EggGroupNode *node) {
00224   TextureReplacement removed;
00225   int num_collapsed = collapse_equivalent_textures(eq, removed);
00226 
00227   // And now walk the egg hierarchy and replace any references to a
00228   // removed texture with its replacement.
00229   replace_textures(node, removed);
00230 
00231   return num_collapsed;
00232 }
00233 
00234 ////////////////////////////////////////////////////////////////////
00235 //     Function: EggTextureCollection::collapse_equivalent_textures
00236 //       Access: Public
00237 //  Description: Walks through the collection and collapses together
00238 //               any separate textures that are equivalent according
00239 //               to the indicated equivalence factor, eq (see
00240 //               EggTexture::is_equivalent_to()).  The return value is
00241 //               the number of textures removed.
00242 //
00243 //               This flavor of collapse_equivalent_textures() does
00244 //               not adjust any primitives in the egg hierarchy;
00245 //               instead, it fills up the 'removed' map with an entry
00246 //               for each removed texture, mapping it back to the
00247 //               equivalent retained texture.  It's up to the user to
00248 //               then call replace_textures() with this map, if
00249 //               desired, to apply these changes to the egg hierarchy.
00250 ////////////////////////////////////////////////////////////////////
00251 int EggTextureCollection::
00252 collapse_equivalent_textures(int eq, EggTextureCollection::TextureReplacement &removed) {
00253   int num_collapsed = 0;
00254 
00255   typedef pset<PT(EggTexture), UniqueEggTextures> Collapser;
00256   UniqueEggTextures uet(eq);
00257   Collapser collapser(uet);
00258 
00259   // First, put all of the textures into the Collapser structure, to
00260   // find out the unique textures.
00261   OrderedTextures::const_iterator oti;
00262   for (oti = _ordered_textures.begin();
00263        oti != _ordered_textures.end();
00264        ++oti) {
00265     EggTexture *tex = (*oti);
00266 
00267     pair<Collapser::const_iterator, bool> result = collapser.insert(tex);
00268     if (!result.second) {
00269       // This texture is non-unique; another one was already there.
00270       EggTexture *first = *(result.first);
00271       removed.insert(TextureReplacement::value_type(tex, first));
00272       num_collapsed++;
00273     }
00274   }
00275 
00276   // Now record all of the unique textures only.
00277   clear();
00278   Collapser::const_iterator ci;
00279   for (ci = collapser.begin(); ci != collapser.end(); ++ci) {
00280     add_texture(*ci);
00281   }
00282 
00283   return num_collapsed;
00284 }
00285 
00286 ////////////////////////////////////////////////////////////////////
00287 //     Function: EggTextureCollection::replace_textures
00288 //       Access: Public, Static
00289 //  Description: Walks the egg hierarchy, changing out any reference
00290 //               to a texture appearing on the left side of the map
00291 //               with its corresponding texture on the right side.
00292 //               This is most often done following a call to
00293 //               collapse_equivalent_textures().  It does not directly
00294 //               affect the Collection.
00295 ////////////////////////////////////////////////////////////////////
00296 void EggTextureCollection::
00297 replace_textures(EggGroupNode *node,
00298                  const EggTextureCollection::TextureReplacement &replace) {
00299   EggGroupNode::iterator ci;
00300   for (ci = node->begin();
00301        ci != node->end();
00302        ++ci) {
00303     EggNode *child = *ci;
00304     if (child->is_of_type(EggPrimitive::get_class_type())) {
00305       EggPrimitive *primitive = DCAST(EggPrimitive, child);
00306       if (primitive->has_texture()) {
00307         PT(EggTexture) tex = primitive->get_texture();
00308         TextureReplacement::const_iterator ri;
00309         ri = replace.find(tex);
00310         if (ri != replace.end()) {
00311           // Here's a texture we want to replace.
00312           primitive->set_texture((*ri).second);
00313         }
00314       }
00315 
00316     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00317       EggGroupNode *group_child = DCAST(EggGroupNode, child);
00318       replace_textures(group_child, replace);
00319     }
00320   }
00321 }
00322 
00323 ////////////////////////////////////////////////////////////////////
00324 //     Function: EggTextureCollection::uniquify_trefs
00325 //       Access: Public
00326 //  Description: Guarantees that each texture in the collection has a
00327 //               unique TRef name.  This is essential before writing
00328 //               an egg file.
00329 ////////////////////////////////////////////////////////////////////
00330 void EggTextureCollection::
00331 uniquify_trefs() {
00332   NameUniquifier nu(".tref", "tref");
00333 
00334   OrderedTextures::const_iterator oti;
00335   for (oti = _ordered_textures.begin();
00336        oti != _ordered_textures.end();
00337        ++oti) {
00338     EggTexture *tex = (*oti);
00339 
00340     tex->set_name(nu.add_name(tex->get_name()));
00341   }
00342 }
00343 
00344 ////////////////////////////////////////////////////////////////////
00345 //     Function: EggTextureCollection::sort_by_tref
00346 //       Access: Public
00347 //  Description: Sorts all the textures into alphabetical order by
00348 //               TRef name.  Subsequent operations using begin()/end()
00349 //               will traverse in this sorted order.
00350 ////////////////////////////////////////////////////////////////////
00351 void EggTextureCollection::
00352 sort_by_tref() {
00353   sort(_ordered_textures.begin(), _ordered_textures.end(),
00354        NamableOrderByName());
00355 }
00356 
00357 ////////////////////////////////////////////////////////////////////
00358 //     Function: EggTextureCollection::add_texture
00359 //       Access: Public
00360 //  Description: Explicitly adds a new texture to the collection.
00361 //               Returns true if the texture was added, false if it
00362 //               was already there or if there was some error.
00363 ////////////////////////////////////////////////////////////////////
00364 bool EggTextureCollection::
00365 add_texture(EggTexture *texture) {
00366   nassertr(_textures.size() == _ordered_textures.size(), false);
00367 
00368   PT(EggTexture) new_tex = texture;
00369 
00370   Textures::const_iterator ti;
00371   ti = _textures.find(new_tex);
00372   if (ti != _textures.end()) {
00373     // This texture is already a member of the collection.
00374     return false;
00375   }
00376 
00377   _textures.insert(Textures::value_type(new_tex, 0));
00378   _ordered_textures.push_back(new_tex);
00379 
00380   nassertr(_textures.size() == _ordered_textures.size(), false);
00381   return true;
00382 }
00383 
00384 ////////////////////////////////////////////////////////////////////
00385 //     Function: EggTextureCollection::remove_texture
00386 //       Access: Public
00387 //  Description: Explicitly removes a texture from the collection.
00388 //               Returns true if the texture was removed, false if it
00389 //               wasn't there or if there was some error.
00390 ////////////////////////////////////////////////////////////////////
00391 bool EggTextureCollection::
00392 remove_texture(EggTexture *texture) {
00393   nassertr(_textures.size() == _ordered_textures.size(), false);
00394 
00395   Textures::iterator ti;
00396   ti = _textures.find(texture);
00397   if (ti == _textures.end()) {
00398     // This texture is not a member of the collection.
00399     return false;
00400   }
00401 
00402   _textures.erase(ti);
00403 
00404   OrderedTextures::iterator oti;
00405   PT(EggTexture) ptex = texture;
00406   oti = find(_ordered_textures.begin(), _ordered_textures.end(), ptex);
00407   nassertr(oti != _ordered_textures.end(), false);
00408 
00409   _ordered_textures.erase(oti);
00410 
00411   nassertr(_textures.size() == _ordered_textures.size(), false);
00412   return true;
00413 }
00414 
00415 ////////////////////////////////////////////////////////////////////
00416 //     Function: EggTextureCollection::create_unique_texture
00417 //       Access: Public
00418 //  Description: Creates a new texture if there is not already one
00419 //               equivalent (according to eq, see
00420 //               EggTexture::is_equivalent_to()) to the indicated
00421 //               texture, or returns the existing one if there is.
00422 ////////////////////////////////////////////////////////////////////
00423 EggTexture *EggTextureCollection::
00424 create_unique_texture(const EggTexture &copy, int eq) {
00425   // This requires a complete linear traversal, not terribly
00426   // efficient.
00427   OrderedTextures::const_iterator oti;
00428   for (oti = _ordered_textures.begin();
00429        oti != _ordered_textures.end();
00430        ++oti) {
00431     EggTexture *tex = (*oti);
00432     if (copy.is_equivalent_to(*tex, eq)) {
00433       return tex;
00434     }
00435   }
00436 
00437   EggTexture *new_texture = new EggTexture(copy);
00438   add_texture(new_texture);
00439   return new_texture;
00440 }
00441 
00442 ////////////////////////////////////////////////////////////////////
00443 //     Function: EggTextureCollection::find_tref
00444 //       Access: Public
00445 //  Description: Returns the texture with the indicated TRef name, or
00446 //               NULL if no texture matches.
00447 ////////////////////////////////////////////////////////////////////
00448 EggTexture *EggTextureCollection::
00449 find_tref(const string &tref_name) const {
00450   // This requires a complete linear traversal, not terribly
00451   // efficient.
00452   OrderedTextures::const_iterator oti;
00453   for (oti = _ordered_textures.begin();
00454        oti != _ordered_textures.end();
00455        ++oti) {
00456     EggTexture *tex = (*oti);
00457     if (tex->get_name() == tref_name) {
00458       return tex;
00459     }
00460   }
00461 
00462   return (EggTexture *)NULL;
00463 }
00464 
00465 ////////////////////////////////////////////////////////////////////
00466 //     Function: EggTextureCollection::find_filename
00467 //       Access: Public
00468 //  Description: Returns the texture with the indicated filename, or
00469 //               NULL if no texture matches.
00470 ////////////////////////////////////////////////////////////////////
00471 EggTexture *EggTextureCollection::
00472 find_filename(const Filename &filename) const {
00473   // This requires a complete linear traversal, not terribly
00474   // efficient.
00475   OrderedTextures::const_iterator oti;
00476   for (oti = _ordered_textures.begin();
00477        oti != _ordered_textures.end();
00478        ++oti) {
00479     EggTexture *tex = (*oti);
00480     if (tex->get_filename() == filename) {
00481       return tex;
00482     }
00483   }
00484 
00485   return (EggTexture *)NULL;
00486 }

Generated on Fri May 2 00:38:01 2003 for Panda by doxygen1.3