Panda3D
|
00001 // Filename: eggGroupNode.cxx 00002 // Created by: drose (16Jan99) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "eggGroupNode.h" 00016 #include "eggCoordinateSystem.h" 00017 #include "eggData.h" 00018 #include "eggFilenameNode.h" 00019 #include "eggExternalReference.h" 00020 #include "eggPrimitive.h" 00021 #include "eggPolygon.h" 00022 #include "eggCompositePrimitive.h" 00023 #include "eggMesher.h" 00024 #include "eggVertexPool.h" 00025 #include "eggVertex.h" 00026 #include "eggTextureCollection.h" 00027 #include "eggMaterialCollection.h" 00028 #include "pt_EggTexture.h" 00029 #include "pt_EggMaterial.h" 00030 #include "config_egg.h" 00031 00032 #include "dSearchPath.h" 00033 #include "deg_2_rad.h" 00034 #include "dcast.h" 00035 #include "bamCacheRecord.h" 00036 00037 #include <algorithm> 00038 00039 TypeHandle EggGroupNode::_type_handle; 00040 00041 00042 //////////////////////////////////////////////////////////////////// 00043 // Function: EggGroupNode::Copy constructor 00044 // Access: Published 00045 // Description: 00046 //////////////////////////////////////////////////////////////////// 00047 EggGroupNode:: 00048 EggGroupNode(const EggGroupNode ©) : 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: Published 00058 // Description: 00059 //////////////////////////////////////////////////////////////////// 00060 EggGroupNode &EggGroupNode:: 00061 operator =(const EggGroupNode ©) { 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: Published, Virtual 00073 // Description: 00074 //////////////////////////////////////////////////////////////////// 00075 EggGroupNode:: 00076 ~EggGroupNode() { 00077 } 00078 00079 00080 //////////////////////////////////////////////////////////////////// 00081 // Function: EggGroupNode::write 00082 // Access: Published, 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 00090 // Since joints tend to reference vertex pools, which sometimes 00091 // appear later in the file, and since generally non-joints don't 00092 // reference joints, we try to maximize our chance of writing out a 00093 // one-pass readable egg file by writing joints at the end of the 00094 // list of children of a particular node. 00095 00096 for (i = begin(); i != end(); ++i) { 00097 PT(EggNode) child = (*i); 00098 if (!child->is_joint()) { 00099 child->write(out, indent_level); 00100 } 00101 } 00102 00103 for (i = begin(); i != end(); ++i) { 00104 PT(EggNode) child = (*i); 00105 if (child->is_joint()) { 00106 child->write(out, indent_level); 00107 } 00108 } 00109 } 00110 00111 //////////////////////////////////////////////////////////////////// 00112 // Function: EggGroupNode::begin 00113 // Access: Published 00114 // Description: 00115 //////////////////////////////////////////////////////////////////// 00116 EggGroupNode::iterator EggGroupNode:: 00117 begin() const { 00118 return _children.begin(); 00119 } 00120 00121 //////////////////////////////////////////////////////////////////// 00122 // Function: EggGroupNode::end 00123 // Access: Published 00124 // Description: 00125 //////////////////////////////////////////////////////////////////// 00126 EggGroupNode::iterator EggGroupNode:: 00127 end() const { 00128 return _children.end(); 00129 } 00130 00131 //////////////////////////////////////////////////////////////////// 00132 // Function: EggGroupNode::rbegin 00133 // Access: Published 00134 // Description: 00135 //////////////////////////////////////////////////////////////////// 00136 EggGroupNode::reverse_iterator EggGroupNode:: 00137 rbegin() const { 00138 return _children.rbegin(); 00139 } 00140 00141 //////////////////////////////////////////////////////////////////// 00142 // Function: EggGroupNode::rend 00143 // Access: Published 00144 // Description: 00145 //////////////////////////////////////////////////////////////////// 00146 EggGroupNode::reverse_iterator EggGroupNode:: 00147 rend() const { 00148 return _children.rend(); 00149 } 00150 00151 //////////////////////////////////////////////////////////////////// 00152 // Function: EggGroupNode::insert 00153 // Access: Published 00154 // Description: 00155 //////////////////////////////////////////////////////////////////// 00156 EggGroupNode::iterator EggGroupNode:: 00157 insert(iterator position, PT(EggNode) x) { 00158 prepare_add_child(x); 00159 return _children.insert((Children::iterator &)position, x); 00160 } 00161 00162 //////////////////////////////////////////////////////////////////// 00163 // Function: EggGroupNode::erase 00164 // Access: Published 00165 // Description: 00166 //////////////////////////////////////////////////////////////////// 00167 EggGroupNode::iterator EggGroupNode:: 00168 erase(iterator position) { 00169 prepare_remove_child(*position); 00170 return _children.erase((Children::iterator &)position); 00171 } 00172 00173 //////////////////////////////////////////////////////////////////// 00174 // Function: EggGroupNode::erase 00175 // Access: Published 00176 // Description: 00177 //////////////////////////////////////////////////////////////////// 00178 EggGroupNode::iterator EggGroupNode:: 00179 erase(iterator first, iterator last) { 00180 iterator i; 00181 for (i = first; i != last; ++i) { 00182 prepare_remove_child(*i); 00183 } 00184 return _children.erase((Children::iterator &)first, 00185 (Children::iterator &)last); 00186 } 00187 00188 //////////////////////////////////////////////////////////////////// 00189 // Function: EggGroupNode::replace 00190 // Access: Published 00191 // Description: Replaces the node at the indicated position with 00192 // the indicated node. It is an error to call this 00193 // with an invalid position iterator (e.g. end()). 00194 //////////////////////////////////////////////////////////////////// 00195 void EggGroupNode:: 00196 replace(iterator position, PT(EggNode) x) { 00197 nassertv(position != end()); 00198 00199 prepare_remove_child(*position); 00200 prepare_add_child(x); 00201 *(Children::iterator &)position = x; 00202 } 00203 00204 //////////////////////////////////////////////////////////////////// 00205 // Function: EggGroupNode::empty 00206 // Access: Published 00207 // Description: 00208 //////////////////////////////////////////////////////////////////// 00209 bool EggGroupNode:: 00210 empty() const { 00211 return _children.empty(); 00212 } 00213 00214 //////////////////////////////////////////////////////////////////// 00215 // Function: EggGroupNode::size 00216 // Access: Published 00217 // Description: 00218 //////////////////////////////////////////////////////////////////// 00219 EggGroupNode::size_type EggGroupNode:: 00220 size() const { 00221 return _children.size(); 00222 } 00223 00224 //////////////////////////////////////////////////////////////////// 00225 // Function: EggGroupNode::clear 00226 // Access: Published 00227 // Description: 00228 //////////////////////////////////////////////////////////////////// 00229 void EggGroupNode:: 00230 clear() { 00231 erase(begin(), end()); 00232 } 00233 00234 //////////////////////////////////////////////////////////////////// 00235 // Function: EggGroupNode::get_first_child 00236 // Access: Published 00237 // Description: Returns the first child in the group's list of 00238 // children, or NULL if the list of children is empty. 00239 // Can be used with get_next_child() to return the 00240 // complete list of children without using the iterator 00241 // class; however, this is non-thread-safe, and so is 00242 // not recommended except for languages other than C++ 00243 // which cannot use the iterators. 00244 //////////////////////////////////////////////////////////////////// 00245 EggNode *EggGroupNode:: 00246 get_first_child() { 00247 _gnc_iterator = begin(); 00248 return get_next_child(); 00249 } 00250 00251 //////////////////////////////////////////////////////////////////// 00252 // Function: EggGroupNode::get_next_child 00253 // Access: Published 00254 // Description: Returns the next child in the group's list of 00255 // children since the last call to get_first_child() or 00256 // get_next_child(), or NULL if the last child has been 00257 // returned. Can be used with get_first_child() to 00258 // return the complete list of children without using 00259 // the iterator class; however, this is non-thread-safe, 00260 // and so is not recommended except for languages other 00261 // than C++ which cannot use the iterators. 00262 // 00263 // It is an error to call this without previously 00264 // calling get_first_child(). 00265 //////////////////////////////////////////////////////////////////// 00266 EggNode *EggGroupNode:: 00267 get_next_child() { 00268 if (_gnc_iterator != end()) { 00269 return *_gnc_iterator++; 00270 } 00271 return NULL; 00272 } 00273 00274 //////////////////////////////////////////////////////////////////// 00275 // Function: EggGroupNode::add_child 00276 // Access: Published 00277 // Description: Adds the indicated child to the group and returns it. 00278 // If the child node is already a child of some other 00279 // node, removes it first. 00280 //////////////////////////////////////////////////////////////////// 00281 EggNode *EggGroupNode:: 00282 add_child(EggNode *node) { 00283 test_ref_count_integrity(); 00284 PT(EggNode) ptnode = node; 00285 if (node->_parent != NULL) { 00286 node->_parent->remove_child(node); 00287 } 00288 prepare_add_child(node); 00289 _children.push_back(node); 00290 return node; 00291 } 00292 00293 //////////////////////////////////////////////////////////////////// 00294 // Function: EggGroupNode::remove_child 00295 // Access: Published 00296 // Description: Removes the indicated child node from the group and 00297 // returns it. If the child was not already in the 00298 // group, does nothing and returns NULL. 00299 //////////////////////////////////////////////////////////////////// 00300 PT(EggNode) EggGroupNode:: 00301 remove_child(EggNode *node) { 00302 PT(EggNode) ptnode = node; 00303 iterator i = find(begin(), end(), ptnode); 00304 if (i == end()) { 00305 return PT(EggNode)(); 00306 } else { 00307 // erase() calls prepare_remove_child(). 00308 erase(i); 00309 return ptnode; 00310 } 00311 } 00312 00313 00314 //////////////////////////////////////////////////////////////////// 00315 // Function: EggGroupNode::steal_children 00316 // Access: Published 00317 // Description: Moves all the children from the other node to this 00318 // one. This is especially useful because the group 00319 // node copy assignment operator does not copy children. 00320 //////////////////////////////////////////////////////////////////// 00321 void EggGroupNode:: 00322 steal_children(EggGroupNode &other) { 00323 Children::iterator ci; 00324 for (ci = other._children.begin(); 00325 ci != other._children.end(); 00326 ++ci) { 00327 other.prepare_remove_child(*ci); 00328 prepare_add_child(*ci); 00329 } 00330 00331 _children.splice(_children.end(), other._children); 00332 } 00333 00334 //////////////////////////////////////////////////////////////////// 00335 // Function: EggGroupNode::find_child 00336 // Access: Published 00337 // Description: Returns the child of this node whose name is the 00338 // indicated string, or NULL if there is no child of 00339 // this node by that name. Does not search recursively. 00340 //////////////////////////////////////////////////////////////////// 00341 EggNode *EggGroupNode:: 00342 find_child(const string &name) const { 00343 Children::const_iterator ci; 00344 for (ci = _children.begin(); ci != _children.end(); ++ci) { 00345 EggNode *child = (*ci); 00346 if (child->get_name() == name) { 00347 return child; 00348 } 00349 } 00350 00351 return NULL; 00352 } 00353 00354 //////////////////////////////////////////////////////////////////// 00355 // Function: EggGroupNode::has_absolute_pathnames 00356 // Access: Published 00357 // Description: Returns true if any nodes at this level and below 00358 // include a reference to a file via an absolute 00359 // pathname, or false if all references are relative. 00360 //////////////////////////////////////////////////////////////////// 00361 bool EggGroupNode:: 00362 has_absolute_pathnames() const { 00363 Children::const_iterator ci; 00364 for (ci = _children.begin(); 00365 ci != _children.end(); 00366 ++ci) { 00367 EggNode *child = *ci; 00368 if (child->is_of_type(EggTexture::get_class_type())) { 00369 EggTexture *tex = DCAST(EggTexture, child); 00370 if (!tex->get_filename().is_local()) { 00371 if (egg_cat.is_debug()) { 00372 egg_cat.debug() 00373 << "Absolute pathname: " << tex->get_filename() 00374 << "\n"; 00375 } 00376 return true; 00377 } 00378 00379 if (tex->has_alpha_filename()) { 00380 if (!tex->get_alpha_filename().is_local()) { 00381 if (egg_cat.is_debug()) { 00382 egg_cat.debug() 00383 << "Absolute pathname: " << tex->get_alpha_filename() 00384 << "\n"; 00385 } 00386 return true; 00387 } 00388 } 00389 00390 } else if (child->is_of_type(EggFilenameNode::get_class_type())) { 00391 EggFilenameNode *fnode = DCAST(EggFilenameNode, child); 00392 if (!fnode->get_filename().is_local()) { 00393 if (egg_cat.is_debug()) { 00394 egg_cat.debug() 00395 << "Absolute pathname: " << fnode->get_filename() 00396 << "\n"; 00397 } 00398 return true; 00399 } 00400 00401 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 00402 if (DCAST(EggGroupNode, child)->has_absolute_pathnames()) { 00403 return true; 00404 } 00405 } 00406 } 00407 00408 return false; 00409 } 00410 00411 //////////////////////////////////////////////////////////////////// 00412 // Function: EggGroupNode::resolve_filenames 00413 // Access: Published 00414 // Description: Walks the tree and attempts to resolve any filenames 00415 // encountered. This looks up filenames along the 00416 // specified search path; it does not automatically 00417 // search the model_path for missing files. 00418 //////////////////////////////////////////////////////////////////// 00419 void EggGroupNode:: 00420 resolve_filenames(const DSearchPath &searchpath) { 00421 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00422 00423 Children::iterator ci; 00424 for (ci = _children.begin(); 00425 ci != _children.end(); 00426 ++ci) { 00427 EggNode *child = *ci; 00428 if (child->is_of_type(EggTexture::get_class_type())) { 00429 EggTexture *tex = DCAST(EggTexture, child); 00430 Filename tex_filename = tex->get_filename(); 00431 vfs->resolve_filename(tex_filename, searchpath); 00432 tex->set_filename(tex_filename); 00433 00434 if (tex->has_alpha_filename()) { 00435 Filename alpha_filename = tex->get_alpha_filename(); 00436 vfs->resolve_filename(alpha_filename, searchpath); 00437 tex->set_alpha_filename(alpha_filename); 00438 } 00439 00440 } else if (child->is_of_type(EggFilenameNode::get_class_type())) { 00441 EggFilenameNode *fnode = DCAST(EggFilenameNode, child); 00442 Filename filename = fnode->get_filename(); 00443 vfs->resolve_filename(filename, searchpath, fnode->get_default_extension()); 00444 fnode->set_filename(filename); 00445 00446 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 00447 DCAST(EggGroupNode, child)->resolve_filenames(searchpath); 00448 } 00449 } 00450 } 00451 00452 //////////////////////////////////////////////////////////////////// 00453 // Function: EggGroupNode::force_filenames 00454 // Access: Published 00455 // Description: Similar to resolve_filenames, but each non-absolute 00456 // filename encountered is arbitrarily taken to be in 00457 // the indicated directory, whether or not the so-named 00458 // filename exists. 00459 //////////////////////////////////////////////////////////////////// 00460 void EggGroupNode:: 00461 force_filenames(const Filename &directory) { 00462 Children::iterator ci; 00463 for (ci = _children.begin(); 00464 ci != _children.end(); 00465 ++ci) { 00466 EggNode *child = *ci; 00467 if (child->is_of_type(EggTexture::get_class_type())) { 00468 EggTexture *tex = DCAST(EggTexture, child); 00469 Filename tex_filename = tex->get_filename(); 00470 if (tex_filename.is_local()) { 00471 tex->set_filename(Filename(directory, tex_filename)); 00472 } 00473 00474 if (tex->has_alpha_filename()) { 00475 Filename alpha_filename = tex->get_alpha_filename(); 00476 if (alpha_filename.is_local()) { 00477 tex->set_alpha_filename(Filename(directory, alpha_filename)); 00478 } 00479 } 00480 00481 } else if (child->is_of_type(EggFilenameNode::get_class_type())) { 00482 EggFilenameNode *fnode = DCAST(EggFilenameNode, child); 00483 Filename filename = fnode->get_filename(); 00484 if (filename.is_local()) { 00485 fnode->set_filename(Filename(directory, filename)); 00486 } 00487 00488 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 00489 DCAST(EggGroupNode, child)->force_filenames(directory); 00490 } 00491 } 00492 } 00493 00494 //////////////////////////////////////////////////////////////////// 00495 // Function: EggGroupNode::reverse_vertex_ordering 00496 // Access: Published 00497 // Description: Reverses the vertex ordering of all polygons defined 00498 // at this node and below. Does not change the surface 00499 // normals, if any. 00500 //////////////////////////////////////////////////////////////////// 00501 void EggGroupNode:: 00502 reverse_vertex_ordering() { 00503 Children::iterator ci; 00504 for (ci = _children.begin(); 00505 ci != _children.end(); 00506 ++ci) { 00507 EggNode *child = *ci; 00508 if (child->is_of_type(EggPrimitive::get_class_type())) { 00509 EggPrimitive *prim = DCAST(EggPrimitive, child); 00510 prim->reverse_vertex_ordering(); 00511 00512 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 00513 DCAST(EggGroupNode, child)->reverse_vertex_ordering(); 00514 } 00515 } 00516 } 00517 00518 //////////////////////////////////////////////////////////////////// 00519 // Function: EggGroupNode::recompute_vertex_normals 00520 // Access: Published 00521 // Description: Recomputes all the vertex normals for polygon 00522 // geometry at this group node and below so that they 00523 // accurately reflect the vertex positions. A shared 00524 // edge between two polygons (even in different groups) 00525 // is considered smooth if the angle between the two 00526 // edges is less than threshold degrees. 00527 // 00528 // This function also removes degenerate polygons that 00529 // do not have enough vertices to define a normal. It 00530 // does not affect normals for other kinds of primitives 00531 // like Nurbs or Points. 00532 // 00533 // This function does not remove or adjust vertices in 00534 // the vertex pool; it only adds new vertices with the 00535 // correct normals. Thus, it is a good idea to call 00536 // remove_unused_vertices() after calling this. 00537 //////////////////////////////////////////////////////////////////// 00538 void EggGroupNode:: 00539 recompute_vertex_normals(double threshold, CoordinateSystem cs) { 00540 // First, collect all the vertices together with their shared 00541 // polygons. 00542 NVertexCollection collection; 00543 r_collect_vertex_normals(collection, threshold, cs); 00544 00545 // Now bust them into separate groups according to the edge 00546 // threshold. Two polygons that share a vertex belong in the same 00547 // group only if the angle between their normals is within the 00548 // threshold. 00549 00550 double cos_angle = cos(deg_2_rad(threshold)); 00551 00552 NVertexCollection::iterator ci; 00553 for (ci = collection.begin(); ci != collection.end(); ++ci) { 00554 NVertexGroup &group = (*ci).second; 00555 00556 // Here's a group of polygons that share a vertex. Build up a new 00557 // group that consists of just the first polygon and all the ones 00558 // that are within threshold degrees from it. 00559 NVertexGroup::iterator gi; 00560 gi = group.begin(); 00561 while (gi != group.end()) { 00562 const NVertexReference &base_ref = (*gi); 00563 NVertexGroup new_group; 00564 NVertexGroup leftover_group; 00565 new_group.push_back(base_ref); 00566 ++gi; 00567 00568 while (gi != group.end()) { 00569 const NVertexReference &ref = (*gi); 00570 double dot = base_ref._normal.dot(ref._normal); 00571 if (dot > cos_angle) { 00572 // These polygons are close enough to the same angle. 00573 new_group.push_back(ref); 00574 } else { 00575 // These polygons are not. 00576 leftover_group.push_back(ref); 00577 } 00578 ++gi; 00579 } 00580 00581 // Now new_group is a collection of connected polygons and the 00582 // vertices that connect them. Smooth these vertices. 00583 do_compute_vertex_normals(new_group); 00584 00585 // And reset the group of remaining polygons. 00586 group.swap(leftover_group); 00587 gi = group.begin(); 00588 } 00589 } 00590 } 00591 00592 //////////////////////////////////////////////////////////////////// 00593 // Function: EggGroupNode::recompute_polygon_normals 00594 // Access: Published 00595 // Description: Recomputes all the polygon normals for polygon 00596 // geometry at this group node and below so that they 00597 // accurately reflect the vertex positions. Normals are 00598 // removed from the vertices and defined only on 00599 // polygons, giving the geometry a faceted appearance. 00600 // 00601 // This function also removes degenerate polygons that 00602 // do not have enough vertices to define a normal. It 00603 // does not affect normals for other kinds of primitives 00604 // like Nurbs or Points. 00605 // 00606 // This function does not remove or adjust vertices in 00607 // the vertex pool; it only adds new vertices with the 00608 // normals removed. Thus, it is a good idea to call 00609 // remove_unused_vertices() after calling this. 00610 //////////////////////////////////////////////////////////////////// 00611 void EggGroupNode:: 00612 recompute_polygon_normals(CoordinateSystem cs) { 00613 Children::iterator ci, cnext; 00614 ci = _children.begin(); 00615 while (ci != _children.end()) { 00616 cnext = ci; 00617 ++cnext; 00618 EggNode *child = *ci; 00619 00620 if (child->is_of_type(EggPolygon::get_class_type())) { 00621 EggPolygon *polygon = DCAST(EggPolygon, child); 00622 00623 if (!polygon->recompute_polygon_normal(cs)) { 00624 // The polygon is degenerate. Remove it. 00625 prepare_remove_child(child); 00626 _children.erase(ci); 00627 00628 } else { 00629 // Remove the normal from each polygon vertex. 00630 size_t num_vertices = polygon->size(); 00631 for (size_t i = 0; i < num_vertices; i++) { 00632 EggVertex *vertex = polygon->get_vertex(i); 00633 EggVertexPool *pool = vertex->get_pool(); 00634 00635 if (vertex->has_normal()) { 00636 EggVertex new_vertex(*vertex); 00637 new_vertex.clear_normal(); 00638 EggVertex *unique = pool->create_unique_vertex(new_vertex); 00639 unique->copy_grefs_from(*vertex); 00640 00641 polygon->set_vertex(i, unique); 00642 } 00643 } 00644 } 00645 00646 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 00647 DCAST(EggGroupNode, child)->recompute_polygon_normals(cs); 00648 } 00649 00650 ci = cnext; 00651 } 00652 } 00653 00654 //////////////////////////////////////////////////////////////////// 00655 // Function: EggGroupNode::strip_normals 00656 // Access: Published 00657 // Description: Removes all normals from primitives, and the vertices 00658 // they reference, at this node and below. 00659 // 00660 // This function does not remove or adjust vertices in 00661 // the vertex pool; it only adds new vertices with the 00662 // normal removed. Thus, it is a good idea to call 00663 // remove_unused_vertices() after calling this. 00664 //////////////////////////////////////////////////////////////////// 00665 void EggGroupNode:: 00666 strip_normals() { 00667 Children::iterator ci; 00668 for (ci = _children.begin(); ci != _children.end(); ++ci) { 00669 EggNode *child = *ci; 00670 00671 if (child->is_of_type(EggPrimitive::get_class_type())) { 00672 EggPrimitive *prim = DCAST(EggPrimitive, child); 00673 prim->clear_normal(); 00674 00675 // Remove the normal from each prim vertex. 00676 size_t num_vertices = prim->size(); 00677 for (size_t i = 0; i < num_vertices; i++) { 00678 EggVertex *vertex = prim->get_vertex(i); 00679 EggVertexPool *pool = vertex->get_pool(); 00680 00681 if (vertex->has_normal()) { 00682 EggVertex new_vertex(*vertex); 00683 new_vertex.clear_normal(); 00684 EggVertex *unique = pool->create_unique_vertex(new_vertex); 00685 unique->copy_grefs_from(*vertex); 00686 00687 prim->set_vertex(i, unique); 00688 } 00689 } 00690 00691 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 00692 DCAST(EggGroupNode, child)->strip_normals(); 00693 } 00694 } 00695 } 00696 00697 //////////////////////////////////////////////////////////////////// 00698 // Function: EggGroupNode::recompute_tangent_binormal 00699 // Access: Published 00700 // Description: This function recomputes the tangent and binormal for 00701 // the named texture coordinate set for all vertices at 00702 // this level and below. Use the empty string for the 00703 // default texture coordinate set. 00704 // 00705 // It is necessary for each vertex to already have a 00706 // normal (or at least a polygon normal), as well as a 00707 // texture coordinate in the named texture coordinate 00708 // set, before calling this function. You might precede 00709 // this with recompute_vertex_normals() to ensure that 00710 // the normals exist. 00711 // 00712 // Like recompute_vertex_normals(), this function does 00713 // not remove or adjust vertices in the vertex pool; it 00714 // only adds new vertices with the new tangents and 00715 // binormals computed. Thus, it is a good idea to call 00716 // remove_unused_vertices() after calling this. 00717 //////////////////////////////////////////////////////////////////// 00718 bool EggGroupNode:: 00719 recompute_tangent_binormal(const GlobPattern &uv_name) { 00720 // First, collect all the vertices together with their shared 00721 // polygons. 00722 TBNVertexCollection collection; 00723 r_collect_tangent_binormal(uv_name, collection); 00724 00725 // Now compute the tangent and binormal separately for each common 00726 // group of vertices. 00727 TBNVertexCollection::const_iterator ci; 00728 for (ci = collection.begin(); ci != collection.end(); ++ci) { 00729 const TBNVertexValue &value = (*ci).first; 00730 const TBNVertexGroup &group = (*ci).second; 00731 00732 do_compute_tangent_binormal(value, group); 00733 } 00734 00735 return true; 00736 } 00737 00738 //////////////////////////////////////////////////////////////////// 00739 // Function: EggGroupNode::recompute_tangent_binormal 00740 // Access: Published 00741 // Description: This function recomputes the tangent and binormal for 00742 // the named texture coordinate sets. 00743 // Returns true if anything was done. 00744 //////////////////////////////////////////////////////////////////// 00745 bool EggGroupNode:: 00746 recompute_tangent_binormal(const vector_string &names) { 00747 bool changed = false; 00748 00749 for (vector_string::const_iterator si = names.begin(); 00750 si != names.end(); 00751 ++si) { 00752 GlobPattern uv_name(*si); 00753 nout << "Computing tangent and binormal for \"" << uv_name << "\"\n"; 00754 recompute_tangent_binormal(uv_name); 00755 changed = true; 00756 } 00757 00758 return changed; 00759 } 00760 00761 //////////////////////////////////////////////////////////////////// 00762 // Function: EggGroupNode::recompute_tangent_binormal_auto 00763 // Access: Published 00764 // Description: This function recomputes the tangent and binormal for 00765 // any texture coordinate set that affects a normal map. 00766 // Returns true if anything was done. 00767 //////////////////////////////////////////////////////////////////// 00768 bool EggGroupNode:: 00769 recompute_tangent_binormal_auto() { 00770 vector_string names; 00771 EggTextureCollection texs; 00772 EggTextureCollection::iterator eti; 00773 texs.find_used_textures(this); 00774 for (eti = texs.begin(); eti != texs.end(); eti++) { 00775 EggTexture *eggtex = (*eti); 00776 if ((eggtex->get_env_type() == EggTexture::ET_normal)|| 00777 (eggtex->get_env_type() == EggTexture::ET_normal_height)) { 00778 string uv = eggtex->get_uv_name(); 00779 vector_string::iterator it = find(names.begin(), names.end(), uv); 00780 if (it == names.end()) { 00781 names.push_back(uv); 00782 } 00783 } 00784 } 00785 return recompute_tangent_binormal(names); 00786 } 00787 00788 //////////////////////////////////////////////////////////////////// 00789 // Function: EggGroupNode::triangulate_polygons 00790 // Access: Published 00791 // Description: Replace all higher-order polygons at this point in 00792 // the scene graph and below with triangles. Returns 00793 // the total number of new triangles produced, less 00794 // degenerate polygons removed. 00795 // 00796 // If flags contains T_polygon and T_convex, both 00797 // concave and convex polygons will be subdivided into 00798 // triangles; with only T_polygon, only concave polygons 00799 // will be subdivided, and convex polygons will be 00800 // largely unchanged. 00801 //////////////////////////////////////////////////////////////////// 00802 int EggGroupNode:: 00803 triangulate_polygons(int flags) { 00804 int num_produced = 0; 00805 00806 Children children_copy = _children; 00807 00808 Children::iterator ci; 00809 for (ci = children_copy.begin(); 00810 ci != children_copy.end(); 00811 ++ci) { 00812 EggNode *child = (*ci); 00813 00814 if (child->is_of_type(EggPolygon::get_class_type())) { 00815 if ((flags & T_polygon) != 0) { 00816 EggPolygon *poly = DCAST(EggPolygon, child); 00817 poly->triangulate_in_place((flags & T_convex) != 0); 00818 } 00819 00820 } else if (child->is_of_type(EggCompositePrimitive::get_class_type())) { 00821 if ((flags & T_composite) != 0) { 00822 EggCompositePrimitive *comp = DCAST(EggCompositePrimitive, child); 00823 comp->triangulate_in_place(); 00824 } 00825 00826 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 00827 if ((flags & T_recurse) != 0) { 00828 num_produced += DCAST(EggGroupNode, child)->triangulate_polygons(flags); 00829 } 00830 } 00831 } 00832 00833 num_produced += max(0, (int)(_children.size() - children_copy.size())); 00834 return num_produced; 00835 } 00836 00837 //////////////////////////////////////////////////////////////////// 00838 // Function: EggGroupNode::mesh_triangles 00839 // Access: Published 00840 // Description: Combine triangles together into triangle strips, at 00841 // this group and below. 00842 //////////////////////////////////////////////////////////////////// 00843 void EggGroupNode:: 00844 mesh_triangles(int flags) { 00845 EggMesher mesher; 00846 mesher.mesh(this, (flags & T_flat_shaded) != 0); 00847 00848 if ((flags & T_recurse) != 0) { 00849 EggGroupNode::iterator ci; 00850 for (ci = begin(); ci != end(); ++ci) { 00851 if ((*ci)->is_of_type(EggGroupNode::get_class_type())) { 00852 EggGroupNode *group_child = DCAST(EggGroupNode, *ci); 00853 group_child->mesh_triangles(flags); 00854 } 00855 } 00856 } 00857 } 00858 00859 //////////////////////////////////////////////////////////////////// 00860 // Function: EggGroupNode::rename_nodes 00861 // Access: Published 00862 // Description: Rename by stripping out the prefix 00863 //////////////////////////////////////////////////////////////////// 00864 int EggGroupNode:: 00865 rename_nodes(vector_string strip_prefix, bool recurse) { 00866 int num_renamed = 0; 00867 for (unsigned int ni = 0; ni < strip_prefix.size(); ++ni) { 00868 string axe_name = strip_prefix[ni]; 00869 if (this->get_name().substr(0, axe_name.size()) == axe_name) { 00870 string new_name = this->get_name().substr(axe_name.size()); 00871 //cout << "renaming " << this->get_name() << "->" << new_name << endl; 00872 this->set_name(new_name); 00873 num_renamed += 1; 00874 } 00875 } 00876 if (recurse) { 00877 EggGroupNode::iterator ci; 00878 for (ci = begin(); ci != end(); ++ci) { 00879 if ((*ci)->is_of_type(EggGroupNode::get_class_type())) { 00880 EggGroupNode *group_child = DCAST(EggGroupNode, *ci); 00881 num_renamed += group_child->rename_nodes(strip_prefix, recurse); 00882 } 00883 else if ((*ci)->is_of_type(EggNode::get_class_type())) { 00884 EggNode *node_child = DCAST(EggNode, *ci); 00885 num_renamed += node_child->rename_node(strip_prefix); 00886 } 00887 } 00888 } 00889 return num_renamed; 00890 } 00891 00892 //////////////////////////////////////////////////////////////////// 00893 // Function: EggGroupNode::remove_unused_vertices 00894 // Access: Published 00895 // Description: Removes all vertices from VertexPools within this 00896 // group or below that are not referenced by at least 00897 // one primitive. Also collapses together equivalent 00898 // vertices, and renumbers all vertices after the 00899 // operation so their indices are consecutive, beginning 00900 // at zero. Returns the total number of vertices 00901 // removed. 00902 // 00903 // Note that this operates on the VertexPools within 00904 // this group level, without respect to primitives that 00905 // reference these vertices (unlike other functions like 00906 // strip_normals()). It is therefore most useful to 00907 // call this on the EggData root, rather than on a 00908 // subgroup within the hierarchy, since a VertexPool may 00909 // appear anywhere in the hierarchy. 00910 //////////////////////////////////////////////////////////////////// 00911 int EggGroupNode:: 00912 remove_unused_vertices(bool recurse) { 00913 int num_removed = 0; 00914 00915 Children::iterator ci, cnext; 00916 ci = _children.begin(); 00917 while (ci != _children.end()) { 00918 cnext = ci; 00919 ++cnext; 00920 EggNode *child = *ci; 00921 00922 if (child->is_of_type(EggVertexPool::get_class_type())) { 00923 EggVertexPool *vpool = DCAST(EggVertexPool, child); 00924 num_removed += vpool->remove_unused_vertices(); 00925 00926 if (vpool->empty()) { 00927 // If, after removing all the vertices, there's nothing left 00928 // in the vertex pool, then remove the whole vertex pool. 00929 _children.erase(ci); 00930 } 00931 00932 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 00933 if (recurse) { 00934 num_removed += DCAST(EggGroupNode, child)->remove_unused_vertices(recurse); 00935 } 00936 } 00937 00938 ci = cnext; 00939 } 00940 00941 return num_removed; 00942 } 00943 00944 //////////////////////////////////////////////////////////////////// 00945 // Function: EggGroupNode::remove_invalid_primitives 00946 // Access: Published 00947 // Description: Removes primitives at this level and below which 00948 // appear to be degenerate; e.g. polygons with fewer 00949 // than 3 vertices, etc. Returns the number of 00950 // primitives removed. 00951 //////////////////////////////////////////////////////////////////// 00952 int EggGroupNode:: 00953 remove_invalid_primitives(bool recurse) { 00954 int num_removed = 0; 00955 00956 Children::iterator ci, cnext; 00957 ci = _children.begin(); 00958 while (ci != _children.end()) { 00959 cnext = ci; 00960 ++cnext; 00961 EggNode *child = *ci; 00962 00963 if (child->is_of_type(EggPrimitive::get_class_type())) { 00964 EggPrimitive *prim = DCAST(EggPrimitive, child); 00965 if (!prim->cleanup()) { 00966 _children.erase(ci); 00967 num_removed++; 00968 } 00969 00970 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 00971 if (recurse) { 00972 num_removed += DCAST(EggGroupNode, child)->remove_invalid_primitives(recurse); 00973 } 00974 } 00975 00976 ci = cnext; 00977 } 00978 00979 return num_removed; 00980 } 00981 00982 //////////////////////////////////////////////////////////////////// 00983 // Function: EggGroupNode::clear_connected_shading 00984 // Access: Published 00985 // Description: Resets the connected_shading information on all 00986 // primitives at this node and below, so that it may be 00987 // accurately rederived by the next call to 00988 // get_connected_shading(). 00989 // 00990 // It may be a good idea to call 00991 // remove_unused_vertices() as well, to establish the 00992 // correct connectivity between common vertices. 00993 //////////////////////////////////////////////////////////////////// 00994 void EggGroupNode:: 00995 clear_connected_shading() { 00996 Children::iterator ci; 00997 for (ci = _children.begin(); ci != _children.end(); ++ci) { 00998 EggNode *child = *ci; 00999 01000 if (child->is_of_type(EggPrimitive::get_class_type())) { 01001 EggPrimitive *prim = DCAST(EggPrimitive, child); 01002 prim->clear_connected_shading(); 01003 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01004 DCAST(EggGroupNode, child)->clear_connected_shading(); 01005 } 01006 } 01007 } 01008 01009 //////////////////////////////////////////////////////////////////// 01010 // Function: EggGroupNode::get_connected_shading 01011 // Access: Published 01012 // Description: Queries the connected_shading information on all 01013 // primitives at this node and below, to ensure that it 01014 // has been completely filled in before we start mucking 01015 // around with vertices. 01016 //////////////////////////////////////////////////////////////////// 01017 void EggGroupNode:: 01018 get_connected_shading() { 01019 Children::iterator ci; 01020 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01021 EggNode *child = *ci; 01022 01023 if (child->is_of_type(EggPrimitive::get_class_type())) { 01024 EggPrimitive *prim = DCAST(EggPrimitive, child); 01025 prim->get_connected_shading(); 01026 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01027 DCAST(EggGroupNode, child)->get_connected_shading(); 01028 } 01029 } 01030 } 01031 01032 //////////////////////////////////////////////////////////////////// 01033 // Function: EggGroupNode::unify_attributes 01034 // Access: Published 01035 // Description: Applies per-vertex normal and color to all vertices, 01036 // if they are in fact per-vertex (and different for 01037 // each vertex), or moves them to the primitive if they 01038 // are all the same. 01039 // 01040 // After this call, either the primitive will have 01041 // normals or its vertices will, but not both. Ditto 01042 // for colors. 01043 // 01044 // If use_connected_shading is true, each polygon is 01045 // considered in conjunction with all connected 01046 // polygons; otherwise, each polygon is considered 01047 // individually. 01048 // 01049 // If allow_per_primitive is false, S_per_face or 01050 // S_overall will treated like S_per_vertex: normals and 01051 // colors will always be assigned to the vertices. In 01052 // this case, there will never be per-primitive colors 01053 // or normals after this call returns. On the other 01054 // hand, if allow_per_primitive is true, then S_per_face 01055 // means that normals and colors should be assigned to 01056 // the primitives, and removed from the vertices, as 01057 // described above. 01058 // 01059 // This may create redundant vertices in the vertex 01060 // pool, so it may be a good idea to follow this up with 01061 // remove_unused_vertices(). 01062 //////////////////////////////////////////////////////////////////// 01063 void EggGroupNode:: 01064 unify_attributes(bool use_connected_shading, bool allow_per_primitive, 01065 bool recurse) { 01066 Children::iterator ci; 01067 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01068 EggNode *child = *ci; 01069 01070 if (child->is_of_type(EggPrimitive::get_class_type())) { 01071 EggPrimitive *prim = DCAST(EggPrimitive, child); 01072 01073 EggPrimitive::Shading shading = EggPrimitive::S_per_vertex; 01074 01075 if (allow_per_primitive) { 01076 shading = prim->get_shading(); 01077 if (use_connected_shading) { 01078 shading = prim->get_connected_shading(); 01079 } 01080 } 01081 01082 prim->unify_attributes(shading); 01083 01084 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01085 if (recurse) { 01086 DCAST(EggGroupNode, child)->unify_attributes 01087 (use_connected_shading, allow_per_primitive, recurse); 01088 } 01089 } 01090 } 01091 } 01092 01093 //////////////////////////////////////////////////////////////////// 01094 // Function: EggGroupNode::apply_last_attribute 01095 // Access: Published 01096 // Description: Sets the last vertex of the triangle (or each 01097 // component) to the primitive normal and/or color, if 01098 // the primitive is flat-shaded. This reflects the 01099 // OpenGL convention of storing flat-shaded properties on 01100 // the last vertex, although it is not usually a 01101 // convention in Egg. 01102 // 01103 // This may create redundant vertices in the vertex 01104 // pool, so it may be a good idea to follow this up with 01105 // remove_unused_vertices(). 01106 //////////////////////////////////////////////////////////////////// 01107 void EggGroupNode:: 01108 apply_last_attribute(bool recurse) { 01109 Children::iterator ci; 01110 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01111 EggNode *child = *ci; 01112 01113 if (child->is_of_type(EggPrimitive::get_class_type())) { 01114 EggPrimitive *prim = DCAST(EggPrimitive, child); 01115 prim->apply_last_attribute(); 01116 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01117 if (recurse) { 01118 DCAST(EggGroupNode, child)->apply_last_attribute(recurse); 01119 } 01120 } 01121 } 01122 } 01123 01124 //////////////////////////////////////////////////////////////////// 01125 // Function: EggGroupNode::apply_first_attribute 01126 // Access: Published 01127 // Description: Sets the first vertex of the triangle (or each 01128 // component) to the primitive normal and/or color, if 01129 // the primitive is flat-shaded. This reflects the 01130 // DirectX convention of storing flat-shaded properties on 01131 // the first vertex, although it is not usually a 01132 // convention in Egg. 01133 // 01134 // This may create redundant vertices in the vertex 01135 // pool, so it may be a good idea to follow this up with 01136 // remove_unused_vertices(). 01137 //////////////////////////////////////////////////////////////////// 01138 void EggGroupNode:: 01139 apply_first_attribute(bool recurse) { 01140 Children::iterator ci; 01141 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01142 EggNode *child = *ci; 01143 01144 if (child->is_of_type(EggPrimitive::get_class_type())) { 01145 EggPrimitive *prim = DCAST(EggPrimitive, child); 01146 prim->apply_first_attribute(); 01147 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01148 if (recurse) { 01149 DCAST(EggGroupNode, child)->apply_first_attribute(recurse); 01150 } 01151 } 01152 } 01153 } 01154 01155 //////////////////////////////////////////////////////////////////// 01156 // Function: EggGroupNode::post_apply_flat_attribute 01157 // Access: Published 01158 // Description: Intended as a followup to apply_last_attribute(), 01159 // this also sets an attribute on the first vertices of 01160 // the primitive, if they don't already have an 01161 // attribute set, just so they end up with *something*. 01162 //////////////////////////////////////////////////////////////////// 01163 void EggGroupNode:: 01164 post_apply_flat_attribute(bool recurse) { 01165 Children::iterator ci; 01166 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01167 EggNode *child = *ci; 01168 01169 if (child->is_of_type(EggPrimitive::get_class_type())) { 01170 EggPrimitive *prim = DCAST(EggPrimitive, child); 01171 prim->post_apply_flat_attribute(); 01172 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01173 if (recurse) { 01174 DCAST(EggGroupNode, child)->post_apply_flat_attribute(recurse); 01175 } 01176 } 01177 } 01178 } 01179 01180 //////////////////////////////////////////////////////////////////// 01181 // Function: EggGroupNode::has_primitives 01182 // Access: Published, Virtual 01183 // Description: Returns true if there are any primitives 01184 // (e.g. polygons) defined within this group or below, 01185 // false otherwise. 01186 //////////////////////////////////////////////////////////////////// 01187 bool EggGroupNode:: 01188 has_primitives() const { 01189 Children::const_iterator ci; 01190 for (ci = _children.begin(); 01191 ci != _children.end(); 01192 ++ci) { 01193 if ((*ci)->has_primitives()) { 01194 return true; 01195 } 01196 } 01197 01198 return false; 01199 } 01200 01201 //////////////////////////////////////////////////////////////////// 01202 // Function: EggGroupNode::joint_has_primitives 01203 // Access: Published, Virtual 01204 // Description: Returns true if there are any primitives 01205 // (e.g. polygons) defined within this group or below, 01206 // but the search does not include nested joints. 01207 //////////////////////////////////////////////////////////////////// 01208 bool EggGroupNode:: 01209 joint_has_primitives() const { 01210 Children::const_iterator ci; 01211 for (ci = _children.begin(); 01212 ci != _children.end(); 01213 ++ci) { 01214 EggNode *child = (*ci); 01215 01216 if (!child->is_joint()) { 01217 if (child->joint_has_primitives()) { 01218 return true; 01219 } 01220 } 01221 } 01222 01223 return false; 01224 } 01225 01226 //////////////////////////////////////////////////////////////////// 01227 // Function: EggGroupNode::has_normals 01228 // Access: Published, Virtual 01229 // Description: Returns true if any of the primitives (e.g. polygons) 01230 // defined within this group or below have either face 01231 // or vertex normals defined, false otherwise. 01232 //////////////////////////////////////////////////////////////////// 01233 bool EggGroupNode:: 01234 has_normals() const { 01235 Children::const_iterator ci; 01236 for (ci = _children.begin(); 01237 ci != _children.end(); 01238 ++ci) { 01239 if ((*ci)->has_normals()) { 01240 return true; 01241 } 01242 } 01243 01244 return false; 01245 } 01246 01247 //////////////////////////////////////////////////////////////////// 01248 // Function: EggGroupNode::rebuild_vertex_pools 01249 // Access: Published 01250 // Description: Copies vertices used by the primitives at this group 01251 // node (and below, if recurse is true) into one or more 01252 // new vertex pools, and updates the primitives to 01253 // reference these pools. It is up to the caller to 01254 // parent the newly-created vertex pools somewhere 01255 // appropriate in the egg hierarchy. 01256 // 01257 // No more than max_vertices will be placed into any one 01258 // vertex pool. This is the sole criteria for splitting 01259 // vertex pools. 01260 //////////////////////////////////////////////////////////////////// 01261 void EggGroupNode:: 01262 rebuild_vertex_pools(EggVertexPools &vertex_pools, unsigned int max_vertices, 01263 bool recurse) { 01264 Children::iterator ci; 01265 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01266 EggNode *child = *ci; 01267 01268 if (child->is_of_type(EggPrimitive::get_class_type())) { 01269 typedef pvector< PT(EggVertex) > Vertices; 01270 Vertices vertices; 01271 EggPrimitive *prim = DCAST(EggPrimitive, child); 01272 01273 // Copy all of the vertices out. 01274 EggPrimitive::const_iterator pi; 01275 for (pi = prim->begin(); pi != prim->end(); ++pi) { 01276 vertices.push_back(*pi); 01277 } 01278 01279 typedef pvector<EggAttributes> Attributes; 01280 Attributes attributes; 01281 01282 if (prim->is_of_type(EggCompositePrimitive::get_class_type())) { 01283 // A compositive primitive has the additional complication of 01284 // dealing with its attributes. 01285 EggCompositePrimitive *cprim = DCAST(EggCompositePrimitive, prim); 01286 int i; 01287 int num_components = cprim->get_num_components(); 01288 for (i = 0; i < num_components; i++) { 01289 attributes.push_back(*cprim->get_component(i)); 01290 } 01291 } 01292 01293 prim->clear(); 01294 01295 // Now look for a new home for the vertices. First, see if any 01296 // of the vertex pools we've already created already have a copy 01297 // of each one of the vertices. 01298 bool found_pool = false; 01299 EggVertexPool *best_pool = NULL; 01300 int best_new_vertices = 0; 01301 01302 Vertices new_vertices; 01303 EggVertexPools::iterator vpi; 01304 for (vpi = vertex_pools.begin(); 01305 vpi != vertex_pools.end() && !found_pool; 01306 ++vpi) { 01307 EggVertexPool *vertex_pool = (*vpi); 01308 int num_new_vertices = 0; 01309 01310 new_vertices.clear(); 01311 new_vertices.reserve(vertices.size()); 01312 01313 Vertices::const_iterator vi; 01314 for (vi = vertices.begin(); 01315 vi != vertices.end() && !found_pool; 01316 ++vi) { 01317 EggVertex *vertex = (*vi); 01318 EggVertex *new_vertex = vertex_pool->find_matching_vertex(*vertex); 01319 new_vertices.push_back(new_vertex); 01320 if (new_vertex == (EggVertex *)NULL) { 01321 ++num_new_vertices; 01322 } 01323 } 01324 01325 if (num_new_vertices == 0) { 01326 // Great, we found a vertex pool that already shares all 01327 // these vertices. No need to look any further. 01328 found_pool = true; 01329 01330 } else if (vertex_pool->size() + num_new_vertices <= max_vertices) { 01331 // We would have to add some vertices to this pool, so this 01332 // vertex pool qualifies only if the number of vertices we 01333 // have to add would still keep it within our limit. 01334 if (best_pool == (EggVertexPool *)NULL || 01335 num_new_vertices < best_new_vertices) { 01336 // This is currently our most favorable vertex pool. 01337 best_pool = vertex_pool; 01338 best_new_vertices = num_new_vertices; 01339 } 01340 } 01341 } 01342 01343 if (!found_pool) { 01344 if (best_pool == (EggVertexPool *)NULL) { 01345 // There was no vertex pool that qualified. We will have to 01346 // create a new vertex pool. 01347 best_pool = new EggVertexPool(""); 01348 vertex_pools.push_back(best_pool); 01349 } 01350 01351 new_vertices.clear(); 01352 new_vertices.reserve(vertices.size()); 01353 01354 Vertices::const_iterator vi; 01355 for (vi = vertices.begin(); vi != vertices.end(); ++vi) { 01356 EggVertex *vertex = (*vi); 01357 EggVertex *new_vertex = best_pool->create_unique_vertex(*vertex); 01358 new_vertex->copy_grefs_from(*vertex); 01359 new_vertices.push_back(new_vertex); 01360 } 01361 } 01362 01363 Vertices::const_iterator vi; 01364 nassertv(new_vertices.size() == vertices.size()); 01365 for (vi = new_vertices.begin(); vi != new_vertices.end(); ++vi) { 01366 EggVertex *new_vertex = (*vi); 01367 nassertv(new_vertex != (EggVertex *)NULL); 01368 prim->add_vertex(new_vertex); 01369 } 01370 01371 if (prim->is_of_type(EggCompositePrimitive::get_class_type())) { 01372 // Now restore the composite attributes. 01373 EggCompositePrimitive *cprim = DCAST(EggCompositePrimitive, prim); 01374 int i; 01375 int num_components = cprim->get_num_components(); 01376 nassertv(num_components == (int)attributes.size()); 01377 for (i = 0; i < num_components; i++) { 01378 cprim->set_component(i, &attributes[i]); 01379 } 01380 } 01381 01382 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01383 if (recurse) { 01384 DCAST(EggGroupNode, child)->rebuild_vertex_pools(vertex_pools, max_vertices, recurse); 01385 } 01386 } 01387 } 01388 } 01389 01390 //////////////////////////////////////////////////////////////////// 01391 // Function: EggGroupNode::update_under 01392 // Access: Protected, Virtual 01393 // Description: This function is called from within EggGroupNode 01394 // whenever the parentage of the node has changed. It 01395 // should update the depth and under_instance flags 01396 // accordingly. 01397 // 01398 // Offset is the difference between the old depth value 01399 // and the new value. It should be consistent with the 01400 // supplied depth value. If it is not, we have some 01401 // error. 01402 //////////////////////////////////////////////////////////////////// 01403 void EggGroupNode:: 01404 update_under(int depth_offset) { 01405 EggNode::update_under(depth_offset); 01406 01407 Children::iterator ci; 01408 for (ci = _children.begin(); 01409 ci != _children.end(); 01410 ++ci) { 01411 nassertv((*ci)->get_parent() == this); 01412 (*ci)->update_under(depth_offset); 01413 } 01414 } 01415 01416 //////////////////////////////////////////////////////////////////// 01417 // Function: EggGroupNode::r_transform 01418 // Access: Protected, Virtual 01419 // Description: This is called from within the egg code by 01420 // transform(). It applies a transformation matrix 01421 // to the current node in some sensible way, then 01422 // continues down the tree. 01423 // 01424 // The first matrix is the transformation to apply; the 01425 // second is its inverse. The third parameter is the 01426 // coordinate system we are changing to, or CS_default 01427 // if we are not changing coordinate systems. 01428 //////////////////////////////////////////////////////////////////// 01429 void EggGroupNode:: 01430 r_transform(const LMatrix4d &mat, const LMatrix4d &inv, 01431 CoordinateSystem to_cs) { 01432 Children::iterator ci; 01433 for (ci = _children.begin(); 01434 ci != _children.end(); 01435 ++ci) { 01436 (*ci)->r_transform(mat, inv, to_cs); 01437 } 01438 } 01439 01440 //////////////////////////////////////////////////////////////////// 01441 // Function: EggGroupNode::r_transform_vertices 01442 // Access: Protected, Virtual 01443 // Description: This is called from within the egg code by 01444 // transform_vertices_only()(). It applies a 01445 // transformation matrix to the current node in some 01446 // sensible way (if the current node is a vertex pool 01447 // with vertices), then continues down the tree. 01448 //////////////////////////////////////////////////////////////////// 01449 void EggGroupNode:: 01450 r_transform_vertices(const LMatrix4d &mat) { 01451 Children::iterator ci; 01452 for (ci = _children.begin(); 01453 ci != _children.end(); 01454 ++ci) { 01455 (*ci)->r_transform_vertices(mat); 01456 } 01457 } 01458 01459 //////////////////////////////////////////////////////////////////// 01460 // Function: EggGroupNode::r_mark_coordsys 01461 // Access: Protected, Virtual 01462 // Description: This is only called immediately after loading an egg 01463 // file from disk, to propagate the value found in the 01464 // CoordinateSystem entry (or the default Y-up 01465 // coordinate system) to all nodes that care about what 01466 // the coordinate system is. 01467 //////////////////////////////////////////////////////////////////// 01468 void EggGroupNode:: 01469 r_mark_coordsys(CoordinateSystem cs) { 01470 Children::iterator ci; 01471 for (ci = _children.begin(); 01472 ci != _children.end(); 01473 ++ci) { 01474 (*ci)->r_mark_coordsys(cs); 01475 } 01476 } 01477 01478 //////////////////////////////////////////////////////////////////// 01479 // Function: EggGroupNode::r_flatten_transforms 01480 // Access: Protected, Virtual 01481 // Description: The recursive implementation of flatten_transforms(). 01482 //////////////////////////////////////////////////////////////////// 01483 void EggGroupNode:: 01484 r_flatten_transforms() { 01485 Children::iterator ci; 01486 for (ci = _children.begin(); 01487 ci != _children.end(); 01488 ++ci) { 01489 (*ci)->r_flatten_transforms(); 01490 } 01491 } 01492 01493 //////////////////////////////////////////////////////////////////// 01494 // Function: EggGroupNode::r_apply_texmats 01495 // Access: Protected, Virtual 01496 // Description: The recursive implementation of apply_texmats(). 01497 //////////////////////////////////////////////////////////////////// 01498 void EggGroupNode:: 01499 r_apply_texmats(EggTextureCollection &textures) { 01500 Children::iterator ci; 01501 for (ci = _children.begin(); 01502 ci != _children.end(); 01503 ++ci) { 01504 (*ci)->r_apply_texmats(textures); 01505 } 01506 } 01507 01508 //////////////////////////////////////////////////////////////////// 01509 // Function: EggGroupNode::find_coordsys_entry() 01510 // Access: Protected 01511 // Description: Walks the tree, looking for an EggCoordinateSystem 01512 // entry. If one is found, extracts it and returns its 01513 // value. If multiple entries are found, extracts all 01514 // of them and returns CS_invalid if they disagree. 01515 //////////////////////////////////////////////////////////////////// 01516 CoordinateSystem EggGroupNode:: 01517 find_coordsys_entry() { 01518 CoordinateSystem coordsys = CS_default; 01519 01520 // We can do this ci/cnext iteration through the list as we modify 01521 // it, only because we know this works with an STL list type 01522 // container. If this were a vector or a set, this wouldn't 01523 // necessarily work. 01524 01525 Children::iterator ci, cnext; 01526 ci = _children.begin(); 01527 while (ci != _children.end()) { 01528 cnext = ci; 01529 ++cnext; 01530 EggNode *child = *ci; 01531 01532 if (child->is_of_type(EggCoordinateSystem::get_class_type())) { 01533 CoordinateSystem new_cs = 01534 DCAST(EggCoordinateSystem, child)->get_value(); 01535 01536 // Now remove the CoordinateSystem entry from our child list. 01537 prepare_remove_child(child); 01538 _children.erase(ci); 01539 01540 if (new_cs != CS_default) { 01541 if (coordsys != CS_default && coordsys != new_cs) { 01542 coordsys = CS_invalid; 01543 } else { 01544 coordsys = new_cs; 01545 } 01546 } 01547 01548 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01549 CoordinateSystem new_cs = 01550 DCAST(EggGroupNode, child)->find_coordsys_entry(); 01551 if (new_cs != CS_default) { 01552 if (coordsys != CS_default && coordsys != new_cs) { 01553 coordsys = CS_invalid; 01554 } else { 01555 coordsys = new_cs; 01556 } 01557 } 01558 } 01559 01560 ci = cnext; 01561 } 01562 01563 return coordsys; 01564 } 01565 01566 //////////////////////////////////////////////////////////////////// 01567 // Function: EggGroupNode::find_textures() 01568 // Access: Protected 01569 // Description: Walks the tree, looking for EggTextures. Each 01570 // EggTexture that is found is removed from the 01571 // hierarchy and added to the EggTextureCollection. 01572 // Returns the number of EggTextures found. 01573 //////////////////////////////////////////////////////////////////// 01574 int EggGroupNode:: 01575 find_textures(EggTextureCollection *collection) { 01576 int num_found = 0; 01577 01578 // We can do this ci/cnext iteration through the list as we modify 01579 // it, only because we know this works with an STL list type 01580 // container. If this were a vector or a set, this wouldn't 01581 // necessarily work. 01582 01583 Children::iterator ci, cnext; 01584 ci = _children.begin(); 01585 while (ci != _children.end()) { 01586 cnext = ci; 01587 ++cnext; 01588 EggNode *child = *ci; 01589 01590 if (child->is_of_type(EggTexture::get_class_type())) { 01591 PT_EggTexture tex = DCAST(EggTexture, child); 01592 01593 // Now remove the EggTexture entry from our child list. 01594 prepare_remove_child(tex); 01595 _children.erase(ci); 01596 01597 // And add it to the collection. 01598 collection->add_texture(tex); 01599 num_found++; 01600 01601 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01602 num_found += 01603 DCAST(EggGroupNode, child)->find_textures(collection); 01604 } 01605 01606 ci = cnext; 01607 } 01608 01609 return num_found; 01610 } 01611 01612 //////////////////////////////////////////////////////////////////// 01613 // Function: EggGroupNode::find_materials() 01614 // Access: Protected 01615 // Description: Walks the tree, looking for EggMaterials. Each 01616 // EggMaterial that is found is removed from the 01617 // hierarchy and added to the EggMaterialCollection. 01618 // Returns the number of EggMaterials found. 01619 //////////////////////////////////////////////////////////////////// 01620 int EggGroupNode:: 01621 find_materials(EggMaterialCollection *collection) { 01622 int num_found = 0; 01623 01624 // We can do this ci/cnext iteration through the list as we modify 01625 // it, only because we know this works with an STL list type 01626 // container. If this were a vector or a set, this wouldn't 01627 // necessarily work. 01628 01629 Children::iterator ci, cnext; 01630 ci = _children.begin(); 01631 while (ci != _children.end()) { 01632 cnext = ci; 01633 ++cnext; 01634 EggNode *child = *ci; 01635 01636 if (child->is_of_type(EggMaterial::get_class_type())) { 01637 PT_EggMaterial tex = DCAST(EggMaterial, child); 01638 01639 // Now remove the EggMaterial entry from our child list. 01640 prepare_remove_child(tex); 01641 _children.erase(ci); 01642 01643 // And add it to the collection. 01644 collection->add_material(tex); 01645 num_found++; 01646 01647 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01648 num_found += 01649 DCAST(EggGroupNode, child)->find_materials(collection); 01650 } 01651 01652 ci = cnext; 01653 } 01654 01655 return num_found; 01656 } 01657 01658 //////////////////////////////////////////////////////////////////// 01659 // Function: EggGroupNode::r_load_externals 01660 // Access: Protected 01661 // Description: Walks the tree and locates unloaded external 01662 // reference nodes, which it attempts to locate and load 01663 // in. The reference node is replaced with the entire 01664 // subtree loaded. This is intended to be called from 01665 // EggData::load_externals(). 01666 //////////////////////////////////////////////////////////////////// 01667 bool EggGroupNode:: 01668 r_load_externals(const DSearchPath &searchpath, CoordinateSystem coordsys, 01669 BamCacheRecord *record) { 01670 bool success = true; 01671 01672 Children::iterator ci; 01673 for (ci = _children.begin(); 01674 ci != _children.end(); 01675 ++ci) { 01676 EggNode *child = *ci; 01677 if (child->is_of_type(EggExternalReference::get_class_type())) { 01678 PT(EggExternalReference) ref = DCAST(EggExternalReference, child); 01679 01680 // Replace the reference with an empty group node. When we load 01681 // the external file successfully, we'll put its contents here. 01682 Filename filename = ref->get_filename(); 01683 EggGroupNode *new_node = 01684 new EggGroupNode(filename.get_basename_wo_extension()); 01685 replace(ci, new_node); 01686 01687 if (!EggData::resolve_egg_filename(filename, searchpath)) { 01688 egg_cat.error() 01689 << "Could not locate " << filename << " in " 01690 << searchpath << "\n"; 01691 } else { 01692 // Now define a new EggData structure to hold the external 01693 // reference, and load it. 01694 EggData ext_data; 01695 ext_data.set_coordinate_system(coordsys); 01696 ext_data.set_auto_resolve_externals(true); 01697 if (ext_data.read(filename)) { 01698 // The external file was read correctly. Add its contents 01699 // into the tree at this point. 01700 if (record != (BamCacheRecord *)NULL) { 01701 record->add_dependent_file(filename); 01702 } 01703 01704 success = 01705 ext_data.load_externals(searchpath, record) 01706 && success; 01707 new_node->steal_children(ext_data); 01708 } 01709 } 01710 01711 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01712 EggGroupNode *group_child = DCAST(EggGroupNode, child); 01713 success = 01714 group_child->r_load_externals(searchpath, coordsys, record) 01715 && success; 01716 } 01717 } 01718 return success; 01719 } 01720 01721 01722 //////////////////////////////////////////////////////////////////// 01723 // Function: EggGroupNode::prepare_add_child 01724 // Access: Private 01725 // Description: Marks the node as a child of the group. This is an 01726 // internal function called by the STL-like functions 01727 // push_back() and insert(), in preparation for actually 01728 // adding the child. 01729 // 01730 // It is an error to add a node that is already a child 01731 // of this group or some other group. 01732 //////////////////////////////////////////////////////////////////// 01733 void EggGroupNode:: 01734 prepare_add_child(EggNode *node) { 01735 nassertv(node != (EggNode *)NULL); 01736 test_ref_count_integrity(); 01737 node->test_ref_count_integrity(); 01738 // Make sure the node is not already a child of some other group. 01739 nassertv(node->get_parent() == NULL); 01740 nassertv(node->get_depth() == 0); 01741 node->_parent = this; 01742 01743 node->update_under(get_depth() + 1); 01744 } 01745 01746 01747 //////////////////////////////////////////////////////////////////// 01748 // Function: EggGroupNode::prepare_remove_child 01749 // Access: Private 01750 // Description: Marks the node as removed from the group. This is an 01751 // internal function called by the STL-like functions 01752 // pop_back() and erase(), in preparation for actually 01753 // doing the removal. 01754 // 01755 // It is an error to attempt to remove a node that is 01756 // not already a child of this group. 01757 //////////////////////////////////////////////////////////////////// 01758 void EggGroupNode:: 01759 prepare_remove_child(EggNode *node) { 01760 nassertv(node != (EggNode *)NULL); 01761 // Make sure the node is in fact a child of this group. 01762 nassertv(node->get_parent() == this); 01763 nassertv(node->get_depth() == get_depth() + 1); 01764 node->_parent = NULL; 01765 01766 node->update_under(-(get_depth() + 1)); 01767 } 01768 01769 01770 01771 //////////////////////////////////////////////////////////////////// 01772 // Function: EggGroupNode::r_collect_vertex_normals 01773 // Access: Private 01774 // Description: This is part of the implementation of 01775 // recompute_vertex_normals(). It walks the scene graph 01776 // at this group node and below, identifying all the 01777 // polygons and the vertices they have in common. 01778 //////////////////////////////////////////////////////////////////// 01779 void EggGroupNode:: 01780 r_collect_vertex_normals(EggGroupNode::NVertexCollection &collection, 01781 double threshold, CoordinateSystem cs) { 01782 // We can do this ci/cnext iteration through the list as we modify 01783 // it, only because we know this works with an STL list type 01784 // container. If this were a vector or a set, this wouldn't 01785 // necessarily work. 01786 01787 Children::iterator ci, cnext; 01788 ci = _children.begin(); 01789 while (ci != _children.end()) { 01790 cnext = ci; 01791 ++cnext; 01792 EggNode *child = *ci; 01793 01794 if (child->is_of_type(EggPolygon::get_class_type())) { 01795 EggPolygon *polygon = DCAST(EggPolygon, child); 01796 polygon->clear_normal(); 01797 01798 NVertexReference ref; 01799 ref._polygon = polygon; 01800 if (!polygon->calculate_normal(ref._normal, cs)) { 01801 // The polygon is degenerate. Remove it. 01802 01803 prepare_remove_child(child); 01804 _children.erase(ci); 01805 01806 } else { 01807 // Now add each vertex from the polygon separately to our 01808 // collection. 01809 size_t num_vertices = polygon->size(); 01810 for (size_t i = 0; i < num_vertices; i++) { 01811 EggVertex *vertex = polygon->get_vertex(i); 01812 ref._vertex = i; 01813 collection[vertex->get_pos3()].push_back(ref); 01814 } 01815 } 01816 01817 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01818 EggGroupNode *group = DCAST(EggGroupNode, child); 01819 01820 // We can't share vertices across an Instance node. Don't 01821 // even bother trying. Instead, just restart. 01822 if (group->is_under_instance()) { 01823 group->recompute_vertex_normals(threshold, cs); 01824 } else { 01825 group->r_collect_vertex_normals(collection, threshold, cs); 01826 } 01827 } 01828 01829 ci = cnext; 01830 } 01831 } 01832 01833 //////////////////////////////////////////////////////////////////// 01834 // Function: EggGroupNode::do_compute_vertex_normals 01835 // Access: Private 01836 // Description: This is part of the implementation of 01837 // recompute_vertex_normals(). It accepts a group of 01838 // polygons and their common normals, and computes the 01839 // same normal for all their shared vertices. 01840 //////////////////////////////////////////////////////////////////// 01841 void EggGroupNode:: 01842 do_compute_vertex_normals(const NVertexGroup &group) { 01843 nassertv(!group.empty()); 01844 01845 // Determine the common normal. This is simply the average of all 01846 // the polygon normals that share this vertex. 01847 Normald normal(0.0, 0.0, 0.0); 01848 NVertexGroup::const_iterator gi; 01849 for (gi = group.begin(); gi != group.end(); ++gi) { 01850 const NVertexReference &ref = (*gi); 01851 normal += ref._normal; 01852 } 01853 01854 normal /= (double)group.size(); 01855 normal.normalize(); 01856 01857 // Now we have the common normal; apply it to all the vertices. 01858 01859 for (gi = group.begin(); gi != group.end(); ++gi) { 01860 const NVertexReference &ref = (*gi); 01861 EggVertex *vertex = ref._polygon->get_vertex(ref._vertex); 01862 EggVertexPool *pool = vertex->get_pool(); 01863 01864 EggVertex new_vertex(*vertex); 01865 new_vertex.set_normal(normal); 01866 EggVertex *unique = pool->create_unique_vertex(new_vertex); 01867 unique->copy_grefs_from(*vertex); 01868 01869 ref._polygon->set_vertex(ref._vertex, unique); 01870 } 01871 } 01872 01873 //////////////////////////////////////////////////////////////////// 01874 // Function: EggGroupNode::r_collect_tangent_binormal 01875 // Access: Private 01876 // Description: This is part of the implementation of 01877 // recompute_tangent_binormal(). It walks the scene 01878 // graph at this group node and below, identifying all 01879 // the polygons and the vertices they have in common. 01880 //////////////////////////////////////////////////////////////////// 01881 void EggGroupNode:: 01882 r_collect_tangent_binormal(const GlobPattern &uv_name, 01883 EggGroupNode::TBNVertexCollection &collection) { 01884 Children::iterator ci; 01885 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01886 EggNode *child = *ci; 01887 01888 if (child->is_of_type(EggPolygon::get_class_type())) { 01889 EggPolygon *polygon = DCAST(EggPolygon, child); 01890 01891 TBNVertexReference ref; 01892 ref._polygon = polygon; 01893 01894 // Now add each vertex from the polygon separately to our 01895 // collection. 01896 size_t num_vertices = polygon->size(); 01897 for (size_t i = 0; i < num_vertices; i++) { 01898 // We look at the triangle formed by each three consecutive 01899 // vertices to determine the s direction and t direction at 01900 // each vertex. v1 is the key vertex, the one at position i; 01901 // v2 is vertex i + 1, and v3 is vertex i - 1. 01902 EggVertex *v1 = polygon->get_vertex(i); 01903 EggVertex *v2 = polygon->get_vertex((i + 1) % num_vertices); 01904 EggVertex *v3 = polygon->get_vertex((i + num_vertices - 1) % num_vertices); 01905 if (v1->has_normal() || polygon->has_normal()) { 01906 // Go through all of the UV names on the vertex, looking for 01907 // one that matches the glob pattern. 01908 EggVertex::const_uv_iterator uvi; 01909 for (uvi = v1->uv_begin(); uvi != v1->uv_end(); ++uvi) { 01910 EggVertexUV *uv_obj = (*uvi); 01911 string name = uv_obj->get_name(); 01912 if (uv_name.matches(name) && 01913 v2->has_uv(name) && v3->has_uv(name)) { 01914 TBNVertexValue value; 01915 value._uv_name = name; 01916 value._pos = v1->get_pos3(); 01917 if (v1->has_normal()) { 01918 value._normal = v1->get_normal(); 01919 } else { 01920 value._normal = polygon->get_normal(); 01921 } 01922 value._uv = v1->get_uv(name); 01923 01924 // Compute the s direction and t direction for this vertex. 01925 LPoint3d p1 = v1->get_pos3(); 01926 LPoint3d p2 = v2->get_pos3(); 01927 LPoint3d p3 = v3->get_pos3(); 01928 01929 TexCoordd w1 = v1->get_uv(name); 01930 TexCoordd w2 = v2->get_uv(name); 01931 TexCoordd w3 = v3->get_uv(name); 01932 01933 // Check the facing of the texture; we will have to 01934 // split vertices whose UV's are mirrored along a seam. 01935 // The facing is determined by the winding order of the 01936 // texcoords on the polygon. A front-facing polygon 01937 // should not contribute to the tangent and binormal of 01938 // a back-facing polygon, and vice-versa. 01939 value._facing = is_right(w1 - w2, w3 - w1); 01940 01941 double x1 = p2[0] - p1[0]; 01942 double x2 = p3[0] - p1[0]; 01943 double y1 = p2[1] - p1[1]; 01944 double y2 = p3[1] - p1[1]; 01945 double z1 = p2[2] - p1[2]; 01946 double z2 = p3[2] - p1[2]; 01947 01948 double s1 = w2[0] - w1[0]; 01949 double s2 = w3[0] - w1[0]; 01950 double t1 = w2[1] - w1[1]; 01951 double t2 = w3[1] - w1[1]; 01952 01953 double denom = (s1 * t2 - s2 * t1); 01954 if (denom == 0.0) { 01955 ref._sdir.set(0.0, 0.0, 0.0); 01956 ref._tdir.set(0.0, 0.0, 0.0); 01957 } else { 01958 double r = 1.0 / denom; 01959 ref._sdir.set((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, 01960 (t2 * z1 - t1 * z2) * r); 01961 ref._tdir.set((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, 01962 (s1 * z2 - s2 * z1) * r); 01963 } 01964 01965 // Store the vertex referenced to the polygon. 01966 ref._vertex = i; 01967 collection[value].push_back(ref); 01968 } 01969 } 01970 } 01971 } 01972 01973 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01974 EggGroupNode *group = DCAST(EggGroupNode, child); 01975 01976 // We can't share vertices across an Instance node. Don't 01977 // even bother trying. Instead, just restart. 01978 if (group->is_under_instance()) { 01979 group->recompute_tangent_binormal(uv_name); 01980 } else { 01981 group->r_collect_tangent_binormal(uv_name, collection); 01982 } 01983 } 01984 } 01985 } 01986 01987 //////////////////////////////////////////////////////////////////// 01988 // Function: EggGroupNode::do_compute_tangent_binormal 01989 // Access: Private 01990 // Description: This is part of the implementation of 01991 // recompute_tangent_binormal(). It accepts a group of 01992 // polygons and their common normals and UV's, and 01993 // computes the tangent and binormal for all their 01994 // shared vertices. 01995 //////////////////////////////////////////////////////////////////// 01996 void EggGroupNode:: 01997 do_compute_tangent_binormal(const TBNVertexValue &value, 01998 const TBNVertexGroup &group) { 01999 nassertv(!group.empty()); 02000 02001 // Accumulate together all of the s vectors and t vectors computed 02002 // for the different vertices that are together here. 02003 Normald sdir(0.0, 0.0, 0.0); 02004 Normald tdir(0.0, 0.0, 0.0); 02005 02006 TBNVertexGroup::const_iterator gi; 02007 for (gi = group.begin(); gi != group.end(); ++gi) { 02008 const TBNVertexReference &ref = (*gi); 02009 sdir += ref._sdir; 02010 tdir += ref._tdir; 02011 } 02012 02013 // If sdir and/or tdir are zero, choose an arbitrary vector instead. 02014 // (This is really the only reason we normalize sdir and tdir, 02015 // though it also helps stabilize the math below in case the vectors 02016 // are very small but not quite zero.) 02017 if (!sdir.normalize()) { 02018 sdir.set(1.0, 0.0, 0.0); 02019 } 02020 if (!tdir.normalize()) { 02021 tdir = sdir.cross(Normald(0.0, 0.0, -1.0)); 02022 } 02023 02024 Normald tangent = (sdir - value._normal * value._normal.dot(sdir)); 02025 tangent.normalize(); 02026 02027 Normald binormal = cross(value._normal, tangent); 02028 if (dot(binormal, tdir) < 0.0f) { 02029 binormal = -binormal; 02030 } 02031 // Shouldn't need to normalize this, but we do just for good measure. 02032 binormal.normalize(); 02033 02034 // Now we have the common tangent and binormal; apply them to all 02035 // the vertices. 02036 02037 for (gi = group.begin(); gi != group.end(); ++gi) { 02038 const TBNVertexReference &ref = (*gi); 02039 EggVertex *vertex = ref._polygon->get_vertex(ref._vertex); 02040 EggVertexPool *pool = vertex->get_pool(); 02041 02042 EggVertex new_vertex(*vertex); 02043 EggVertexUV *uv_obj = new_vertex.modify_uv_obj(value._uv_name); 02044 nassertv(uv_obj != (EggVertexUV *)NULL); 02045 uv_obj->set_tangent(tangent); 02046 uv_obj->set_binormal(binormal); 02047 02048 EggVertex *unique = pool->create_unique_vertex(new_vertex); 02049 unique->copy_grefs_from(*vertex); 02050 02051 ref._polygon->set_vertex(ref._vertex, unique); 02052 } 02053 }