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 (eggtex->get_env_type() == EggTexture::ET_normal_gloss)) { 00779 string uv = eggtex->get_uv_name(); 00780 vector_string::iterator it = find(names.begin(), names.end(), uv); 00781 if (it == names.end()) { 00782 names.push_back(uv); 00783 } 00784 } 00785 } 00786 return recompute_tangent_binormal(names); 00787 } 00788 00789 //////////////////////////////////////////////////////////////////// 00790 // Function: EggGroupNode::triangulate_polygons 00791 // Access: Published 00792 // Description: Replace all higher-order polygons at this point in 00793 // the scene graph and below with triangles. Returns 00794 // the total number of new triangles produced, less 00795 // degenerate polygons removed. 00796 // 00797 // If flags contains T_polygon and T_convex, both 00798 // concave and convex polygons will be subdivided into 00799 // triangles; with only T_polygon, only concave polygons 00800 // will be subdivided, and convex polygons will be 00801 // largely unchanged. 00802 //////////////////////////////////////////////////////////////////// 00803 int EggGroupNode:: 00804 triangulate_polygons(int flags) { 00805 int num_produced = 0; 00806 00807 Children children_copy = _children; 00808 00809 Children::iterator ci; 00810 for (ci = children_copy.begin(); 00811 ci != children_copy.end(); 00812 ++ci) { 00813 EggNode *child = (*ci); 00814 00815 if (child->is_of_type(EggPolygon::get_class_type())) { 00816 if ((flags & T_polygon) != 0) { 00817 EggPolygon *poly = DCAST(EggPolygon, child); 00818 poly->triangulate_in_place((flags & T_convex) != 0); 00819 } 00820 00821 } else if (child->is_of_type(EggCompositePrimitive::get_class_type())) { 00822 if ((flags & T_composite) != 0) { 00823 EggCompositePrimitive *comp = DCAST(EggCompositePrimitive, child); 00824 comp->triangulate_in_place(); 00825 } 00826 00827 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 00828 if ((flags & T_recurse) != 0) { 00829 num_produced += DCAST(EggGroupNode, child)->triangulate_polygons(flags); 00830 } 00831 } 00832 } 00833 00834 num_produced += max(0, (int)(_children.size() - children_copy.size())); 00835 return num_produced; 00836 } 00837 00838 //////////////////////////////////////////////////////////////////// 00839 // Function: EggGroupNode::mesh_triangles 00840 // Access: Published 00841 // Description: Combine triangles together into triangle strips, at 00842 // this group and below. 00843 //////////////////////////////////////////////////////////////////// 00844 void EggGroupNode:: 00845 mesh_triangles(int flags) { 00846 EggMesher mesher; 00847 mesher.mesh(this, (flags & T_flat_shaded) != 0); 00848 00849 if ((flags & T_recurse) != 0) { 00850 EggGroupNode::iterator ci; 00851 for (ci = begin(); ci != end(); ++ci) { 00852 if ((*ci)->is_of_type(EggGroupNode::get_class_type())) { 00853 EggGroupNode *group_child = DCAST(EggGroupNode, *ci); 00854 group_child->mesh_triangles(flags); 00855 } 00856 } 00857 } 00858 } 00859 00860 //////////////////////////////////////////////////////////////////// 00861 // Function: EggGroupNode::make_point_primitives 00862 // Access: Published 00863 // Description: Creates PointLight primitives to reference any 00864 // otherwise unreferences vertices discovered in this 00865 // group or below. 00866 //////////////////////////////////////////////////////////////////// 00867 void EggGroupNode:: 00868 make_point_primitives() { 00869 // Create a temporary node to hold the EggPoint objects we might 00870 // create while we iterate. (We don't add them during the iteration 00871 // to avoid invalidating the iterator.) 00872 PT(EggGroupNode) temp = new EggGroup("temp"); 00873 00874 EggGroupNode::iterator ci; 00875 for (ci = begin(); ci != end(); ++ci) { 00876 if ((*ci)->is_of_type(EggGroupNode::get_class_type())) { 00877 EggGroupNode *group_child = DCAST(EggGroupNode, *ci); 00878 group_child->make_point_primitives(); 00879 00880 } else if ((*ci)->is_of_type(EggVertexPool::get_class_type())) { 00881 EggVertexPool *vpool = DCAST(EggVertexPool, *ci); 00882 PT(EggPrimitive) prim = new EggPoint; 00883 vpool->add_unused_vertices_to_prim(prim); 00884 if (!prim->empty()) { 00885 temp->add_child(prim); 00886 } 00887 } 00888 } 00889 00890 steal_children(*temp); 00891 } 00892 00893 //////////////////////////////////////////////////////////////////// 00894 // Function: EggGroupNode::rename_nodes 00895 // Access: Published 00896 // Description: Rename by stripping out the prefix 00897 //////////////////////////////////////////////////////////////////// 00898 int EggGroupNode:: 00899 rename_nodes(vector_string strip_prefix, bool recurse) { 00900 int num_renamed = 0; 00901 for (unsigned int ni = 0; ni < strip_prefix.size(); ++ni) { 00902 string axe_name = strip_prefix[ni]; 00903 if (this->get_name().substr(0, axe_name.size()) == axe_name) { 00904 string new_name = this->get_name().substr(axe_name.size()); 00905 //cout << "renaming " << this->get_name() << "->" << new_name << endl; 00906 this->set_name(new_name); 00907 num_renamed += 1; 00908 } 00909 } 00910 if (recurse) { 00911 EggGroupNode::iterator ci; 00912 for (ci = begin(); ci != end(); ++ci) { 00913 if ((*ci)->is_of_type(EggGroupNode::get_class_type())) { 00914 EggGroupNode *group_child = DCAST(EggGroupNode, *ci); 00915 num_renamed += group_child->rename_nodes(strip_prefix, recurse); 00916 } 00917 else if ((*ci)->is_of_type(EggNode::get_class_type())) { 00918 EggNode *node_child = DCAST(EggNode, *ci); 00919 num_renamed += node_child->rename_node(strip_prefix); 00920 } 00921 } 00922 } 00923 return num_renamed; 00924 } 00925 00926 //////////////////////////////////////////////////////////////////// 00927 // Function: EggGroupNode::remove_unused_vertices 00928 // Access: Published 00929 // Description: Removes all vertices from VertexPools within this 00930 // group or below that are not referenced by at least 00931 // one primitive. Also collapses together equivalent 00932 // vertices, and renumbers all vertices after the 00933 // operation so their indices are consecutive, beginning 00934 // at zero. Returns the total number of vertices 00935 // removed. 00936 // 00937 // Note that this operates on the VertexPools within 00938 // this group level, without respect to primitives that 00939 // reference these vertices (unlike other functions like 00940 // strip_normals()). It is therefore most useful to 00941 // call this on the EggData root, rather than on a 00942 // subgroup within the hierarchy, since a VertexPool may 00943 // appear anywhere in the hierarchy. 00944 //////////////////////////////////////////////////////////////////// 00945 int EggGroupNode:: 00946 remove_unused_vertices(bool recurse) { 00947 int num_removed = 0; 00948 00949 Children::iterator ci, cnext; 00950 ci = _children.begin(); 00951 while (ci != _children.end()) { 00952 cnext = ci; 00953 ++cnext; 00954 EggNode *child = *ci; 00955 00956 if (child->is_of_type(EggVertexPool::get_class_type())) { 00957 EggVertexPool *vpool = DCAST(EggVertexPool, child); 00958 num_removed += vpool->remove_unused_vertices(); 00959 00960 if (vpool->empty()) { 00961 // If, after removing all the vertices, there's nothing left 00962 // in the vertex pool, then remove the whole vertex pool. 00963 _children.erase(ci); 00964 } 00965 00966 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 00967 if (recurse) { 00968 num_removed += DCAST(EggGroupNode, child)->remove_unused_vertices(recurse); 00969 } 00970 } 00971 00972 ci = cnext; 00973 } 00974 00975 return num_removed; 00976 } 00977 00978 //////////////////////////////////////////////////////////////////// 00979 // Function: EggGroupNode::remove_invalid_primitives 00980 // Access: Published 00981 // Description: Removes primitives at this level and below which 00982 // appear to be degenerate; e.g. polygons with fewer 00983 // than 3 vertices, etc. Returns the number of 00984 // primitives removed. 00985 //////////////////////////////////////////////////////////////////// 00986 int EggGroupNode:: 00987 remove_invalid_primitives(bool recurse) { 00988 int num_removed = 0; 00989 00990 Children::iterator ci, cnext; 00991 ci = _children.begin(); 00992 while (ci != _children.end()) { 00993 cnext = ci; 00994 ++cnext; 00995 EggNode *child = *ci; 00996 00997 if (child->is_of_type(EggPrimitive::get_class_type())) { 00998 EggPrimitive *prim = DCAST(EggPrimitive, child); 00999 if (!prim->cleanup()) { 01000 _children.erase(ci); 01001 num_removed++; 01002 } 01003 01004 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01005 if (recurse) { 01006 num_removed += DCAST(EggGroupNode, child)->remove_invalid_primitives(recurse); 01007 } 01008 } 01009 01010 ci = cnext; 01011 } 01012 01013 return num_removed; 01014 } 01015 01016 //////////////////////////////////////////////////////////////////// 01017 // Function: EggGroupNode::clear_connected_shading 01018 // Access: Published 01019 // Description: Resets the connected_shading information on all 01020 // primitives at this node and below, so that it may be 01021 // accurately rederived by the next call to 01022 // get_connected_shading(). 01023 // 01024 // It may be a good idea to call 01025 // remove_unused_vertices() as well, to establish the 01026 // correct connectivity between common vertices. 01027 //////////////////////////////////////////////////////////////////// 01028 void EggGroupNode:: 01029 clear_connected_shading() { 01030 Children::iterator ci; 01031 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01032 EggNode *child = *ci; 01033 01034 if (child->is_of_type(EggPrimitive::get_class_type())) { 01035 EggPrimitive *prim = DCAST(EggPrimitive, child); 01036 prim->clear_connected_shading(); 01037 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01038 DCAST(EggGroupNode, child)->clear_connected_shading(); 01039 } 01040 } 01041 } 01042 01043 //////////////////////////////////////////////////////////////////// 01044 // Function: EggGroupNode::get_connected_shading 01045 // Access: Published 01046 // Description: Queries the connected_shading information on all 01047 // primitives at this node and below, to ensure that it 01048 // has been completely filled in before we start mucking 01049 // around with vertices. 01050 //////////////////////////////////////////////////////////////////// 01051 void EggGroupNode:: 01052 get_connected_shading() { 01053 Children::iterator ci; 01054 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01055 EggNode *child = *ci; 01056 01057 if (child->is_of_type(EggPrimitive::get_class_type())) { 01058 EggPrimitive *prim = DCAST(EggPrimitive, child); 01059 prim->get_connected_shading(); 01060 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01061 DCAST(EggGroupNode, child)->get_connected_shading(); 01062 } 01063 } 01064 } 01065 01066 //////////////////////////////////////////////////////////////////// 01067 // Function: EggGroupNode::unify_attributes 01068 // Access: Published 01069 // Description: Applies per-vertex normal and color to all vertices, 01070 // if they are in fact per-vertex (and different for 01071 // each vertex), or moves them to the primitive if they 01072 // are all the same. 01073 // 01074 // After this call, either the primitive will have 01075 // normals or its vertices will, but not both. Ditto 01076 // for colors. 01077 // 01078 // If use_connected_shading is true, each polygon is 01079 // considered in conjunction with all connected 01080 // polygons; otherwise, each polygon is considered 01081 // individually. 01082 // 01083 // If allow_per_primitive is false, S_per_face or 01084 // S_overall will treated like S_per_vertex: normals and 01085 // colors will always be assigned to the vertices. In 01086 // this case, there will never be per-primitive colors 01087 // or normals after this call returns. On the other 01088 // hand, if allow_per_primitive is true, then S_per_face 01089 // means that normals and colors should be assigned to 01090 // the primitives, and removed from the vertices, as 01091 // described above. 01092 // 01093 // This may create redundant vertices in the vertex 01094 // pool, so it may be a good idea to follow this up with 01095 // remove_unused_vertices(). 01096 //////////////////////////////////////////////////////////////////// 01097 void EggGroupNode:: 01098 unify_attributes(bool use_connected_shading, bool allow_per_primitive, 01099 bool recurse) { 01100 Children::iterator ci; 01101 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01102 EggNode *child = *ci; 01103 01104 if (child->is_of_type(EggPrimitive::get_class_type())) { 01105 EggPrimitive *prim = DCAST(EggPrimitive, child); 01106 01107 EggPrimitive::Shading shading = EggPrimitive::S_per_vertex; 01108 01109 if (allow_per_primitive) { 01110 shading = prim->get_shading(); 01111 if (use_connected_shading) { 01112 shading = prim->get_connected_shading(); 01113 } 01114 } 01115 01116 prim->unify_attributes(shading); 01117 01118 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01119 if (recurse) { 01120 DCAST(EggGroupNode, child)->unify_attributes 01121 (use_connected_shading, allow_per_primitive, recurse); 01122 } 01123 } 01124 } 01125 } 01126 01127 //////////////////////////////////////////////////////////////////// 01128 // Function: EggGroupNode::apply_last_attribute 01129 // Access: Published 01130 // Description: Sets the last vertex of the triangle (or each 01131 // component) to the primitive normal and/or color, if 01132 // the primitive is flat-shaded. This reflects the 01133 // OpenGL convention of storing flat-shaded properties on 01134 // the last vertex, although it is not usually a 01135 // convention in Egg. 01136 // 01137 // This may create redundant vertices in the vertex 01138 // pool, so it may be a good idea to follow this up with 01139 // remove_unused_vertices(). 01140 //////////////////////////////////////////////////////////////////// 01141 void EggGroupNode:: 01142 apply_last_attribute(bool recurse) { 01143 Children::iterator ci; 01144 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01145 EggNode *child = *ci; 01146 01147 if (child->is_of_type(EggPrimitive::get_class_type())) { 01148 EggPrimitive *prim = DCAST(EggPrimitive, child); 01149 prim->apply_last_attribute(); 01150 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01151 if (recurse) { 01152 DCAST(EggGroupNode, child)->apply_last_attribute(recurse); 01153 } 01154 } 01155 } 01156 } 01157 01158 //////////////////////////////////////////////////////////////////// 01159 // Function: EggGroupNode::apply_first_attribute 01160 // Access: Published 01161 // Description: Sets the first vertex of the triangle (or each 01162 // component) to the primitive normal and/or color, if 01163 // the primitive is flat-shaded. This reflects the 01164 // DirectX convention of storing flat-shaded properties on 01165 // the first vertex, although it is not usually a 01166 // convention in Egg. 01167 // 01168 // This may create redundant vertices in the vertex 01169 // pool, so it may be a good idea to follow this up with 01170 // remove_unused_vertices(). 01171 //////////////////////////////////////////////////////////////////// 01172 void EggGroupNode:: 01173 apply_first_attribute(bool recurse) { 01174 Children::iterator ci; 01175 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01176 EggNode *child = *ci; 01177 01178 if (child->is_of_type(EggPrimitive::get_class_type())) { 01179 EggPrimitive *prim = DCAST(EggPrimitive, child); 01180 prim->apply_first_attribute(); 01181 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01182 if (recurse) { 01183 DCAST(EggGroupNode, child)->apply_first_attribute(recurse); 01184 } 01185 } 01186 } 01187 } 01188 01189 //////////////////////////////////////////////////////////////////// 01190 // Function: EggGroupNode::post_apply_flat_attribute 01191 // Access: Published 01192 // Description: Intended as a followup to apply_last_attribute(), 01193 // this also sets an attribute on the first vertices of 01194 // the primitive, if they don't already have an 01195 // attribute set, just so they end up with *something*. 01196 //////////////////////////////////////////////////////////////////// 01197 void EggGroupNode:: 01198 post_apply_flat_attribute(bool recurse) { 01199 Children::iterator ci; 01200 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01201 EggNode *child = *ci; 01202 01203 if (child->is_of_type(EggPrimitive::get_class_type())) { 01204 EggPrimitive *prim = DCAST(EggPrimitive, child); 01205 prim->post_apply_flat_attribute(); 01206 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01207 if (recurse) { 01208 DCAST(EggGroupNode, child)->post_apply_flat_attribute(recurse); 01209 } 01210 } 01211 } 01212 } 01213 01214 //////////////////////////////////////////////////////////////////// 01215 // Function: EggGroupNode::has_primitives 01216 // Access: Published, Virtual 01217 // Description: Returns true if there are any primitives 01218 // (e.g. polygons) defined within this group or below, 01219 // false otherwise. 01220 //////////////////////////////////////////////////////////////////// 01221 bool EggGroupNode:: 01222 has_primitives() const { 01223 Children::const_iterator ci; 01224 for (ci = _children.begin(); 01225 ci != _children.end(); 01226 ++ci) { 01227 if ((*ci)->has_primitives()) { 01228 return true; 01229 } 01230 } 01231 01232 return false; 01233 } 01234 01235 //////////////////////////////////////////////////////////////////// 01236 // Function: EggGroupNode::joint_has_primitives 01237 // Access: Published, Virtual 01238 // Description: Returns true if there are any primitives 01239 // (e.g. polygons) defined within this group or below, 01240 // but the search does not include nested joints. 01241 //////////////////////////////////////////////////////////////////// 01242 bool EggGroupNode:: 01243 joint_has_primitives() const { 01244 Children::const_iterator ci; 01245 for (ci = _children.begin(); 01246 ci != _children.end(); 01247 ++ci) { 01248 EggNode *child = (*ci); 01249 01250 if (!child->is_joint()) { 01251 if (child->joint_has_primitives()) { 01252 return true; 01253 } 01254 } 01255 } 01256 01257 return false; 01258 } 01259 01260 //////////////////////////////////////////////////////////////////// 01261 // Function: EggGroupNode::has_normals 01262 // Access: Published, Virtual 01263 // Description: Returns true if any of the primitives (e.g. polygons) 01264 // defined within this group or below have either face 01265 // or vertex normals defined, false otherwise. 01266 //////////////////////////////////////////////////////////////////// 01267 bool EggGroupNode:: 01268 has_normals() const { 01269 Children::const_iterator ci; 01270 for (ci = _children.begin(); 01271 ci != _children.end(); 01272 ++ci) { 01273 if ((*ci)->has_normals()) { 01274 return true; 01275 } 01276 } 01277 01278 return false; 01279 } 01280 01281 //////////////////////////////////////////////////////////////////// 01282 // Function: EggGroupNode::rebuild_vertex_pools 01283 // Access: Published 01284 // Description: Copies vertices used by the primitives at this group 01285 // node (and below, if recurse is true) into one or more 01286 // new vertex pools, and updates the primitives to 01287 // reference these pools. It is up to the caller to 01288 // parent the newly-created vertex pools somewhere 01289 // appropriate in the egg hierarchy. 01290 // 01291 // No more than max_vertices will be placed into any one 01292 // vertex pool. This is the sole criteria for splitting 01293 // vertex pools. 01294 //////////////////////////////////////////////////////////////////// 01295 void EggGroupNode:: 01296 rebuild_vertex_pools(EggVertexPools &vertex_pools, unsigned int max_vertices, 01297 bool recurse) { 01298 Children::iterator ci; 01299 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01300 EggNode *child = *ci; 01301 01302 if (child->is_of_type(EggPrimitive::get_class_type())) { 01303 typedef pvector< PT(EggVertex) > Vertices; 01304 Vertices vertices; 01305 EggPrimitive *prim = DCAST(EggPrimitive, child); 01306 01307 // Copy all of the vertices out. 01308 EggPrimitive::const_iterator pi; 01309 for (pi = prim->begin(); pi != prim->end(); ++pi) { 01310 vertices.push_back(*pi); 01311 } 01312 01313 typedef epvector<EggAttributes> Attributes; 01314 Attributes attributes; 01315 01316 if (prim->is_of_type(EggCompositePrimitive::get_class_type())) { 01317 // A compositive primitive has the additional complication of 01318 // dealing with its attributes. 01319 EggCompositePrimitive *cprim = DCAST(EggCompositePrimitive, prim); 01320 int i; 01321 int num_components = cprim->get_num_components(); 01322 for (i = 0; i < num_components; i++) { 01323 attributes.push_back(*cprim->get_component(i)); 01324 } 01325 } 01326 01327 prim->clear(); 01328 01329 // Now look for a new home for the vertices. First, see if any 01330 // of the vertex pools we've already created already have a copy 01331 // of each one of the vertices. 01332 bool found_pool = false; 01333 EggVertexPool *best_pool = NULL; 01334 int best_new_vertices = 0; 01335 01336 Vertices new_vertices; 01337 EggVertexPools::iterator vpi; 01338 for (vpi = vertex_pools.begin(); 01339 vpi != vertex_pools.end() && !found_pool; 01340 ++vpi) { 01341 EggVertexPool *vertex_pool = (*vpi); 01342 int num_new_vertices = 0; 01343 01344 new_vertices.clear(); 01345 new_vertices.reserve(vertices.size()); 01346 01347 Vertices::const_iterator vi; 01348 for (vi = vertices.begin(); 01349 vi != vertices.end() && !found_pool; 01350 ++vi) { 01351 EggVertex *vertex = (*vi); 01352 EggVertex *new_vertex = vertex_pool->find_matching_vertex(*vertex); 01353 new_vertices.push_back(new_vertex); 01354 if (new_vertex == (EggVertex *)NULL) { 01355 ++num_new_vertices; 01356 } 01357 } 01358 01359 if (num_new_vertices == 0) { 01360 // Great, we found a vertex pool that already shares all 01361 // these vertices. No need to look any further. 01362 found_pool = true; 01363 01364 } else if (vertex_pool->size() + num_new_vertices <= max_vertices) { 01365 // We would have to add some vertices to this pool, so this 01366 // vertex pool qualifies only if the number of vertices we 01367 // have to add would still keep it within our limit. 01368 if (best_pool == (EggVertexPool *)NULL || 01369 num_new_vertices < best_new_vertices) { 01370 // This is currently our most favorable vertex pool. 01371 best_pool = vertex_pool; 01372 best_new_vertices = num_new_vertices; 01373 } 01374 } 01375 } 01376 01377 if (!found_pool) { 01378 if (best_pool == (EggVertexPool *)NULL) { 01379 // There was no vertex pool that qualified. We will have to 01380 // create a new vertex pool. 01381 best_pool = new EggVertexPool(""); 01382 vertex_pools.push_back(best_pool); 01383 } 01384 01385 new_vertices.clear(); 01386 new_vertices.reserve(vertices.size()); 01387 01388 Vertices::const_iterator vi; 01389 for (vi = vertices.begin(); vi != vertices.end(); ++vi) { 01390 EggVertex *vertex = (*vi); 01391 EggVertex *new_vertex = best_pool->create_unique_vertex(*vertex); 01392 new_vertex->copy_grefs_from(*vertex); 01393 new_vertices.push_back(new_vertex); 01394 } 01395 } 01396 01397 Vertices::const_iterator vi; 01398 nassertv(new_vertices.size() == vertices.size()); 01399 for (vi = new_vertices.begin(); vi != new_vertices.end(); ++vi) { 01400 EggVertex *new_vertex = (*vi); 01401 nassertv(new_vertex != (EggVertex *)NULL); 01402 prim->add_vertex(new_vertex); 01403 } 01404 01405 if (prim->is_of_type(EggCompositePrimitive::get_class_type())) { 01406 // Now restore the composite attributes. 01407 EggCompositePrimitive *cprim = DCAST(EggCompositePrimitive, prim); 01408 int i; 01409 int num_components = cprim->get_num_components(); 01410 nassertv(num_components == (int)attributes.size()); 01411 for (i = 0; i < num_components; i++) { 01412 cprim->set_component(i, &attributes[i]); 01413 } 01414 } 01415 01416 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01417 if (recurse) { 01418 DCAST(EggGroupNode, child)->rebuild_vertex_pools(vertex_pools, max_vertices, recurse); 01419 } 01420 } 01421 } 01422 } 01423 01424 //////////////////////////////////////////////////////////////////// 01425 // Function: EggGroupNode::update_under 01426 // Access: Protected, Virtual 01427 // Description: This function is called from within EggGroupNode 01428 // whenever the parentage of the node has changed. It 01429 // should update the depth and under_instance flags 01430 // accordingly. 01431 // 01432 // Offset is the difference between the old depth value 01433 // and the new value. It should be consistent with the 01434 // supplied depth value. If it is not, we have some 01435 // error. 01436 //////////////////////////////////////////////////////////////////// 01437 void EggGroupNode:: 01438 update_under(int depth_offset) { 01439 EggNode::update_under(depth_offset); 01440 01441 Children::iterator ci; 01442 for (ci = _children.begin(); 01443 ci != _children.end(); 01444 ++ci) { 01445 nassertv((*ci)->get_parent() == this); 01446 (*ci)->update_under(depth_offset); 01447 } 01448 } 01449 01450 //////////////////////////////////////////////////////////////////// 01451 // Function: EggGroupNode::r_transform 01452 // Access: Protected, Virtual 01453 // Description: This is called from within the egg code by 01454 // transform(). It applies a transformation matrix 01455 // to the current node in some sensible way, then 01456 // continues down the tree. 01457 // 01458 // The first matrix is the transformation to apply; the 01459 // second is its inverse. The third parameter is the 01460 // coordinate system we are changing to, or CS_default 01461 // if we are not changing coordinate systems. 01462 //////////////////////////////////////////////////////////////////// 01463 void EggGroupNode:: 01464 r_transform(const LMatrix4d &mat, const LMatrix4d &inv, 01465 CoordinateSystem to_cs) { 01466 Children::iterator ci; 01467 for (ci = _children.begin(); 01468 ci != _children.end(); 01469 ++ci) { 01470 (*ci)->r_transform(mat, inv, to_cs); 01471 } 01472 } 01473 01474 //////////////////////////////////////////////////////////////////// 01475 // Function: EggGroupNode::r_transform_vertices 01476 // Access: Protected, Virtual 01477 // Description: This is called from within the egg code by 01478 // transform_vertices_only()(). It applies a 01479 // transformation matrix to the current node in some 01480 // sensible way (if the current node is a vertex pool 01481 // with vertices), then continues down the tree. 01482 //////////////////////////////////////////////////////////////////// 01483 void EggGroupNode:: 01484 r_transform_vertices(const LMatrix4d &mat) { 01485 Children::iterator ci; 01486 for (ci = _children.begin(); 01487 ci != _children.end(); 01488 ++ci) { 01489 (*ci)->r_transform_vertices(mat); 01490 } 01491 } 01492 01493 //////////////////////////////////////////////////////////////////// 01494 // Function: EggGroupNode::r_mark_coordsys 01495 // Access: Protected, Virtual 01496 // Description: This is only called immediately after loading an egg 01497 // file from disk, to propagate the value found in the 01498 // CoordinateSystem entry (or the default Y-up 01499 // coordinate system) to all nodes that care about what 01500 // the coordinate system is. 01501 //////////////////////////////////////////////////////////////////// 01502 void EggGroupNode:: 01503 r_mark_coordsys(CoordinateSystem cs) { 01504 Children::iterator ci; 01505 for (ci = _children.begin(); 01506 ci != _children.end(); 01507 ++ci) { 01508 (*ci)->r_mark_coordsys(cs); 01509 } 01510 } 01511 01512 //////////////////////////////////////////////////////////////////// 01513 // Function: EggGroupNode::r_flatten_transforms 01514 // Access: Protected, Virtual 01515 // Description: The recursive implementation of flatten_transforms(). 01516 //////////////////////////////////////////////////////////////////// 01517 void EggGroupNode:: 01518 r_flatten_transforms() { 01519 Children::iterator ci; 01520 for (ci = _children.begin(); 01521 ci != _children.end(); 01522 ++ci) { 01523 (*ci)->r_flatten_transforms(); 01524 } 01525 } 01526 01527 //////////////////////////////////////////////////////////////////// 01528 // Function: EggGroupNode::r_apply_texmats 01529 // Access: Protected, Virtual 01530 // Description: The recursive implementation of apply_texmats(). 01531 //////////////////////////////////////////////////////////////////// 01532 void EggGroupNode:: 01533 r_apply_texmats(EggTextureCollection &textures) { 01534 Children::iterator ci; 01535 for (ci = _children.begin(); 01536 ci != _children.end(); 01537 ++ci) { 01538 (*ci)->r_apply_texmats(textures); 01539 } 01540 } 01541 01542 //////////////////////////////////////////////////////////////////// 01543 // Function: EggGroupNode::find_coordsys_entry() 01544 // Access: Protected 01545 // Description: Walks the tree, looking for an EggCoordinateSystem 01546 // entry. If one is found, extracts it and returns its 01547 // value. If multiple entries are found, extracts all 01548 // of them and returns CS_invalid if they disagree. 01549 //////////////////////////////////////////////////////////////////// 01550 CoordinateSystem EggGroupNode:: 01551 find_coordsys_entry() { 01552 CoordinateSystem coordsys = CS_default; 01553 01554 // We can do this ci/cnext iteration through the list as we modify 01555 // it, only because we know this works with an STL list type 01556 // container. If this were a vector or a set, this wouldn't 01557 // necessarily work. 01558 01559 Children::iterator ci, cnext; 01560 ci = _children.begin(); 01561 while (ci != _children.end()) { 01562 cnext = ci; 01563 ++cnext; 01564 EggNode *child = *ci; 01565 01566 if (child->is_of_type(EggCoordinateSystem::get_class_type())) { 01567 CoordinateSystem new_cs = 01568 DCAST(EggCoordinateSystem, child)->get_value(); 01569 01570 // Now remove the CoordinateSystem entry from our child list. 01571 prepare_remove_child(child); 01572 _children.erase(ci); 01573 01574 if (new_cs != CS_default) { 01575 if (coordsys != CS_default && coordsys != new_cs) { 01576 coordsys = CS_invalid; 01577 } else { 01578 coordsys = new_cs; 01579 } 01580 } 01581 01582 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01583 CoordinateSystem new_cs = 01584 DCAST(EggGroupNode, child)->find_coordsys_entry(); 01585 if (new_cs != CS_default) { 01586 if (coordsys != CS_default && coordsys != new_cs) { 01587 coordsys = CS_invalid; 01588 } else { 01589 coordsys = new_cs; 01590 } 01591 } 01592 } 01593 01594 ci = cnext; 01595 } 01596 01597 return coordsys; 01598 } 01599 01600 //////////////////////////////////////////////////////////////////// 01601 // Function: EggGroupNode::find_textures() 01602 // Access: Protected 01603 // Description: Walks the tree, looking for EggTextures. Each 01604 // EggTexture that is found is removed from the 01605 // hierarchy and added to the EggTextureCollection. 01606 // Returns the number of EggTextures found. 01607 //////////////////////////////////////////////////////////////////// 01608 int EggGroupNode:: 01609 find_textures(EggTextureCollection *collection) { 01610 int num_found = 0; 01611 01612 // We can do this ci/cnext iteration through the list as we modify 01613 // it, only because we know this works with an STL list type 01614 // container. If this were a vector or a set, this wouldn't 01615 // necessarily work. 01616 01617 Children::iterator ci, cnext; 01618 ci = _children.begin(); 01619 while (ci != _children.end()) { 01620 cnext = ci; 01621 ++cnext; 01622 EggNode *child = *ci; 01623 01624 if (child->is_of_type(EggTexture::get_class_type())) { 01625 PT_EggTexture tex = DCAST(EggTexture, child); 01626 01627 // Now remove the EggTexture entry from our child list. 01628 prepare_remove_child(tex); 01629 _children.erase(ci); 01630 01631 // And add it to the collection. 01632 collection->add_texture(tex); 01633 num_found++; 01634 01635 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01636 num_found += 01637 DCAST(EggGroupNode, child)->find_textures(collection); 01638 } 01639 01640 ci = cnext; 01641 } 01642 01643 return num_found; 01644 } 01645 01646 //////////////////////////////////////////////////////////////////// 01647 // Function: EggGroupNode::find_materials() 01648 // Access: Protected 01649 // Description: Walks the tree, looking for EggMaterials. Each 01650 // EggMaterial that is found is removed from the 01651 // hierarchy and added to the EggMaterialCollection. 01652 // Returns the number of EggMaterials found. 01653 //////////////////////////////////////////////////////////////////// 01654 int EggGroupNode:: 01655 find_materials(EggMaterialCollection *collection) { 01656 int num_found = 0; 01657 01658 // We can do this ci/cnext iteration through the list as we modify 01659 // it, only because we know this works with an STL list type 01660 // container. If this were a vector or a set, this wouldn't 01661 // necessarily work. 01662 01663 Children::iterator ci, cnext; 01664 ci = _children.begin(); 01665 while (ci != _children.end()) { 01666 cnext = ci; 01667 ++cnext; 01668 EggNode *child = *ci; 01669 01670 if (child->is_of_type(EggMaterial::get_class_type())) { 01671 PT_EggMaterial tex = DCAST(EggMaterial, child); 01672 01673 // Now remove the EggMaterial entry from our child list. 01674 prepare_remove_child(tex); 01675 _children.erase(ci); 01676 01677 // And add it to the collection. 01678 collection->add_material(tex); 01679 num_found++; 01680 01681 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01682 num_found += 01683 DCAST(EggGroupNode, child)->find_materials(collection); 01684 } 01685 01686 ci = cnext; 01687 } 01688 01689 return num_found; 01690 } 01691 01692 //////////////////////////////////////////////////////////////////// 01693 // Function: EggGroupNode::r_load_externals 01694 // Access: Protected 01695 // Description: Walks the tree and locates unloaded external 01696 // reference nodes, which it attempts to locate and load 01697 // in. The reference node is replaced with the entire 01698 // subtree loaded. This is intended to be called from 01699 // EggData::load_externals(). 01700 //////////////////////////////////////////////////////////////////// 01701 bool EggGroupNode:: 01702 r_load_externals(const DSearchPath &searchpath, CoordinateSystem coordsys, 01703 BamCacheRecord *record) { 01704 bool success = true; 01705 01706 Children::iterator ci; 01707 for (ci = _children.begin(); 01708 ci != _children.end(); 01709 ++ci) { 01710 EggNode *child = *ci; 01711 if (child->is_of_type(EggExternalReference::get_class_type())) { 01712 PT(EggExternalReference) ref = DCAST(EggExternalReference, child); 01713 01714 // Replace the reference with an empty group node. When we load 01715 // the external file successfully, we'll put its contents here. 01716 Filename filename = ref->get_filename(); 01717 EggGroupNode *new_node = 01718 new EggGroupNode(filename.get_basename_wo_extension()); 01719 replace(ci, new_node); 01720 01721 if (!EggData::resolve_egg_filename(filename, searchpath)) { 01722 egg_cat.error() 01723 << "Could not locate " << filename << " in " 01724 << searchpath << "\n"; 01725 } else { 01726 // Now define a new EggData structure to hold the external 01727 // reference, and load it. 01728 EggData ext_data; 01729 ext_data.set_coordinate_system(coordsys); 01730 ext_data.set_auto_resolve_externals(true); 01731 if (ext_data.read(filename)) { 01732 // The external file was read correctly. Add its contents 01733 // into the tree at this point. 01734 if (record != (BamCacheRecord *)NULL) { 01735 record->add_dependent_file(filename); 01736 } 01737 01738 success = 01739 ext_data.load_externals(searchpath, record) 01740 && success; 01741 new_node->steal_children(ext_data); 01742 } 01743 } 01744 01745 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01746 EggGroupNode *group_child = DCAST(EggGroupNode, child); 01747 success = 01748 group_child->r_load_externals(searchpath, coordsys, record) 01749 && success; 01750 } 01751 } 01752 return success; 01753 } 01754 01755 01756 //////////////////////////////////////////////////////////////////// 01757 // Function: EggGroupNode::prepare_add_child 01758 // Access: Private 01759 // Description: Marks the node as a child of the group. This is an 01760 // internal function called by the STL-like functions 01761 // push_back() and insert(), in preparation for actually 01762 // adding the child. 01763 // 01764 // It is an error to add a node that is already a child 01765 // of this group or some other group. 01766 //////////////////////////////////////////////////////////////////// 01767 void EggGroupNode:: 01768 prepare_add_child(EggNode *node) { 01769 nassertv(node != (EggNode *)NULL); 01770 test_ref_count_integrity(); 01771 node->test_ref_count_integrity(); 01772 // Make sure the node is not already a child of some other group. 01773 nassertv(node->get_parent() == NULL); 01774 nassertv(node->get_depth() == 0); 01775 node->_parent = this; 01776 01777 node->update_under(get_depth() + 1); 01778 } 01779 01780 01781 //////////////////////////////////////////////////////////////////// 01782 // Function: EggGroupNode::prepare_remove_child 01783 // Access: Private 01784 // Description: Marks the node as removed from the group. This is an 01785 // internal function called by the STL-like functions 01786 // pop_back() and erase(), in preparation for actually 01787 // doing the removal. 01788 // 01789 // It is an error to attempt to remove a node that is 01790 // not already a child of this group. 01791 //////////////////////////////////////////////////////////////////// 01792 void EggGroupNode:: 01793 prepare_remove_child(EggNode *node) { 01794 nassertv(node != (EggNode *)NULL); 01795 // Make sure the node is in fact a child of this group. 01796 nassertv(node->get_parent() == this); 01797 nassertv(node->get_depth() == get_depth() + 1); 01798 node->_parent = NULL; 01799 01800 node->update_under(-(get_depth() + 1)); 01801 } 01802 01803 01804 01805 //////////////////////////////////////////////////////////////////// 01806 // Function: EggGroupNode::r_collect_vertex_normals 01807 // Access: Private 01808 // Description: This is part of the implementation of 01809 // recompute_vertex_normals(). It walks the scene graph 01810 // at this group node and below, identifying all the 01811 // polygons and the vertices they have in common. 01812 //////////////////////////////////////////////////////////////////// 01813 void EggGroupNode:: 01814 r_collect_vertex_normals(EggGroupNode::NVertexCollection &collection, 01815 double threshold, CoordinateSystem cs) { 01816 // We can do this ci/cnext iteration through the list as we modify 01817 // it, only because we know this works with an STL list type 01818 // container. If this were a vector or a set, this wouldn't 01819 // necessarily work. 01820 01821 Children::iterator ci, cnext; 01822 ci = _children.begin(); 01823 while (ci != _children.end()) { 01824 cnext = ci; 01825 ++cnext; 01826 EggNode *child = *ci; 01827 01828 if (child->is_of_type(EggPolygon::get_class_type())) { 01829 EggPolygon *polygon = DCAST(EggPolygon, child); 01830 polygon->clear_normal(); 01831 01832 NVertexReference ref; 01833 ref._polygon = polygon; 01834 if (!polygon->calculate_normal(ref._normal, cs)) { 01835 // The polygon is degenerate. Remove it. 01836 01837 prepare_remove_child(child); 01838 _children.erase(ci); 01839 01840 } else { 01841 // Now add each vertex from the polygon separately to our 01842 // collection. 01843 size_t num_vertices = polygon->size(); 01844 for (size_t i = 0; i < num_vertices; i++) { 01845 EggVertex *vertex = polygon->get_vertex(i); 01846 ref._vertex = i; 01847 collection[vertex->get_pos3()].push_back(ref); 01848 } 01849 } 01850 01851 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 01852 EggGroupNode *group = DCAST(EggGroupNode, child); 01853 01854 // We can't share vertices across an Instance node. Don't 01855 // even bother trying. Instead, just restart. 01856 if (group->is_under_instance()) { 01857 group->recompute_vertex_normals(threshold, cs); 01858 } else { 01859 group->r_collect_vertex_normals(collection, threshold, cs); 01860 } 01861 } 01862 01863 ci = cnext; 01864 } 01865 } 01866 01867 //////////////////////////////////////////////////////////////////// 01868 // Function: EggGroupNode::do_compute_vertex_normals 01869 // Access: Private 01870 // Description: This is part of the implementation of 01871 // recompute_vertex_normals(). It accepts a group of 01872 // polygons and their common normals, and computes the 01873 // same normal for all their shared vertices. 01874 //////////////////////////////////////////////////////////////////// 01875 void EggGroupNode:: 01876 do_compute_vertex_normals(const NVertexGroup &group) { 01877 nassertv(!group.empty()); 01878 01879 // Determine the common normal. This is simply the average of all 01880 // the polygon normals that share this vertex. 01881 LNormald normal(0.0, 0.0, 0.0); 01882 NVertexGroup::const_iterator gi; 01883 for (gi = group.begin(); gi != group.end(); ++gi) { 01884 const NVertexReference &ref = (*gi); 01885 normal += ref._normal; 01886 } 01887 01888 normal /= (double)group.size(); 01889 normal.normalize(); 01890 01891 // Now we have the common normal; apply it to all the vertices. 01892 01893 for (gi = group.begin(); gi != group.end(); ++gi) { 01894 const NVertexReference &ref = (*gi); 01895 EggVertex *vertex = ref._polygon->get_vertex(ref._vertex); 01896 EggVertexPool *pool = vertex->get_pool(); 01897 01898 EggVertex new_vertex(*vertex); 01899 new_vertex.set_normal(normal); 01900 EggVertex *unique = pool->create_unique_vertex(new_vertex); 01901 unique->copy_grefs_from(*vertex); 01902 01903 ref._polygon->set_vertex(ref._vertex, unique); 01904 } 01905 } 01906 01907 //////////////////////////////////////////////////////////////////// 01908 // Function: EggGroupNode::r_collect_tangent_binormal 01909 // Access: Private 01910 // Description: This is part of the implementation of 01911 // recompute_tangent_binormal(). It walks the scene 01912 // graph at this group node and below, identifying all 01913 // the polygons and the vertices they have in common. 01914 //////////////////////////////////////////////////////////////////// 01915 void EggGroupNode:: 01916 r_collect_tangent_binormal(const GlobPattern &uv_name, 01917 EggGroupNode::TBNVertexCollection &collection) { 01918 Children::iterator ci; 01919 for (ci = _children.begin(); ci != _children.end(); ++ci) { 01920 EggNode *child = *ci; 01921 01922 if (child->is_of_type(EggPolygon::get_class_type())) { 01923 EggPolygon *polygon = DCAST(EggPolygon, child); 01924 01925 TBNVertexReference ref; 01926 ref._polygon = polygon; 01927 01928 // Now add each vertex from the polygon separately to our 01929 // collection. 01930 size_t num_vertices = polygon->size(); 01931 for (size_t i = 0; i < num_vertices; i++) { 01932 // We look at the triangle formed by each three consecutive 01933 // vertices to determine the s direction and t direction at 01934 // each vertex. v1 is the key vertex, the one at position i; 01935 // v2 is vertex i + 1, and v3 is vertex i - 1. 01936 EggVertex *v1 = polygon->get_vertex(i); 01937 EggVertex *v2 = polygon->get_vertex((i + 1) % num_vertices); 01938 EggVertex *v3 = polygon->get_vertex((i + num_vertices - 1) % num_vertices); 01939 if (v1->has_normal() || polygon->has_normal()) { 01940 // Go through all of the UV names on the vertex, looking for 01941 // one that matches the glob pattern. 01942 EggVertex::const_uv_iterator uvi; 01943 for (uvi = v1->uv_begin(); uvi != v1->uv_end(); ++uvi) { 01944 EggVertexUV *uv_obj = (*uvi); 01945 string name = uv_obj->get_name(); 01946 if (uv_name.matches(name) && 01947 v2->has_uv(name) && v3->has_uv(name)) { 01948 TBNVertexValue value; 01949 value._uv_name = name; 01950 value._pos = v1->get_pos3(); 01951 if (v1->has_normal()) { 01952 value._normal = v1->get_normal(); 01953 } else { 01954 value._normal = polygon->get_normal(); 01955 } 01956 value._uv = v1->get_uv(name); 01957 01958 // Compute the s direction and t direction for this vertex. 01959 LPoint3d p1 = v1->get_pos3(); 01960 LPoint3d p2 = v2->get_pos3(); 01961 LPoint3d p3 = v3->get_pos3(); 01962 01963 LTexCoordd w1 = v1->get_uv(name); 01964 LTexCoordd w2 = v2->get_uv(name); 01965 LTexCoordd w3 = v3->get_uv(name); 01966 01967 // Check the facing of the texture; we will have to 01968 // split vertices whose UV's are mirrored along a seam. 01969 // The facing is determined by the winding order of the 01970 // texcoords on the polygon. A front-facing polygon 01971 // should not contribute to the tangent and binormal of 01972 // a back-facing polygon, and vice-versa. 01973 value._facing = is_right(w1 - w2, w3 - w1); 01974 01975 double x1 = p2[0] - p1[0]; 01976 double x2 = p3[0] - p1[0]; 01977 double y1 = p2[1] - p1[1]; 01978 double y2 = p3[1] - p1[1]; 01979 double z1 = p2[2] - p1[2]; 01980 double z2 = p3[2] - p1[2]; 01981 01982 double s1 = w2[0] - w1[0]; 01983 double s2 = w3[0] - w1[0]; 01984 double t1 = w2[1] - w1[1]; 01985 double t2 = w3[1] - w1[1]; 01986 01987 double denom = (s1 * t2 - s2 * t1); 01988 if (denom == 0.0) { 01989 ref._sdir.set(0.0, 0.0, 0.0); 01990 ref._tdir.set(0.0, 0.0, 0.0); 01991 } else { 01992 double r = 1.0 / denom; 01993 ref._sdir.set((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, 01994 (t2 * z1 - t1 * z2) * r); 01995 ref._tdir.set((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, 01996 (s1 * z2 - s2 * z1) * r); 01997 } 01998 01999 // Store the vertex referenced to the polygon. 02000 ref._vertex = i; 02001 collection[value].push_back(ref); 02002 } 02003 } 02004 } 02005 } 02006 02007 } else if (child->is_of_type(EggGroupNode::get_class_type())) { 02008 EggGroupNode *group = DCAST(EggGroupNode, child); 02009 02010 // We can't share vertices across an Instance node. Don't 02011 // even bother trying. Instead, just restart. 02012 if (group->is_under_instance()) { 02013 group->recompute_tangent_binormal(uv_name); 02014 } else { 02015 group->r_collect_tangent_binormal(uv_name, collection); 02016 } 02017 } 02018 } 02019 } 02020 02021 //////////////////////////////////////////////////////////////////// 02022 // Function: EggGroupNode::do_compute_tangent_binormal 02023 // Access: Private 02024 // Description: This is part of the implementation of 02025 // recompute_tangent_binormal(). It accepts a group of 02026 // polygons and their common normals and UV's, and 02027 // computes the tangent and binormal for all their 02028 // shared vertices. 02029 //////////////////////////////////////////////////////////////////// 02030 void EggGroupNode:: 02031 do_compute_tangent_binormal(const TBNVertexValue &value, 02032 const TBNVertexGroup &group) { 02033 nassertv(!group.empty()); 02034 02035 // Accumulate together all of the s vectors and t vectors computed 02036 // for the different vertices that are together here. 02037 LNormald sdir(0.0, 0.0, 0.0); 02038 LNormald tdir(0.0, 0.0, 0.0); 02039 02040 TBNVertexGroup::const_iterator gi; 02041 for (gi = group.begin(); gi != group.end(); ++gi) { 02042 const TBNVertexReference &ref = (*gi); 02043 sdir += ref._sdir; 02044 tdir += ref._tdir; 02045 } 02046 02047 // If sdir and/or tdir are zero, choose an arbitrary vector instead. 02048 // (This is really the only reason we normalize sdir and tdir, 02049 // though it also helps stabilize the math below in case the vectors 02050 // are very small but not quite zero.) 02051 if (!sdir.normalize()) { 02052 sdir.set(1.0, 0.0, 0.0); 02053 } 02054 if (!tdir.normalize()) { 02055 tdir = sdir.cross(LNormald(0.0, 0.0, -1.0)); 02056 } 02057 02058 LNormald tangent = (sdir - value._normal * value._normal.dot(sdir)); 02059 tangent.normalize(); 02060 02061 LNormald binormal = cross(value._normal, tangent); 02062 if (dot(binormal, tdir) < 0.0f) { 02063 binormal = -binormal; 02064 } 02065 // Shouldn't need to normalize this, but we do just for good measure. 02066 binormal.normalize(); 02067 02068 // Now we have the common tangent and binormal; apply them to all 02069 // the vertices. 02070 02071 for (gi = group.begin(); gi != group.end(); ++gi) { 02072 const TBNVertexReference &ref = (*gi); 02073 EggVertex *vertex = ref._polygon->get_vertex(ref._vertex); 02074 EggVertexPool *pool = vertex->get_pool(); 02075 02076 EggVertex new_vertex(*vertex); 02077 EggVertexUV *uv_obj = new_vertex.modify_uv_obj(value._uv_name); 02078 nassertv(uv_obj != (EggVertexUV *)NULL); 02079 uv_obj->set_tangent(tangent); 02080 uv_obj->set_binormal(binormal); 02081 02082 EggVertex *unique = pool->create_unique_vertex(new_vertex); 02083 unique->copy_grefs_from(*vertex); 02084 02085 ref._polygon->set_vertex(ref._vertex, unique); 02086 } 02087 }