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

panda/src/egg/eggGroupNode.cxx

Go to the documentation of this file.
00001 // Filename: eggGroupNode.cxx
00002 // Created by:  drose (16Jan99)
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 "eggGroupNode.h"
00020 #include "eggCoordinateSystem.h"
00021 #include "eggData.h"
00022 #include "eggFilenameNode.h"
00023 #include "eggExternalReference.h"
00024 #include "eggPrimitive.h"
00025 #include "eggPolygon.h"
00026 #include "eggVertexPool.h"
00027 #include "eggVertex.h"
00028 #include "eggTextureCollection.h"
00029 #include "eggMaterialCollection.h"
00030 #include "pt_EggTexture.h"
00031 #include "pt_EggMaterial.h"
00032 #include "config_egg.h"
00033 
00034 #include "dSearchPath.h"
00035 #include "deg_2_rad.h"
00036 
00037 #include <algorithm>
00038 
00039 TypeHandle EggGroupNode::_type_handle;
00040 
00041 
00042 ////////////////////////////////////////////////////////////////////
00043 //     Function: EggGroupNode::Copy constructor
00044 //       Access: Public
00045 //  Description:
00046 ////////////////////////////////////////////////////////////////////
00047 EggGroupNode::
00048 EggGroupNode(const EggGroupNode &copy) : EggNode(copy) {
00049   if (!copy.empty()) {
00050     egg_cat.warning()
00051       << "The EggGroupNode copy constructor does not copy children!\n";
00052   }
00053 }
00054 
00055 ////////////////////////////////////////////////////////////////////
00056 //     Function: EggGroupNode::Copy assignment operator
00057 //       Access: Public
00058 //  Description:
00059 ////////////////////////////////////////////////////////////////////
00060 EggGroupNode &EggGroupNode::
00061 operator =(const EggGroupNode &copy) {
00062   if (!copy.empty()) {
00063     egg_cat.warning()
00064       << "The EggGroupNode copy assignment does not copy children!\n";
00065   }
00066   EggNode::operator =(copy);
00067   return *this;
00068 }
00069 
00070 ////////////////////////////////////////////////////////////////////
00071 //     Function: EggGroupNode::Destructor
00072 //       Access: Public, Virtual
00073 //  Description:
00074 ////////////////////////////////////////////////////////////////////
00075 EggGroupNode::
00076 ~EggGroupNode() {
00077 }
00078 
00079 
00080 ////////////////////////////////////////////////////////////////////
00081 //     Function: EggGroupNode::write
00082 //       Access: Public, Virtual
00083 //  Description: Writes the group and all of its children to the
00084 //               indicated output stream in Egg format.
00085 ////////////////////////////////////////////////////////////////////
00086 void EggGroupNode::
00087 write(ostream &out, int indent_level) const {
00088   iterator i;
00089   for (i = begin(); i != end(); ++i) {
00090     (*i)->write(out, indent_level);
00091   }
00092 }
00093 
00094 ////////////////////////////////////////////////////////////////////
00095 //     Function: EggGroupNode::begin
00096 //       Access: Public
00097 //  Description:
00098 ////////////////////////////////////////////////////////////////////
00099 EggGroupNode::iterator EggGroupNode::
00100 begin() const {
00101   return _children.begin();
00102 }
00103 
00104 ////////////////////////////////////////////////////////////////////
00105 //     Function: EggGroupNode::end
00106 //       Access: Public
00107 //  Description:
00108 ////////////////////////////////////////////////////////////////////
00109 EggGroupNode::iterator EggGroupNode::
00110 end() const {
00111   return _children.end();
00112 }
00113 
00114 ////////////////////////////////////////////////////////////////////
00115 //     Function: EggGroupNode::rbegin
00116 //       Access: Public
00117 //  Description:
00118 ////////////////////////////////////////////////////////////////////
00119 EggGroupNode::reverse_iterator EggGroupNode::
00120 rbegin() const {
00121   return _children.rbegin();
00122 }
00123 
00124 ////////////////////////////////////////////////////////////////////
00125 //     Function: EggGroupNode::rend
00126 //       Access: Public
00127 //  Description:
00128 ////////////////////////////////////////////////////////////////////
00129 EggGroupNode::reverse_iterator EggGroupNode::
00130 rend() const {
00131   return _children.rend();
00132 }
00133 
00134 ////////////////////////////////////////////////////////////////////
00135 //     Function: EggGroupNode::empty
00136 //       Access: Public
00137 //  Description:
00138 ////////////////////////////////////////////////////////////////////
00139 bool EggGroupNode::
00140 empty() const {
00141   return _children.empty();
00142 }
00143 
00144 ////////////////////////////////////////////////////////////////////
00145 //     Function: EggGroupNode::size
00146 //       Access: Public
00147 //  Description:
00148 ////////////////////////////////////////////////////////////////////
00149 EggGroupNode::size_type EggGroupNode::
00150 size() const {
00151   return _children.size();
00152 }
00153 
00154 ////////////////////////////////////////////////////////////////////
00155 //     Function: EggGroupNode::insert
00156 //       Access: Public
00157 //  Description:
00158 ////////////////////////////////////////////////////////////////////
00159 EggGroupNode::iterator EggGroupNode::
00160 insert(iterator position, PT(EggNode) x) {
00161   prepare_add_child(x);
00162   return _children.insert((Children::iterator &)position, x);
00163 }
00164 
00165 ////////////////////////////////////////////////////////////////////
00166 //     Function: EggGroupNode::erase
00167 //       Access: Public
00168 //  Description:
00169 ////////////////////////////////////////////////////////////////////
00170 EggGroupNode::iterator EggGroupNode::
00171 erase(iterator position) {
00172   prepare_remove_child(*position);
00173   return _children.erase((Children::iterator &)position);
00174 }
00175 
00176 ////////////////////////////////////////////////////////////////////
00177 //     Function: EggGroupNode::erase
00178 //       Access: Public
00179 //  Description:
00180 ////////////////////////////////////////////////////////////////////
00181 EggGroupNode::iterator EggGroupNode::
00182 erase(iterator first, iterator last) {
00183   iterator i;
00184   for (i = first; i != last; ++i) {
00185     prepare_remove_child(*i);
00186   }
00187   return _children.erase((Children::iterator &)first,
00188                          (Children::iterator &)last);
00189 }
00190 
00191 ////////////////////////////////////////////////////////////////////
00192 //     Function: EggGroupNode::replace
00193 //       Access: Public
00194 //  Description: Replaces the node at the indicated position with
00195 //               the indicated node.  It is an error to call this
00196 //               with an invalid position iterator (e.g. end()).
00197 ////////////////////////////////////////////////////////////////////
00198 void EggGroupNode::
00199 replace(iterator position, PT(EggNode) x) {
00200   nassertv(position != end());
00201 
00202   prepare_remove_child(*position);
00203   prepare_add_child(x);
00204   *(Children::iterator &)position = x;
00205 }
00206 
00207 ////////////////////////////////////////////////////////////////////
00208 //     Function: EggGroupNode::clear
00209 //       Access: Public
00210 //  Description:
00211 ////////////////////////////////////////////////////////////////////
00212 void EggGroupNode::
00213 clear() {
00214   erase(begin(), end());
00215 }
00216 
00217 
00218 ////////////////////////////////////////////////////////////////////
00219 //     Function: EggGroupNode::add_child
00220 //       Access: Public
00221 //  Description: Adds the indicated child to the group and returns it.
00222 //               If the child node is already a child of some other
00223 //               node, removes it first.
00224 ////////////////////////////////////////////////////////////////////
00225 PT(EggNode) EggGroupNode::
00226 add_child(PT(EggNode) node) {
00227   if (node->_parent != NULL) {
00228     node->_parent->remove_child(node);
00229   }
00230   prepare_add_child(node);
00231   _children.push_back(node);
00232   return node;
00233 }
00234 
00235 ////////////////////////////////////////////////////////////////////
00236 //     Function: EggGroupNode::remove_child
00237 //       Access: Public
00238 //  Description: Removes the indicated child node from the group and
00239 //               returns it.  If the child was not already in the
00240 //               group, does nothing and returns NULL.
00241 ////////////////////////////////////////////////////////////////////
00242 PT(EggNode) EggGroupNode::
00243 remove_child(PT(EggNode) node) {
00244   iterator i = find(begin(), end(), node);
00245   if (i == end()) {
00246     return PT(EggNode)();
00247   } else {
00248     // erase() calls prepare_remove_child().
00249     erase(i);
00250     return node;
00251   }
00252 }
00253 
00254 
00255 ////////////////////////////////////////////////////////////////////
00256 //     Function: EggGroupNode::steal_children
00257 //       Access: Public
00258 //  Description: Moves all the children from the other node to this
00259 //               one.  This is especially useful because the group
00260 //               node copy assignment operator does not copy children.
00261 ////////////////////////////////////////////////////////////////////
00262 void EggGroupNode::
00263 steal_children(EggGroupNode &other) {
00264   Children::iterator ci;
00265   for (ci = other._children.begin();
00266        ci != other._children.end();
00267        ++ci) {
00268     other.prepare_remove_child(*ci);
00269     prepare_add_child(*ci);
00270   }
00271 
00272   _children.splice(_children.end(), other._children);
00273 }
00274 
00275 
00276 ////////////////////////////////////////////////////////////////////
00277 //     Function: EggGroupNode::resolve_filenames
00278 //       Access: Public
00279 //  Description: Walks the tree and attempts to resolve any filenames
00280 //               encountered.  This looks up filenames in the search
00281 //               path, etc.  It does not automatically search the
00282 //               egg_path for missing files.
00283 ////////////////////////////////////////////////////////////////////
00284 void EggGroupNode::
00285 resolve_filenames(const DSearchPath &searchpath) {
00286   Children::iterator ci;
00287   for (ci = _children.begin();
00288        ci != _children.end();
00289        ++ci) {
00290     EggNode *child = *ci;
00291     if (child->is_of_type(EggTexture::get_class_type())) {
00292       EggTexture *tex = DCAST(EggTexture, child);
00293       Filename tex_filename = tex->get_filename();
00294       tex_filename.resolve_filename(searchpath);
00295       tex->set_filename(tex_filename);
00296 
00297       if (tex->has_alpha_filename()) {
00298         Filename alpha_filename = tex->get_alpha_filename();
00299         alpha_filename.resolve_filename(searchpath);
00300         tex->set_alpha_filename(alpha_filename);
00301       }
00302 
00303     } else if (child->is_of_type(EggFilenameNode::get_class_type())) {
00304       EggFilenameNode *fnode = DCAST(EggFilenameNode, child);
00305       Filename filename = fnode->get_filename();
00306       filename.resolve_filename(searchpath, fnode->get_default_extension());
00307       fnode->set_filename(filename);
00308 
00309     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00310       DCAST(EggGroupNode, child)->resolve_filenames(searchpath);
00311     }
00312   }
00313 }
00314 
00315 ////////////////////////////////////////////////////////////////////
00316 //     Function: EggGroupNode::reverse_vertex_ordering
00317 //       Access: Public
00318 //  Description: Reverses the vertex ordering of all polygons defined
00319 //               at this node and below.  Does not change the surface
00320 //               normals, if any.
00321 ////////////////////////////////////////////////////////////////////
00322 void EggGroupNode::
00323 reverse_vertex_ordering() {
00324   Children::iterator ci;
00325   for (ci = _children.begin();
00326        ci != _children.end();
00327        ++ci) {
00328     EggNode *child = *ci;
00329     if (child->is_of_type(EggPrimitive::get_class_type())) {
00330       EggPrimitive *prim = DCAST(EggPrimitive, child);
00331       prim->reverse_vertex_ordering();
00332 
00333     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00334       DCAST(EggGroupNode, child)->reverse_vertex_ordering();
00335     }
00336   }
00337 }
00338 
00339 ////////////////////////////////////////////////////////////////////
00340 //     Function: EggGroupNode::recompute_vertex_normals
00341 //       Access: Public
00342 //  Description: Recomputes all the vertex normals for polygon
00343 //               geometry at this group node and below so that they
00344 //               accurately reflect the vertex positions.  A shared
00345 //               edge between two polygons (even in different groups)
00346 //               is considered smooth if the angle between the two
00347 //               edges is less than threshold degrees.
00348 //
00349 //               This function also removes degenerate polygons that
00350 //               do not have enough vertices to define a normal.  It
00351 //               does not affect normals for other kinds of primitives
00352 //               like Nurbs or Points.
00353 //
00354 //               This function does not remove or adjust vertices in
00355 //               the vertex pool; it only adds new vertices with the
00356 //               correct normals.  Thus, it is a good idea to call
00357 //               remove_unused_vertices() after calling this.
00358 ////////////////////////////////////////////////////////////////////
00359 void EggGroupNode::
00360 recompute_vertex_normals(double threshold, CoordinateSystem cs) {
00361   // First, collect all the vertices together with their shared
00362   // polygons.
00363   NVertexCollection collection;
00364   r_collect_vertex_normals(collection, threshold, cs);
00365 
00366   // Now bust them into separate groups according to the edge
00367   // threshold.  Two polygons that share a vertex belong in the same
00368   // group only if the angle between their normals is within the
00369   // threshold.
00370 
00371   double cos_angle = cos(deg_2_rad(threshold));
00372 
00373   NVertexCollection::iterator ci;
00374   for (ci = collection.begin(); ci != collection.end(); ++ci) {
00375     NVertexGroup &group = (*ci).second;
00376 
00377     // Here's a group of polygons that share a vertex.  Build up a new
00378     // group that consists of just the first polygon and all the ones
00379     // that are within threshold degrees from it.
00380     NVertexGroup::iterator gi;
00381     gi = group.begin();
00382     while (gi != group.end()) {
00383       const NVertexReference &base_ref = (*gi);
00384       NVertexGroup new_group;
00385       NVertexGroup leftover_group;
00386       new_group.push_back(base_ref);
00387       ++gi;
00388 
00389       while (gi != group.end()) {
00390         const NVertexReference &ref = (*gi);
00391         double dot = base_ref._normal.dot(ref._normal);
00392         if (dot > cos_angle) {
00393           // These polygons are close enough to the same angle.
00394           new_group.push_back(ref);
00395         } else {
00396           // These polygons are not.
00397           leftover_group.push_back(ref);
00398         }
00399         ++gi;
00400       }
00401 
00402       // Now new_group is a collection of connected polygons and the
00403       // vertices that connect them.  Smooth these vertices.
00404       do_compute_vertex_normals(new_group);
00405 
00406       // And reset the group of remaining polygons.
00407       group.swap(leftover_group);
00408       gi = group.begin();
00409     }
00410   }
00411 }
00412 
00413 ////////////////////////////////////////////////////////////////////
00414 //     Function: EggGroupNode::recompute_polygon_normals
00415 //       Access: Public
00416 //  Description: Recomputes all the polygon normals for polygon
00417 //               geometry at this group node and below so that they
00418 //               accurately reflect the vertex positions.  Normals are
00419 //               removed from the vertices and defined only on
00420 //               polygons, giving the geometry a faceted appearance.
00421 //
00422 //               This function also removes degenerate polygons that
00423 //               do not have enough vertices to define a normal.  It
00424 //               does not affect normals for other kinds of primitives
00425 //               like Nurbs or Points.
00426 //
00427 //               This function does not remove or adjust vertices in
00428 //               the vertex pool; it only adds new vertices with the
00429 //               normals removed.  Thus, it is a good idea to call
00430 //               remove_unused_vertices() after calling this.
00431 ////////////////////////////////////////////////////////////////////
00432 void EggGroupNode::
00433 recompute_polygon_normals(CoordinateSystem cs) {
00434   Children::iterator ci, cnext;
00435   ci = _children.begin();
00436   while (ci != _children.end()) {
00437     cnext = ci;
00438     ++cnext;
00439     EggNode *child = *ci;
00440 
00441     if (child->is_of_type(EggPolygon::get_class_type())) {
00442       EggPolygon *polygon = DCAST(EggPolygon, child);
00443 
00444       if (!polygon->recompute_polygon_normal(cs)) {
00445         // The polygon is degenerate.  Remove it.
00446         prepare_remove_child(child);
00447         _children.erase(ci);
00448 
00449       } else {
00450         // Remove the normal from each polygon vertex.
00451         size_t num_vertices = polygon->size();
00452         for (size_t i = 0; i < num_vertices; i++) {
00453           EggVertex *vertex = polygon->get_vertex(i);
00454           EggVertexPool *pool = vertex->get_pool();
00455 
00456           if (vertex->has_normal()) {
00457             EggVertex new_vertex(*vertex);
00458             new_vertex.clear_normal();
00459             EggVertex *unique = pool->create_unique_vertex(new_vertex);
00460             unique->copy_grefs_from(*vertex);
00461 
00462             polygon->set_vertex(i, unique);
00463           }
00464         }
00465       }
00466 
00467     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00468       DCAST(EggGroupNode, child)->recompute_polygon_normals(cs);
00469     }
00470 
00471     ci = cnext;
00472   }
00473 }
00474 
00475 ////////////////////////////////////////////////////////////////////
00476 //     Function: EggGroupNode::strip_normals
00477 //       Access: Public
00478 //  Description: Removes all normals from primitives, and the vertices
00479 //               they reference, at this node and below.
00480 //
00481 //               This function does not remove or adjust vertices in
00482 //               the vertex pool; it only adds new vertices with the
00483 //               normal removed.  Thus, it is a good idea to call
00484 //               remove_unused_vertices() after calling this.
00485 ////////////////////////////////////////////////////////////////////
00486 void EggGroupNode::
00487 strip_normals() {
00488   Children::iterator ci;
00489   for (ci = _children.begin(); ci != _children.end(); ++ci) {
00490     EggNode *child = *ci;
00491 
00492     if (child->is_of_type(EggPrimitive::get_class_type())) {
00493       EggPrimitive *prim = DCAST(EggPrimitive, child);
00494       prim->clear_normal();
00495 
00496       // Remove the normal from each prim vertex.
00497       size_t num_vertices = prim->size();
00498       for (size_t i = 0; i < num_vertices; i++) {
00499         EggVertex *vertex = prim->get_vertex(i);
00500         EggVertexPool *pool = vertex->get_pool();
00501 
00502         if (vertex->has_normal()) {
00503           EggVertex new_vertex(*vertex);
00504           new_vertex.clear_normal();
00505           EggVertex *unique = pool->create_unique_vertex(new_vertex);
00506           unique->copy_grefs_from(*vertex);
00507 
00508           prim->set_vertex(i, unique);
00509         }
00510       }
00511 
00512     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00513       DCAST(EggGroupNode, child)->strip_normals();
00514     }
00515   }
00516 }
00517 
00518 ////////////////////////////////////////////////////////////////////
00519 //     Function: EggGroupNode::triangulate_polygons
00520 //       Access: Public
00521 //  Description: Replace all higher-order polygons at this point in
00522 //               the scene graph and below with triangles.  Returns
00523 //               the total number of new triangles produced, less
00524 //               degenerate polygons removed.
00525 //
00526 //               If convex_also is true, both concave and convex
00527 //               polygons will be subdivided into triangles;
00528 //               otherwise, only concave polygons will be subdivided,
00529 //               and convex polygons will be largely unchanged.
00530 ////////////////////////////////////////////////////////////////////
00531 int EggGroupNode::
00532 triangulate_polygons(bool convex_also) {
00533   int num_produced = 0;
00534 
00535   Children children_copy = _children;
00536 
00537   Children::iterator ci;
00538   for (ci = children_copy.begin();
00539        ci != children_copy.end();
00540        ++ci) {
00541     EggNode *child = (*ci);
00542 
00543     if (child->is_of_type(EggPolygon::get_class_type())) {
00544       EggPolygon *poly = DCAST(EggPolygon, child);
00545       poly->triangulate_in_place(convex_also);
00546 
00547     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00548       num_produced += DCAST(EggGroupNode, child)->triangulate_polygons(convex_also);
00549     }
00550   }
00551 
00552   num_produced += max(0, (int)(_children.size() - children_copy.size()));
00553   return num_produced;
00554 }
00555 
00556 
00557 ////////////////////////////////////////////////////////////////////
00558 //     Function: EggGroupNode::remove_unused_vertices
00559 //       Access: Public
00560 //  Description: Removes all vertices from VertexPools within this
00561 //               group or below that are not referenced by at least
00562 //               one primitive.  Also renumbers all vertices after the
00563 //               operation so their indices are consecutive, beginning
00564 //               at zero.  Returns the total number of vertices removed.
00565 //
00566 //               Note that this operates on the VertexPools within
00567 //               this group level, without respect to primitives that
00568 //               reference these vertices (unlike other functions like
00569 //               strip_normals()).  It is therefore most useful to
00570 //               call this on the EggData root, rather than on a
00571 //               subgroup within the hierarchy, since a VertexPool may
00572 //               appear anywhere in the hierarchy.
00573 ////////////////////////////////////////////////////////////////////
00574 int EggGroupNode::
00575 remove_unused_vertices() {
00576   int num_removed = 0;
00577 
00578   Children::iterator ci, cnext;
00579   ci = _children.begin();
00580   while (ci != _children.end()) {
00581     cnext = ci;
00582     ++cnext;
00583     EggNode *child = *ci;
00584 
00585     if (child->is_of_type(EggVertexPool::get_class_type())) {
00586       EggVertexPool *vpool = DCAST(EggVertexPool, child);
00587       num_removed += vpool->remove_unused_vertices();
00588 
00589       if (vpool->empty()) {
00590         // If, after removing all the vertices, there's nothing left
00591         // in the vertex pool, then remove the whole vertex pool.
00592         _children.erase(ci);
00593       }
00594 
00595     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00596       num_removed += DCAST(EggGroupNode, child)->remove_unused_vertices();
00597     }
00598 
00599     ci = cnext;
00600   }
00601 
00602   return num_removed;
00603 }
00604 
00605 ////////////////////////////////////////////////////////////////////
00606 //     Function: EggGroupNode::remove_invalid_primitives
00607 //       Access: Public
00608 //  Description: Removes primitives at this level and below which
00609 //               appear to be degenerate; e.g. polygons with fewer
00610 //               than 3 vertices, etc.  Returns the number of
00611 //               primitives removed.
00612 ////////////////////////////////////////////////////////////////////
00613 int EggGroupNode::
00614 remove_invalid_primitives() {
00615   int num_removed = 0;
00616 
00617   Children::iterator ci, cnext;
00618   ci = _children.begin();
00619   while (ci != _children.end()) {
00620     cnext = ci;
00621     ++cnext;
00622     EggNode *child = *ci;
00623 
00624     if (child->is_of_type(EggPrimitive::get_class_type())) {
00625       EggPrimitive *prim = DCAST(EggPrimitive, child);
00626       if (!prim->cleanup()) {
00627         _children.erase(ci);
00628         num_removed++;
00629       }
00630 
00631     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00632       num_removed += DCAST(EggGroupNode, child)->remove_invalid_primitives();
00633     }
00634 
00635     ci = cnext;
00636   }
00637 
00638   return num_removed;
00639 }
00640 
00641 ////////////////////////////////////////////////////////////////////
00642 //     Function: EggGroupNode::update_under
00643 //       Access: Protected, Virtual
00644 //  Description: This function is called from within EggGroupNode
00645 //               whenever the parentage of the node has changed.  It
00646 //               should update the depth and under_instance flags
00647 //               accordingly.
00648 //
00649 //               Offset is the difference between the old depth value
00650 //               and the new value.  It should be consistent with the
00651 //               supplied depth value.  If it is not, we have some
00652 //               error.
00653 ////////////////////////////////////////////////////////////////////
00654 void EggGroupNode::
00655 update_under(int depth_offset) {
00656   EggNode::update_under(depth_offset);
00657 
00658   Children::iterator ci;
00659   for (ci = _children.begin();
00660        ci != _children.end();
00661        ++ci) {
00662     nassertv((*ci)->get_parent() == this);
00663     (*ci)->update_under(depth_offset);
00664   }
00665 }
00666 
00667 ////////////////////////////////////////////////////////////////////
00668 //     Function: EggGroupNode::r_transform
00669 //       Access: Protected, Virtual
00670 //  Description: This is called from within the egg code by
00671 //               transform().  It applies a transformation matrix
00672 //               to the current node in some sensible way, then
00673 //               continues down the tree.
00674 //
00675 //               The first matrix is the transformation to apply; the
00676 //               second is its inverse.  The third parameter is the
00677 //               coordinate system we are changing to, or CS_default
00678 //               if we are not changing coordinate systems.
00679 ////////////////////////////////////////////////////////////////////
00680 void EggGroupNode::
00681 r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
00682             CoordinateSystem to_cs) {
00683   Children::iterator ci;
00684   for (ci = _children.begin();
00685        ci != _children.end();
00686        ++ci) {
00687     (*ci)->r_transform(mat, inv, to_cs);
00688   }
00689 }
00690 
00691 ////////////////////////////////////////////////////////////////////
00692 //     Function: EggGroupNode::r_transform_vertices
00693 //       Access: Protected, Virtual
00694 //  Description: This is called from within the egg code by
00695 //               transform_vertices_only()().  It applies a
00696 //               transformation matrix to the current node in some
00697 //               sensible way (if the current node is a vertex pool
00698 //               with vertices), then continues down the tree.
00699 ////////////////////////////////////////////////////////////////////
00700 void EggGroupNode::
00701 r_transform_vertices(const LMatrix4d &mat) {
00702   Children::iterator ci;
00703   for (ci = _children.begin();
00704        ci != _children.end();
00705        ++ci) {
00706     (*ci)->r_transform_vertices(mat);
00707   }
00708 }
00709 
00710 ////////////////////////////////////////////////////////////////////
00711 //     Function: EggGroupNode::r_mark_coordsys
00712 //       Access: Protected, Virtual
00713 //  Description: This is only called immediately after loading an egg
00714 //               file from disk, to propagate the value found in the
00715 //               CoordinateSystem entry (or the default Y-up
00716 //               coordinate system) to all nodes that care about what
00717 //               the coordinate system is.
00718 ////////////////////////////////////////////////////////////////////
00719 void EggGroupNode::
00720 r_mark_coordsys(CoordinateSystem cs) {
00721   Children::iterator ci;
00722   for (ci = _children.begin();
00723        ci != _children.end();
00724        ++ci) {
00725     (*ci)->r_mark_coordsys(cs);
00726   }
00727 }
00728 
00729 ////////////////////////////////////////////////////////////////////
00730 //     Function: EggGroupNode::r_flatten_transforms
00731 //       Access: Protected, Virtual
00732 //  Description: The recursive implementation of flatten_transforms().
00733 ////////////////////////////////////////////////////////////////////
00734 void EggGroupNode::
00735 r_flatten_transforms() {
00736   Children::iterator ci;
00737   for (ci = _children.begin();
00738        ci != _children.end();
00739        ++ci) {
00740     (*ci)->r_flatten_transforms();
00741   }
00742 }
00743 
00744 ////////////////////////////////////////////////////////////////////
00745 //     Function: EggGroupNode::r_apply_texmats
00746 //       Access: Protected, Virtual
00747 //  Description: The recursive implementation of apply_texmats().
00748 ////////////////////////////////////////////////////////////////////
00749 void EggGroupNode::
00750 r_apply_texmats(EggTextureCollection &textures) {
00751   Children::iterator ci;
00752   for (ci = _children.begin();
00753        ci != _children.end();
00754        ++ci) {
00755     (*ci)->r_apply_texmats(textures);
00756   }
00757 }
00758 
00759 ////////////////////////////////////////////////////////////////////
00760 //     Function: EggGroupNode::find_coordsys_entry()
00761 //       Access: Protected
00762 //  Description: Walks the tree, looking for an EggCoordinateSystem
00763 //               entry.  If one is found, extracts it and returns its
00764 //               value.  If multiple entries are found, extracts all
00765 //               of them and returns CS_invalid if they disagree.
00766 ////////////////////////////////////////////////////////////////////
00767 CoordinateSystem EggGroupNode::
00768 find_coordsys_entry() {
00769   CoordinateSystem coordsys = CS_default;
00770 
00771   // We can do this ci/cnext iteration through the list as we modify
00772   // it, only because we know this works with an STL list type
00773   // container.  If this were a vector or a set, this wouldn't
00774   // necessarily work.
00775 
00776   Children::iterator ci, cnext;
00777   ci = _children.begin();
00778   while (ci != _children.end()) {
00779     cnext = ci;
00780     ++cnext;
00781     EggNode *child = *ci;
00782 
00783     if (child->is_of_type(EggCoordinateSystem::get_class_type())) {
00784       CoordinateSystem new_cs =
00785         DCAST(EggCoordinateSystem, child)->get_value();
00786 
00787       // Now remove the CoordinateSystem entry from our child list.
00788       prepare_remove_child(child);
00789       _children.erase(ci);
00790 
00791       if (new_cs != CS_default) {
00792         if (coordsys != CS_default && coordsys != new_cs) {
00793           coordsys = CS_invalid;
00794         } else {
00795           coordsys = new_cs;
00796         }
00797       }
00798 
00799     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00800       CoordinateSystem new_cs =
00801         DCAST(EggGroupNode, child)->find_coordsys_entry();
00802       if (new_cs != CS_default) {
00803         if (coordsys != CS_default && coordsys != new_cs) {
00804           coordsys = CS_invalid;
00805         } else {
00806           coordsys = new_cs;
00807         }
00808       }
00809     }
00810 
00811     ci = cnext;
00812   }
00813 
00814   return coordsys;
00815 }
00816 
00817 ////////////////////////////////////////////////////////////////////
00818 //     Function: EggGroupNode::find_textures()
00819 //       Access: Protected
00820 //  Description: Walks the tree, looking for EggTextures.  Each
00821 //               EggTexture that is found is removed from the
00822 //               hierarchy and added to the EggTextureCollection.
00823 //               Returns the number of EggTextures found.
00824 ////////////////////////////////////////////////////////////////////
00825 int EggGroupNode::
00826 find_textures(EggTextureCollection *collection) {
00827   int num_found = 0;
00828 
00829   // We can do this ci/cnext iteration through the list as we modify
00830   // it, only because we know this works with an STL list type
00831   // container.  If this were a vector or a set, this wouldn't
00832   // necessarily work.
00833 
00834   Children::iterator ci, cnext;
00835   ci = _children.begin();
00836   while (ci != _children.end()) {
00837     cnext = ci;
00838     ++cnext;
00839     EggNode *child = *ci;
00840 
00841     if (child->is_of_type(EggTexture::get_class_type())) {
00842       PT_EggTexture tex = DCAST(EggTexture, child);
00843 
00844       // Now remove the EggTexture entry from our child list.
00845       prepare_remove_child(tex);
00846       _children.erase(ci);
00847 
00848       // And add it to the collection.
00849       collection->add_texture(tex);
00850       num_found++;
00851 
00852     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00853       num_found +=
00854         DCAST(EggGroupNode, child)->find_textures(collection);
00855     }
00856 
00857     ci = cnext;
00858   }
00859 
00860   return num_found;
00861 }
00862 
00863 ////////////////////////////////////////////////////////////////////
00864 //     Function: EggGroupNode::find_materials()
00865 //       Access: Protected
00866 //  Description: Walks the tree, looking for EggMaterials.  Each
00867 //               EggMaterial that is found is removed from the
00868 //               hierarchy and added to the EggMaterialCollection.
00869 //               Returns the number of EggMaterials found.
00870 ////////////////////////////////////////////////////////////////////
00871 int EggGroupNode::
00872 find_materials(EggMaterialCollection *collection) {
00873   int num_found = 0;
00874 
00875   // We can do this ci/cnext iteration through the list as we modify
00876   // it, only because we know this works with an STL list type
00877   // container.  If this were a vector or a set, this wouldn't
00878   // necessarily work.
00879 
00880   Children::iterator ci, cnext;
00881   ci = _children.begin();
00882   while (ci != _children.end()) {
00883     cnext = ci;
00884     ++cnext;
00885     EggNode *child = *ci;
00886 
00887     if (child->is_of_type(EggMaterial::get_class_type())) {
00888       PT_EggMaterial tex = DCAST(EggMaterial, child);
00889 
00890       // Now remove the EggMaterial entry from our child list.
00891       prepare_remove_child(tex);
00892       _children.erase(ci);
00893 
00894       // And add it to the collection.
00895       collection->add_material(tex);
00896       num_found++;
00897 
00898     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00899       num_found +=
00900         DCAST(EggGroupNode, child)->find_materials(collection);
00901     }
00902 
00903     ci = cnext;
00904   }
00905 
00906   return num_found;
00907 }
00908 
00909 ////////////////////////////////////////////////////////////////////
00910 //     Function: EggGroupNode::r_load_externals
00911 //       Access: Protected
00912 //  Description: Walks the tree and locates unloaded external
00913 //               reference nodes, which it attempts to locate and load
00914 //               in.  The reference node is replaced with the entire
00915 //               subtree loaded.  This is intended to be called from
00916 //               EggData::load_externals().
00917 ////////////////////////////////////////////////////////////////////
00918 bool EggGroupNode::
00919 r_load_externals(const DSearchPath &searchpath, CoordinateSystem coordsys) {
00920   bool success = true;
00921 
00922   Children::iterator ci;
00923   for (ci = _children.begin();
00924        ci != _children.end();
00925        ++ci) {
00926     EggNode *child = *ci;
00927     if (child->is_of_type(EggExternalReference::get_class_type())) {
00928       PT(EggExternalReference) ref = DCAST(EggExternalReference, child);
00929 
00930       // Replace the reference with an empty group node.  When we load
00931       // the external file successfully, we'll put its contents here.
00932       Filename filename = ref->get_filename();
00933       EggGroupNode *new_node =
00934         new EggGroupNode(filename.get_basename_wo_extension());
00935       replace(ci, new_node);
00936 
00937       if (!EggData::resolve_egg_filename(filename, searchpath)) {
00938         egg_cat.error()
00939           << "Could not locate " << filename << " in "
00940           << searchpath << "\n";
00941       } else {
00942         // Now define a new EggData structure to hold the external
00943         // reference, and load it.
00944         EggData ext_data;
00945         ext_data.set_coordinate_system(coordsys);
00946         ext_data.set_auto_resolve_externals(true);
00947         if (ext_data.read(filename)) {
00948           // The external file was read correctly.  Add its contents
00949           // into the tree at this point.
00950           success =
00951             ext_data.load_externals(searchpath)
00952             && success;
00953           new_node->steal_children(ext_data);
00954         }
00955       }
00956 
00957     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00958       EggGroupNode *group_child = DCAST(EggGroupNode, child);
00959       success =
00960         group_child->r_load_externals(searchpath, coordsys)
00961         && success;
00962     }
00963   }
00964   return success;
00965 }
00966 
00967 
00968 ////////////////////////////////////////////////////////////////////
00969 //     Function: EggGroupNode::prepare_add_child
00970 //       Access: Private
00971 //  Description: Marks the node as a child of the group.  This is an
00972 //               internal function called by the STL-like functions
00973 //               push_back() and insert(), in preparation for actually
00974 //               adding the child.
00975 //
00976 //               It is an error to add a node that is already a child
00977 //               of this group or some other group.
00978 ////////////////////////////////////////////////////////////////////
00979 void EggGroupNode::
00980 prepare_add_child(EggNode *node) {
00981   nassertv(node != (EggNode *)NULL);
00982   // Make sure the node is not already a child of some other group.
00983   nassertv(node->get_parent() == NULL);
00984   nassertv(node->get_depth() == 0);
00985   node->_parent = this;
00986 
00987   node->update_under(get_depth() + 1);
00988 }
00989 
00990 
00991 ////////////////////////////////////////////////////////////////////
00992 //     Function: EggGroupNode::prepare_remove_child
00993 //       Access: Private
00994 //  Description: Marks the node as removed from the group.  This is an
00995 //               internal function called by the STL-like functions
00996 //               pop_back() and erase(), in preparation for actually
00997 //               doing the removal.
00998 //
00999 //               It is an error to attempt to remove a node that is
01000 //               not already a child of this group.
01001 ////////////////////////////////////////////////////////////////////
01002 void EggGroupNode::
01003 prepare_remove_child(EggNode *node) {
01004   nassertv(node != (EggNode *)NULL);
01005   // Make sure the node is in fact a child of this group.
01006   nassertv(node->get_parent() == this);
01007   nassertv(node->get_depth() == get_depth() + 1);
01008   node->_parent = NULL;
01009 
01010   node->update_under(-(get_depth() + 1));
01011 }
01012 
01013 
01014 
01015 ////////////////////////////////////////////////////////////////////
01016 //     Function: EggGroupNode::r_collect_vertex_normals
01017 //       Access: Private
01018 //  Description: This is part of the implementation of
01019 //               recompute_vertex_normals().  It walks the scene graph
01020 //               at this group node and below, identifying all the
01021 //               polygons and the vertices they have in common.
01022 ////////////////////////////////////////////////////////////////////
01023 void EggGroupNode::
01024 r_collect_vertex_normals(EggGroupNode::NVertexCollection &collection,
01025                          double threshold, CoordinateSystem cs) {
01026   // We can do this ci/cnext iteration through the list as we modify
01027   // it, only because we know this works with an STL list type
01028   // container.  If this were a vector or a set, this wouldn't
01029   // necessarily work.
01030 
01031   Children::iterator ci, cnext;
01032   ci = _children.begin();
01033   while (ci != _children.end()) {
01034     cnext = ci;
01035     ++cnext;
01036     EggNode *child = *ci;
01037 
01038     if (child->is_of_type(EggPolygon::get_class_type())) {
01039       EggPolygon *polygon = DCAST(EggPolygon, child);
01040       polygon->clear_normal();
01041 
01042       NVertexReference ref;
01043       ref._polygon = polygon;
01044       if (!polygon->calculate_normal(ref._normal, cs)) {
01045         // The polygon is degenerate.  Remove it.
01046 
01047         prepare_remove_child(child);
01048         _children.erase(ci);
01049 
01050       } else {
01051         // Now add each vertex from the polygon separately to our
01052         // collection.
01053         size_t num_vertices = polygon->size();
01054         for (size_t i = 0; i < num_vertices; i++) {
01055           EggVertex *vertex = polygon->get_vertex(i);
01056           ref._vertex = i;
01057           collection[vertex->get_pos3()].push_back(ref);
01058         }
01059       }
01060 
01061     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01062       EggGroupNode *group = DCAST(EggGroupNode, child);
01063 
01064       // We can't share vertices across an Instance node.  Don't
01065       // even bother trying.  Instead, just restart.
01066       if (group->is_under_instance()) {
01067         group->recompute_vertex_normals(threshold, cs);
01068       } else {
01069         group->r_collect_vertex_normals(collection, threshold, cs);
01070       }
01071     }
01072 
01073     ci = cnext;
01074   }
01075 }
01076 
01077 ////////////////////////////////////////////////////////////////////
01078 //     Function: EggGroupNode::r_collect_vertex_normals
01079 //       Access: Private
01080 //  Description: This is part of the implementation of
01081 //               recompute_vertex_normals().  It accepts a group of
01082 //               polygons and their common normals, and computes the
01083 //               same normal for all their shared vertices.
01084 ////////////////////////////////////////////////////////////////////
01085 void EggGroupNode::
01086 do_compute_vertex_normals(const NVertexGroup &group) {
01087   nassertv(!group.empty());
01088 
01089   // Determine the common normal.  This is simply the average of all
01090   // the polygon normals that share this vertex.
01091   Normald normal(0.0, 0.0, 0.0);
01092   NVertexGroup::const_iterator gi;
01093   for (gi = group.begin(); gi != group.end(); ++gi) {
01094     const NVertexReference &ref = (*gi);
01095     normal += ref._normal;
01096   }
01097 
01098   normal /= (double)group.size();
01099   normal.normalize();
01100 
01101   // Now we have the common normal; apply it to all the vertices.
01102 
01103   for (gi = group.begin(); gi != group.end(); ++gi) {
01104     const NVertexReference &ref = (*gi);
01105     EggVertex *vertex = ref._polygon->get_vertex(ref._vertex);
01106     EggVertexPool *pool = vertex->get_pool();
01107 
01108     EggVertex new_vertex(*vertex);
01109     new_vertex.set_normal(normal);
01110     EggVertex *unique = pool->create_unique_vertex(new_vertex);
01111     unique->copy_grefs_from(*vertex);
01112 
01113     ref._polygon->set_vertex(ref._vertex, unique);
01114   }
01115 }
01116 

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