Panda3D
|
00001 // Filename: eggVertexPool.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 "eggVertexPool.h" 00016 #include "eggPrimitive.h" 00017 #include "eggUtilities.h" 00018 00019 #include "indent.h" 00020 00021 TypeHandle EggVertexPool::_type_handle; 00022 00023 //////////////////////////////////////////////////////////////////// 00024 // Function: EggVertexPool::Constructor 00025 // Access: Public 00026 // Description: 00027 //////////////////////////////////////////////////////////////////// 00028 EggVertexPool:: 00029 EggVertexPool(const string &name) : EggNode(name) { 00030 _highest_index = -1; 00031 } 00032 00033 //////////////////////////////////////////////////////////////////// 00034 // Function: EggVertexPool::Copy Constructor 00035 // Access: Public 00036 // Description: Copying a vertex pool is of questionable value, since 00037 // it will copy all of the vertices and assign new 00038 // pointers to them all. There will be no polygons 00039 // referring to the new vertices. 00040 //////////////////////////////////////////////////////////////////// 00041 EggVertexPool:: 00042 EggVertexPool(const EggVertexPool ©) : EggNode(copy) { 00043 iterator i; 00044 for (i = copy.begin(); i != copy.end(); ++i) { 00045 add_vertex(new EggVertex(*(*i)), (*i)->get_index()); 00046 } 00047 } 00048 00049 00050 //////////////////////////////////////////////////////////////////// 00051 // Function: EggVertexPool::Destructor 00052 // Access: Public 00053 // Description: 00054 //////////////////////////////////////////////////////////////////// 00055 EggVertexPool:: 00056 ~EggVertexPool() { 00057 // Remove all vertices from the pool when it destructs. 00058 00059 // Sanity check. 00060 nassertv(_index_vertices.size() == _unique_vertices.size()); 00061 00062 IndexVertices::iterator ivi; 00063 for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { 00064 int index = (*ivi).first; 00065 EggVertex *vertex = (*ivi).second; 00066 00067 // Sanity checks on our internal data structures. 00068 nassertv(vertex->_pool == this); 00069 nassertv(vertex->get_index() == index); 00070 00071 vertex->_pool = NULL; 00072 vertex->_index = -1; 00073 } 00074 00075 _index_vertices.clear(); 00076 _unique_vertices.clear(); 00077 } 00078 00079 //////////////////////////////////////////////////////////////////// 00080 // Function: EggVertexPool::has_forward_vertices 00081 // Access: Published 00082 // Description: Returns true if any vertices in the pool are 00083 // undefined forward-reference vertices, false if all 00084 // vertices are defined. 00085 //////////////////////////////////////////////////////////////////// 00086 bool EggVertexPool:: 00087 has_forward_vertices() const { 00088 IndexVertices::const_iterator ivi; 00089 for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { 00090 EggVertex *vertex = (*ivi).second; 00091 if (vertex->is_forward_reference()) { 00092 return true; 00093 } 00094 } 00095 00096 return false; 00097 } 00098 00099 //////////////////////////////////////////////////////////////////// 00100 // Function: EggVertexPool::has_defined_vertices 00101 // Access: Published 00102 // Description: Returns true if any vertices in the pool are 00103 // fully defined vertices, false if all vertices are 00104 // forward references. 00105 //////////////////////////////////////////////////////////////////// 00106 bool EggVertexPool:: 00107 has_defined_vertices() const { 00108 IndexVertices::const_iterator ivi; 00109 for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { 00110 EggVertex *vertex = (*ivi).second; 00111 if (!vertex->is_forward_reference()) { 00112 return true; 00113 } 00114 } 00115 00116 return false; 00117 } 00118 00119 //////////////////////////////////////////////////////////////////// 00120 // Function: EggVertexPool::get_vertex 00121 // Access: Public 00122 // Description: Returns the vertex in the pool with the indicated 00123 // index number, or NULL if no vertices have that index 00124 // number. 00125 //////////////////////////////////////////////////////////////////// 00126 EggVertex *EggVertexPool:: 00127 get_vertex(int index) const { 00128 IndexVertices::const_iterator ivi = _index_vertices.find(index); 00129 00130 if (ivi == _index_vertices.end()) { 00131 return NULL; 00132 } else { 00133 EggVertex *vertex = (*ivi).second; 00134 if (vertex->is_forward_reference()) { 00135 return NULL; 00136 } 00137 return vertex; 00138 } 00139 } 00140 00141 //////////////////////////////////////////////////////////////////// 00142 // Function: EggVertexPool::get_forward_vertex 00143 // Access: Public 00144 // Description: Returns the vertex in the pool with the indicated 00145 // index number. If there is not a vertex in the pool 00146 // with the indicated index number, creates a special 00147 // forward-reference EggVertex that has no data, on the 00148 // assumption that the vertex pool has not yet been 00149 // fully read and more data will be available later. 00150 //////////////////////////////////////////////////////////////////// 00151 EggVertex *EggVertexPool:: 00152 get_forward_vertex(int index) { 00153 nassertr(index >= 0, NULL); 00154 00155 IndexVertices::const_iterator ivi = _index_vertices.find(index); 00156 00157 if (ivi == _index_vertices.end()) { 00158 PT(EggVertex) forward = new EggVertex; 00159 forward->_forward_reference = true; 00160 return add_vertex(forward, index); 00161 } else { 00162 return (*ivi).second; 00163 } 00164 } 00165 00166 //////////////////////////////////////////////////////////////////// 00167 // Function: EggVertexPool::get_highest_index 00168 // Access: Public 00169 // Description: Returns the highest index number used by any vertex 00170 // in the pool (except forward references). Returns -1 00171 // if the pool is empty. 00172 //////////////////////////////////////////////////////////////////// 00173 int EggVertexPool:: 00174 get_highest_index() const { 00175 return _highest_index; 00176 } 00177 00178 //////////////////////////////////////////////////////////////////// 00179 // Function: EggVertexPool::set_highest_index 00180 // Access: Public 00181 // Description: Artificially changes the "highest index number", so 00182 // that a newly created vertex will begin at this number 00183 // plus 1. This can be used to default a vertex pool to 00184 // start counting at 1 (or any other index number), 00185 // instead of the default of 0. Use with caution. 00186 //////////////////////////////////////////////////////////////////// 00187 void EggVertexPool:: 00188 set_highest_index(int highest_index) { 00189 _highest_index = highest_index; 00190 } 00191 00192 //////////////////////////////////////////////////////////////////// 00193 // Function: EggVertexPool::get_num_dimensions 00194 // Access: Public 00195 // Description: Returns the maximum number of dimensions used by any 00196 // vertex in the pool. 00197 //////////////////////////////////////////////////////////////////// 00198 int EggVertexPool:: 00199 get_num_dimensions() const { 00200 int num_dimensions = 0; 00201 00202 IndexVertices::const_iterator ivi; 00203 for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { 00204 EggVertex *vertex = (*ivi).second; 00205 num_dimensions = max(num_dimensions, vertex->get_num_dimensions()); 00206 } 00207 00208 return num_dimensions; 00209 } 00210 00211 //////////////////////////////////////////////////////////////////// 00212 // Function: EggVertexPool::has_normals 00213 // Access: Public 00214 // Description: Returns true if any vertex in the pool has a normal 00215 // defined, false if none of them do. 00216 //////////////////////////////////////////////////////////////////// 00217 bool EggVertexPool:: 00218 has_normals() const { 00219 IndexVertices::const_iterator ivi; 00220 for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { 00221 EggVertex *vertex = (*ivi).second; 00222 if (vertex->has_normal()) { 00223 return true; 00224 } 00225 } 00226 00227 return false; 00228 } 00229 00230 //////////////////////////////////////////////////////////////////// 00231 // Function: EggVertexPool::has_colors 00232 // Access: Public 00233 // Description: Returns true if any vertex in the pool has a color 00234 // defined, false if none of them do. 00235 //////////////////////////////////////////////////////////////////// 00236 bool EggVertexPool:: 00237 has_colors() const { 00238 IndexVertices::const_iterator ivi; 00239 for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { 00240 EggVertex *vertex = (*ivi).second; 00241 if (vertex->has_color()) { 00242 return true; 00243 } 00244 } 00245 00246 return false; 00247 } 00248 00249 //////////////////////////////////////////////////////////////////// 00250 // Function: EggVertexPool::has_nonwhite_colors 00251 // Access: Public 00252 // Description: Returns true if any vertex in the pool has a color 00253 // defined other than white, false if no vertices have 00254 // colors, or if all colors are white. 00255 //////////////////////////////////////////////////////////////////// 00256 bool EggVertexPool:: 00257 has_nonwhite_colors() const { 00258 IndexVertices::const_iterator ivi; 00259 for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { 00260 EggVertex *vertex = (*ivi).second; 00261 if (vertex->has_color() && 00262 (vertex->get_color() != Colorf(1.0, 1.0, 1.0, 1.0) || 00263 !vertex->_drgbas.empty())) { 00264 return true; 00265 } 00266 } 00267 00268 return false; 00269 } 00270 00271 //////////////////////////////////////////////////////////////////// 00272 // Function: EggVertexPool::check_overall_color 00273 // Access: Public 00274 // Description: Scans the vertex pool for different colors on 00275 // different vertices. If all vertices are the same 00276 // color, sets has_overall_color to true and fills the 00277 // color into overall_color. If no vertices have any 00278 // color, set has_overall_color to true and fills white 00279 // into overall_color. If at least two vertices have 00280 // different colors, sets has_overall_color to false. 00281 //////////////////////////////////////////////////////////////////// 00282 void EggVertexPool:: 00283 check_overall_color(bool &has_overall_color, Colorf &overall_color) const { 00284 if (empty()) { 00285 has_overall_color = true; 00286 overall_color.set(1.0f, 1.0f, 1.0f, 1.0f); 00287 return; 00288 } 00289 00290 IndexVertices::const_iterator ivi; 00291 ivi = _index_vertices.begin(); 00292 EggVertex *vertex = (*ivi).second; 00293 overall_color = vertex->get_color(); 00294 00295 ++ivi; 00296 while (ivi != _index_vertices.end()) { 00297 vertex = (*ivi).second; 00298 if (!vertex->get_color().almost_equal(overall_color)) { 00299 has_overall_color = false; 00300 return; 00301 } 00302 ++ivi; 00303 } 00304 00305 has_overall_color = true; 00306 } 00307 00308 //////////////////////////////////////////////////////////////////// 00309 // Function: EggVertexPool::has_uvs 00310 // Access: Public 00311 // Description: Returns true if any vertex in the pool has a uv 00312 // defined, false if none of them do. 00313 //////////////////////////////////////////////////////////////////// 00314 bool EggVertexPool:: 00315 has_uvs() const { 00316 IndexVertices::const_iterator ivi; 00317 for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { 00318 EggVertex *vertex = (*ivi).second; 00319 if (vertex->has_uv()) { 00320 return true; 00321 } 00322 } 00323 00324 return false; 00325 } 00326 00327 //////////////////////////////////////////////////////////////////// 00328 // Function: EggVertexPool::get_uv_names 00329 // Access: Public 00330 // Description: Returns the list of UV names that are defined by any 00331 // vertices in the pool, as well as the subset of UV 00332 // names that actually define 3-d texture coordinates 00333 // ("uvw_names"). Also returns the subset of UV/UVW 00334 // names that define a tangent and binormal. It is the 00335 // user's responsibility to clear both vectors before 00336 // calling this method. 00337 //////////////////////////////////////////////////////////////////// 00338 void EggVertexPool:: 00339 get_uv_names(vector_string &uv_names, vector_string &uvw_names, 00340 vector_string &tbn_names) const { 00341 pset<string> uv_names_set, uvw_names_set, tbn_names_set; 00342 IndexVertices::const_iterator ivi; 00343 for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { 00344 EggVertex *vertex = (*ivi).second; 00345 EggVertex::const_uv_iterator uvi; 00346 for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) { 00347 EggVertexUV *uv_obj = (*uvi); 00348 uv_names_set.insert(uv_obj->get_name()); 00349 if (uv_obj->has_w()) { 00350 uvw_names_set.insert(uv_obj->get_name()); 00351 } 00352 if (uv_obj->has_tangent() && uv_obj->has_binormal()) { 00353 tbn_names_set.insert(uv_obj->get_name()); 00354 } 00355 } 00356 } 00357 00358 pset<string>::const_iterator si; 00359 for (si = uv_names_set.begin(); si != uv_names_set.end(); ++si) { 00360 uv_names.push_back(*si); 00361 } 00362 for (si = uvw_names_set.begin(); si != uvw_names_set.end(); ++si) { 00363 uvw_names.push_back(*si); 00364 } 00365 for (si = tbn_names_set.begin(); si != tbn_names_set.end(); ++si) { 00366 tbn_names.push_back(*si); 00367 } 00368 } 00369 00370 //////////////////////////////////////////////////////////////////// 00371 // Function: EggVertexPool::begin() 00372 // Access: Public 00373 // Description: Returns an iterator that can be used to traverse 00374 // through all the vertices in the pool. 00375 //////////////////////////////////////////////////////////////////// 00376 EggVertexPool::iterator EggVertexPool:: 00377 begin() const { 00378 nassertr(_index_vertices.size() == _unique_vertices.size(), 00379 iterator(_index_vertices.begin())); 00380 return iterator(_index_vertices.begin()); 00381 } 00382 00383 //////////////////////////////////////////////////////////////////// 00384 // Function: EggVertexPool::end() 00385 // Access: Public 00386 // Description: Returns an iterator that can be used to traverse 00387 // through all the vertices in the pool. 00388 //////////////////////////////////////////////////////////////////// 00389 EggVertexPool::iterator EggVertexPool:: 00390 end() const { 00391 return iterator(_index_vertices.end()); 00392 } 00393 00394 //////////////////////////////////////////////////////////////////// 00395 // Function: EggVertexPool::empty() 00396 // Access: Public 00397 // Description: Returns true if the pool is empty. 00398 //////////////////////////////////////////////////////////////////// 00399 bool EggVertexPool:: 00400 empty() const { 00401 return _index_vertices.empty(); 00402 } 00403 00404 //////////////////////////////////////////////////////////////////// 00405 // Function: EggVertexPool::size() 00406 // Access: Public 00407 // Description: Returns the number of vertices in the pool. 00408 //////////////////////////////////////////////////////////////////// 00409 EggVertexPool::size_type EggVertexPool:: 00410 size() const { 00411 nassertr(_index_vertices.size() == _unique_vertices.size(), 0); 00412 return _index_vertices.size(); 00413 } 00414 00415 //////////////////////////////////////////////////////////////////// 00416 // Function: EggVertexPool::add_vertex 00417 // Access: Public 00418 // Description: Adds the indicated vertex to the pool. It is an 00419 // error if the vertex is already a member of this or 00420 // any other pool. The vertex must have been allocated 00421 // from the free store; its pointer will now be owned by 00422 // the vertex pool. If the index number is supplied, 00423 // tries to assign that index number; it is an error if 00424 // the index number is already in use. 00425 // 00426 // It is possible that a forward reference to this 00427 // vertex was requested in the past; if so, the data 00428 // from the supplied vertex is copied onto the forward 00429 // reference, which becomes the actual vertex. In this 00430 // case, a different pointer is saved (and returned) 00431 // than the one actually passed in. In the usual case, 00432 // however, the vertex pointer passed in is the one that 00433 // is saved in the vertex pool and returned from this 00434 // method. 00435 //////////////////////////////////////////////////////////////////// 00436 EggVertex *EggVertexPool:: 00437 add_vertex(EggVertex *vertex, int index) { 00438 // Save a pointer to the vertex. 00439 PT(EggVertex) vertex_keep = vertex; 00440 00441 // Don't try to add a vertex while it still belongs to another pool. 00442 nassertr(vertex->_pool == NULL, NULL); 00443 00444 if (index == -1) { 00445 index = get_highest_index() + 1; 00446 } 00447 // Always supply an index number >= 0. 00448 nassertr(index >= 0, NULL); 00449 00450 // Check for a forward reference. 00451 IndexVertices::const_iterator ivi = _index_vertices.find(index); 00452 00453 if (ivi != _index_vertices.end()) { 00454 EggVertex *orig_vertex = (*ivi).second; 00455 if (orig_vertex->is_forward_reference() && 00456 !vertex->is_forward_reference()) { 00457 (*orig_vertex) = (*vertex); 00458 orig_vertex->_forward_reference = false; 00459 _highest_index = max(_highest_index, index); 00460 return orig_vertex; 00461 } 00462 00463 // Oops, you duplicated a vertex index. 00464 nassertr(false, NULL); 00465 } 00466 00467 _unique_vertices.insert(vertex); 00468 _index_vertices[index] = vertex; 00469 00470 if (!vertex->is_forward_reference()) { 00471 _highest_index = max(_highest_index, index); 00472 } 00473 00474 vertex->_pool = this; 00475 vertex->_index = index; 00476 00477 return vertex; 00478 } 00479 00480 00481 //////////////////////////////////////////////////////////////////// 00482 // Function: EggVertexPool::create_unique_vertex 00483 // Access: Public 00484 // Description: Creates a new vertex in the pool that is a copy of 00485 // the indicated one and returns it. If there is 00486 // already a vertex in the pool like the indicated one, 00487 // simply returns that one. 00488 //////////////////////////////////////////////////////////////////// 00489 EggVertex *EggVertexPool:: 00490 create_unique_vertex(const EggVertex ©) { 00491 UniqueVertices::iterator uvi; 00492 uvi = _unique_vertices.find((EggVertex *)©); 00493 00494 if (uvi != _unique_vertices.end()) { 00495 // There was already such a vertex. Return it. 00496 return (*uvi); 00497 } 00498 00499 // Create a new vertex. 00500 return add_vertex(new EggVertex(copy)); 00501 } 00502 00503 //////////////////////////////////////////////////////////////////// 00504 // Function: EggVertexPool::find_matching_vertex 00505 // Access: Public 00506 // Description: If the EggVertexPool already has a vertex matching 00507 // the indicated vertex, returns it; otherwise, returns 00508 // NULL. This is similar to create_unique_vertex() 00509 // except that a new vertex is never created. 00510 //////////////////////////////////////////////////////////////////// 00511 EggVertex *EggVertexPool:: 00512 find_matching_vertex(const EggVertex ©) { 00513 UniqueVertices::iterator uvi; 00514 uvi = _unique_vertices.find((EggVertex *)©); 00515 00516 if (uvi != _unique_vertices.end()) { 00517 // There was already such a vertex. Return it. 00518 return (*uvi); 00519 } 00520 00521 // No matching vertex. 00522 return NULL; 00523 } 00524 00525 00526 //////////////////////////////////////////////////////////////////// 00527 // Function: EggVertexPool::remove_vertex 00528 // Access: Public 00529 // Description: Removes the vertex from the pool. It is an error if 00530 // the vertex is not already a member of the pool. 00531 //////////////////////////////////////////////////////////////////// 00532 void EggVertexPool:: 00533 remove_vertex(EggVertex *vertex) { 00534 // Make sure the vertex is already a member of this pool. 00535 nassertv(vertex->_pool == this); 00536 00537 // Sanity check. Is the vertex actually in the pool? 00538 nassertv(get_vertex(vertex->_index) == vertex); 00539 00540 // Removing the vertex from the indexed list is simple. 00541 _index_vertices.erase(vertex->_index); 00542 00543 if (_highest_index == vertex->_index) { 00544 // Find the new highest vertex index. 00545 if (_index_vertices.empty()) { 00546 _highest_index = -1; 00547 } else { 00548 IndexVertices::reverse_iterator ivi = _index_vertices.rbegin(); 00549 while (ivi != _index_vertices.rend() && 00550 (*ivi).second->is_forward_reference()) { 00551 ++ivi; 00552 } 00553 if (ivi != _index_vertices.rend()) { 00554 _highest_index = (*ivi).first; 00555 } else { 00556 _highest_index = -1; 00557 } 00558 } 00559 } 00560 00561 // Removing the vertex from the unique list is a bit trickier--there 00562 // might be several other vertices that are considered identical to 00563 // this one, and so we have to walk through all the identical 00564 // vertices until we find the right one. 00565 UniqueVertices::iterator uvi; 00566 uvi = _unique_vertices.find(vertex); 00567 00568 // Sanity check. Is the vertex actually in the pool? 00569 nassertv(uvi != _unique_vertices.end()); 00570 00571 while ((*uvi) != vertex) { 00572 ++uvi; 00573 // Sanity check. Is the vertex actually in the pool? 00574 nassertv(uvi != _unique_vertices.end()); 00575 } 00576 00577 _unique_vertices.erase(uvi); 00578 00579 vertex->_pool = NULL; 00580 } 00581 00582 //////////////////////////////////////////////////////////////////// 00583 // Function: EggVertexPool::remove_unused_vertices 00584 // Access: Public 00585 // Description: Removes all vertices from the pool that are not 00586 // referenced by at least one primitive. Also collapses 00587 // together equivalent vertices, and renumbers all 00588 // vertices after the operation so their indices are 00589 // consecutive, beginning at zero. Returns the number 00590 // of vertices removed. 00591 //////////////////////////////////////////////////////////////////// 00592 int EggVertexPool:: 00593 remove_unused_vertices() { 00594 int num_removed = 0; 00595 00596 UniqueVertices new_unique_vertices; 00597 IndexVertices new_index_vertices; 00598 00599 IndexVertices::const_iterator ivi; 00600 for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { 00601 EggVertex *vertex = (*ivi).second; 00602 if (vertex->pref_size() == 0) { 00603 // This vertex is not used. Don't add it to the new lists. 00604 vertex->clear_grefs(); 00605 vertex->_pool = NULL; 00606 num_removed++; 00607 00608 } else { 00609 // The vertex *is* used somewhere. Is it identical to an 00610 // existing vertex? 00611 UniqueVertices::iterator uvi; 00612 uvi = new_unique_vertices.find(vertex); 00613 if (uvi != new_unique_vertices.end()) { 00614 // Yes, there's already another vertex just like this one. 00615 // Redirect all the primitives currently referencing this 00616 // vertex to reference the other one instead. 00617 EggVertex *orig_vertex = (*uvi); 00618 00619 EggVertex::PrimitiveRef pref = vertex->_pref; 00620 EggVertex::PrimitiveRef::iterator pi; 00621 for (pi = pref.begin(); pi != pref.end(); ++pi) { 00622 EggPrimitive *prim = (*pi); 00623 EggPrimitive::iterator pvi = prim->find(vertex); 00624 nassertr(pvi != prim->end(), 0); 00625 prim->replace(pvi, orig_vertex); 00626 } 00627 vertex->test_pref_integrity(); 00628 orig_vertex->test_pref_integrity(); 00629 nassertr(vertex->pref_size() == 0, 0); 00630 vertex->clear_grefs(); 00631 vertex->_pool = NULL; 00632 num_removed++; 00633 00634 } else { 00635 // It's a unique vertex. Renumber it and add it to the new 00636 // lists. 00637 vertex->_index = new_index_vertices.size(); 00638 new_index_vertices.insert(IndexVertices::value_type(vertex->_index, vertex)); 00639 new_unique_vertices.insert(vertex); 00640 } 00641 } 00642 } 00643 00644 // All done. Lose the old lists. 00645 _unique_vertices.swap(new_unique_vertices); 00646 _index_vertices.swap(new_index_vertices); 00647 _highest_index = (int)_index_vertices.size() - 1; 00648 00649 nassertr(_index_vertices.size() == _unique_vertices.size(), num_removed); 00650 00651 return num_removed; 00652 } 00653 00654 // A function object for split_vertex(), used in transform(), below. 00655 class IsLocalVertexSplitter { 00656 public: 00657 int operator () (const EggPrimitive *prim) const { 00658 return (prim->is_local_coord() ? 1 : 0); 00659 } 00660 }; 00661 00662 //////////////////////////////////////////////////////////////////// 00663 // Function: EggVertexPool::transform 00664 // Access: Public 00665 // Description: Applies the indicated transformation matrix to all 00666 // the vertices. However, vertices that are attached to 00667 // primitives that believe their vertices are in a local 00668 // coordinate system are transformed only by the scale 00669 // and rotation component. If a vertex happens to be 00670 // attached both to a local and a global primitive, and 00671 // the transformation includes a translation component, 00672 // the vertex will be split. 00673 //////////////////////////////////////////////////////////////////// 00674 void EggVertexPool:: 00675 transform(const LMatrix4d &mat) { 00676 LVector3d translation = mat.get_row3(3); 00677 00678 if (translation == LVector3d(0.0, 0.0, 0.0)) { 00679 // If the matrix does not have a translation component, we can 00680 // treat the local and global vertices the same. This makes 00681 // things much easier. 00682 iterator i; 00683 for (i = begin(); i != end(); ++i) { 00684 EggVertex *vert = *i; 00685 vert->transform(mat); 00686 } 00687 00688 } else { 00689 // The matrix does have a translation component. That means we 00690 // have to treat the global and local vertices differently. 00691 // Yucky. 00692 00693 // First, transform the global vertices. Get a copy of the list 00694 // of vertices in this pool. We must have a copy because we might 00695 // be modifying the list as we traverse it. 00696 00697 typedef pvector<EggVertex *> Verts; 00698 Verts verts; 00699 verts.reserve(size()); 00700 copy(begin(), end(), back_inserter(verts)); 00701 00702 Verts::const_iterator vi; 00703 for (vi = verts.begin(); vi != verts.end(); ++vi) { 00704 EggVertex *vert = *vi; 00705 int num_local_coord = vert->get_num_local_coord(); 00706 int num_global_coord = vert->get_num_global_coord(); 00707 00708 if (num_global_coord != 0) { 00709 // This vertex will be transformed. 00710 if (num_local_coord != 0) { 00711 // It also needs to be split! Yuck. 00712 split_vertex(vert, IsLocalVertexSplitter()); 00713 } 00714 00715 vert->transform(mat); 00716 } 00717 } 00718 00719 // Now transform the local vertices. We can walk through the list 00720 // directly now, because we won't be modifying the list this time. 00721 LMatrix4d local_mat = mat; 00722 local_mat.set_row(3, LVector3d(0.0, 0.0, 0.0)); 00723 00724 iterator i; 00725 for (i = begin(); i != end(); ++i) { 00726 EggVertex *vert = *i; 00727 if (vert->get_num_local_coord() != 0) { 00728 00729 // This should be guaranteed by the vertex-splitting logic 00730 // above. 00731 nassertv(vert->get_num_global_coord() == 0); 00732 vert->transform(local_mat); 00733 } 00734 } 00735 } 00736 } 00737 00738 00739 //////////////////////////////////////////////////////////////////// 00740 // Function: EggVertexPool::write 00741 // Access: Public 00742 // Description: Writes the vertex pool to the indicated output stream 00743 // in Egg format. 00744 //////////////////////////////////////////////////////////////////// 00745 void EggVertexPool:: 00746 write(ostream &out, int indent_level) const { 00747 write_header(out, indent_level, "<VertexPool>"); 00748 00749 iterator i; 00750 for (i = begin(); i != end(); ++i) { 00751 (*i)->write(out, indent_level+2); 00752 } 00753 00754 indent(out, indent_level) 00755 << "}\n"; 00756 } 00757 00758 00759 //////////////////////////////////////////////////////////////////// 00760 // Function: EggVertexPool::r_transform 00761 // Access: Protected, Virtual 00762 // Description: This is called from within the egg code by 00763 // transform(). It applies a transformation matrix 00764 // to the current node in some sensible way, then 00765 // continues down the tree. 00766 // 00767 // The first matrix is the transformation to apply; the 00768 // second is its inverse. The third parameter is the 00769 // coordinate system we are changing to, or CS_default 00770 // if we are not changing coordinate systems. 00771 //////////////////////////////////////////////////////////////////// 00772 void EggVertexPool:: 00773 r_transform(const LMatrix4d &mat, const LMatrix4d &, CoordinateSystem) { 00774 } 00775 00776 //////////////////////////////////////////////////////////////////// 00777 // Function: EggVertexPool::r_transform_vertices 00778 // Access: Protected, Virtual 00779 // Description: This is called from within the egg code by 00780 // transform_vertices_only()(). It applies a 00781 // transformation matrix to the current node in some 00782 // sensible way (if the current node is a vertex pool 00783 // with vertices), then continues down the tree. 00784 //////////////////////////////////////////////////////////////////// 00785 void EggVertexPool:: 00786 r_transform_vertices(const LMatrix4d &mat) { 00787 transform(mat); 00788 }