00001 // Filename: eggPrimitive.cxx 00002 // Created by: drose (16Jan99) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 #include "eggPrimitive.h" 00020 #include "eggVertexPool.h" 00021 #include "eggMiscFuncs.h" 00022 #include "eggTextureCollection.h" 00023 #include "lexerDefs.h" 00024 00025 #include <indent.h> 00026 #include <vector_int.h> 00027 00028 TypeHandle EggPrimitive::_type_handle; 00029 00030 00031 //////////////////////////////////////////////////////////////////// 00032 // Function: EggPrimitive::determine_alpha_mode 00033 // Access: Public, Virtual 00034 // Description: Walks back up the hierarchy, looking for an EggPrimitive 00035 // or EggPrimitive or some such object at this level or 00036 // above this primitive that has an alpha_mode other than 00037 // AM_unspecified. Returns a valid EggRenderMode pointer 00038 // if one is found, or NULL otherwise. 00039 //////////////////////////////////////////////////////////////////// 00040 EggRenderMode *EggPrimitive:: 00041 determine_alpha_mode() { 00042 if (get_alpha_mode() != AM_unspecified) { 00043 return this; 00044 } 00045 00046 EggRenderMode *result = EggNode::determine_alpha_mode(); 00047 if (result == (EggRenderMode *)NULL) { 00048 if (has_texture() && get_texture()->get_alpha_mode() != AM_unspecified) { 00049 result = get_texture(); 00050 } 00051 } 00052 return result; 00053 } 00054 00055 //////////////////////////////////////////////////////////////////// 00056 // Function: EggPrimitive::determine_depth_write_mode 00057 // Access: Public, Virtual 00058 // Description: Walks back up the hierarchy, looking for an EggGroup 00059 // or EggPrimitive or some such object at this level or 00060 // above this node that has a depth_write_mode other than 00061 // DWM_unspecified. Returns a valid EggRenderMode pointer 00062 // if one is found, or NULL otherwise. 00063 //////////////////////////////////////////////////////////////////// 00064 EggRenderMode *EggPrimitive:: 00065 determine_depth_write_mode() { 00066 if (get_depth_write_mode() != DWM_unspecified) { 00067 return this; 00068 } 00069 00070 EggRenderMode *result = EggNode::determine_depth_write_mode(); 00071 if (result == (EggRenderMode *)NULL) { 00072 if (has_texture() && 00073 get_texture()->get_depth_write_mode() != DWM_unspecified) { 00074 result = get_texture(); 00075 } 00076 } 00077 return result; 00078 } 00079 00080 //////////////////////////////////////////////////////////////////// 00081 // Function: EggPrimitive::determine_depth_test_mode 00082 // Access: Public, Virtual 00083 // Description: Walks back up the hierarchy, looking for an EggGroup 00084 // or EggPrimitive or some such object at this level or 00085 // above this node that has a depth_test_mode other than 00086 // DTM_unspecified. Returns a valid EggRenderMode pointer 00087 // if one is found, or NULL otherwise. 00088 //////////////////////////////////////////////////////////////////// 00089 EggRenderMode *EggPrimitive:: 00090 determine_depth_test_mode() { 00091 if (get_depth_test_mode() != DTM_unspecified) { 00092 return this; 00093 } 00094 00095 EggRenderMode *result = EggNode::determine_depth_test_mode(); 00096 if (result == (EggRenderMode *)NULL) { 00097 if (has_texture() && 00098 get_texture()->get_depth_test_mode() != DTM_unspecified) { 00099 result = get_texture(); 00100 } 00101 } 00102 return result; 00103 } 00104 00105 //////////////////////////////////////////////////////////////////// 00106 // Function: EggPrimitive::determine_draw_order 00107 // Access: Public, Virtual 00108 // Description: Walks back up the hierarchy, looking for an EggPrimitive 00109 // or EggPrimitive or some such object at this level or 00110 // above this primitive that has a draw_order specified. 00111 // Returns a valid EggRenderMode pointer if one is found, 00112 // or NULL otherwise. 00113 //////////////////////////////////////////////////////////////////// 00114 EggRenderMode *EggPrimitive:: 00115 determine_draw_order() { 00116 if (has_draw_order()) { 00117 return this; 00118 } 00119 00120 EggRenderMode *result = EggNode::determine_draw_order(); 00121 if (result == (EggRenderMode *)NULL) { 00122 if (has_texture() && get_texture()->has_draw_order()) { 00123 result = get_texture(); 00124 } 00125 } 00126 return result; 00127 } 00128 00129 //////////////////////////////////////////////////////////////////// 00130 // Function: EggPrimitive::determine_bin 00131 // Access: Public, Virtual 00132 // Description: Walks back up the hierarchy, looking for an EggPrimitive 00133 // or EggPrimitive or some such object at this level or 00134 // above this primitive that has a bin specified. Returns a 00135 // valid EggRenderMode pointer if one is found, or NULL 00136 // otherwise. 00137 //////////////////////////////////////////////////////////////////// 00138 EggRenderMode *EggPrimitive:: 00139 determine_bin() { 00140 if (has_bin()) { 00141 return this; 00142 } 00143 00144 EggRenderMode *result = EggNode::determine_bin(); 00145 if (result == (EggRenderMode *)NULL) { 00146 if (has_texture() && get_texture()->has_bin()) { 00147 result = get_texture(); 00148 } 00149 } 00150 return result; 00151 } 00152 00153 //////////////////////////////////////////////////////////////////// 00154 // Function: EggPrimitive::has_vertex_normal 00155 // Access: Public 00156 // Description: Returns true if any vertex on the primitive has a 00157 // specific normal set, false otherwise. 00158 //////////////////////////////////////////////////////////////////// 00159 bool EggPrimitive:: 00160 has_vertex_normal() const { 00161 Vertices::const_iterator vi; 00162 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) { 00163 if ((*vi)->has_normal()) { 00164 return true; 00165 } 00166 } 00167 return false; 00168 } 00169 00170 //////////////////////////////////////////////////////////////////// 00171 // Function: EggPrimitive::has_vertex_color 00172 // Access: Public 00173 // Description: Returns true if any vertex on the primitive has a 00174 // specific color set, false otherwise. 00175 //////////////////////////////////////////////////////////////////// 00176 bool EggPrimitive:: 00177 has_vertex_color() const { 00178 Vertices::const_iterator vi; 00179 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) { 00180 if ((*vi)->has_color()) { 00181 return true; 00182 } 00183 } 00184 return false; 00185 } 00186 00187 //////////////////////////////////////////////////////////////////// 00188 // Function: EggPrimitive::reverse_vertex_ordering 00189 // Access: Public, Virtual 00190 // Description: Reverses the ordering of the vertices in this 00191 // primitive, if appropriate, in order to change the 00192 // direction the polygon appears to be facing. Does not 00193 // adjust the surface normal, if any. 00194 //////////////////////////////////////////////////////////////////// 00195 void EggPrimitive:: 00196 reverse_vertex_ordering() { 00197 // This really only makes sense for polygons. Lights don't care 00198 // about vertex ordering, and NURBS surfaces have to do a bit more 00199 // work in addition to this. 00200 reverse(_vertices.begin(), _vertices.end()); 00201 } 00202 00203 //////////////////////////////////////////////////////////////////// 00204 // Function: EggPrimitive::cleanup 00205 // Access: Public, Virtual 00206 // Description: Cleans up modeling errors in whatever context this 00207 // makes sense. For instance, for a polygon, this calls 00208 // remove_doubled_verts(true). For a point, it calls 00209 // remove_nonunique_verts(). Returns true if the 00210 // primitive is valid, or false if it is degenerate. 00211 //////////////////////////////////////////////////////////////////// 00212 bool EggPrimitive:: 00213 cleanup() { 00214 return !empty(); 00215 } 00216 00217 //////////////////////////////////////////////////////////////////// 00218 // Function: EggPrimitive::remove_doubled_verts 00219 // Access: Public 00220 // Description: Certain kinds of primitives, particularly polygons, 00221 // don't like to have the same vertex repeated 00222 // consecutively. Unfortunately, some modeling programs 00223 // (like MultiGen) make this an easy mistake to make. 00224 // 00225 // It's handy to have a function to remove these 00226 // redundant vertices. If closed is true, it also 00227 // checks that the first and last vertices are not the 00228 // same. 00229 // 00230 // This function identifies repeated vertices by pointer 00231 // only; it does not remove consecutive equivalent but 00232 // different vertices. 00233 //////////////////////////////////////////////////////////////////// 00234 void EggPrimitive:: 00235 remove_doubled_verts(bool closed) { 00236 if (!_vertices.empty()) { 00237 Vertices new_vertices; 00238 Vertices::iterator vi, vlast; 00239 vi = _vertices.begin(); 00240 new_vertices.push_back(*vi); 00241 00242 vlast = vi; 00243 ++vi; 00244 while (vi != _vertices.end()) { 00245 if ((*vi) != (*vlast)) { 00246 new_vertices.push_back(*vi); 00247 } else { 00248 prepare_remove_vertex(*vi); 00249 } 00250 vlast = vi; 00251 ++vi; 00252 } 00253 _vertices.swap(new_vertices); 00254 } 00255 00256 if (closed) { 00257 // Then, if this is a polygon (which will be closed anyway), 00258 // remove the vertex from the end if it's a repeat of the 00259 // beginning. 00260 while (_vertices.size() > 1 && _vertices.back() == _vertices.front()) { 00261 prepare_remove_vertex(_vertices.back()); 00262 _vertices.pop_back(); 00263 } 00264 } 00265 } 00266 00267 //////////////////////////////////////////////////////////////////// 00268 // Function: EggPrimitive::remove_nonunique_verts 00269 // Access: Public 00270 // Description: Removes any multiple appearances of the same vertex 00271 // from the primitive. This primarily makes sense for a 00272 // point primitive, which is really a collection of 00273 // points and which doesn't make sense to include the 00274 // same point twice, in any order. 00275 //////////////////////////////////////////////////////////////////// 00276 void EggPrimitive:: 00277 remove_nonunique_verts() { 00278 Vertices::iterator vi, vj; 00279 Vertices new_vertices; 00280 00281 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) { 00282 bool okflag = true; 00283 for (vj = _vertices.begin(); vj != vi && okflag; ++vj) { 00284 okflag = ((*vi) != (*vj)); 00285 } 00286 if (okflag) { 00287 new_vertices.push_back(*vi); 00288 } else { 00289 prepare_remove_vertex(*vi); 00290 } 00291 } 00292 00293 _vertices.swap(new_vertices); 00294 } 00295 00296 00297 //////////////////////////////////////////////////////////////////// 00298 // Function: EggPrimitive::erase 00299 // Access: Public 00300 // Description: Part of the implementaion of the EggPrimitive as an 00301 // STL container. Most of the rest of these functions 00302 // are inline and declared in EggPrimitive.I. 00303 //////////////////////////////////////////////////////////////////// 00304 EggPrimitive::iterator EggPrimitive:: 00305 erase(iterator first, iterator last) { 00306 iterator i; 00307 for (i = first; i != last; ++i) { 00308 prepare_remove_vertex(*i); 00309 } 00310 iterator result = _vertices.erase((Vertices::iterator &)first, 00311 (Vertices::iterator &)last); 00312 test_vref_integrity(); 00313 return result; 00314 } 00315 00316 00317 //////////////////////////////////////////////////////////////////// 00318 // Function: EggPrimitive::add_vertex 00319 // Access: Public 00320 // Description: Adds the indicated vertex to the end of the 00321 // primitive's list of vertices, and returns it. 00322 //////////////////////////////////////////////////////////////////// 00323 EggVertex *EggPrimitive:: 00324 add_vertex(EggVertex *vertex) { 00325 prepare_add_vertex(vertex); 00326 _vertices.push_back(vertex); 00327 00328 vertex->test_pref_integrity(); 00329 test_vref_integrity(); 00330 00331 return vertex; 00332 } 00333 00334 //////////////////////////////////////////////////////////////////// 00335 // Function: EggPrimitive::remove_vertex 00336 // Access: Public 00337 // Description: Removes the indicated vertex vertex from the 00338 // primitive and returns it. If the vertex was not 00339 // already in the primitive, does nothing and returns 00340 // NULL. 00341 //////////////////////////////////////////////////////////////////// 00342 EggVertex *EggPrimitive:: 00343 remove_vertex(EggVertex *vertex) { 00344 PT_EggVertex vpt = vertex; 00345 iterator i = find(begin(), end(), vpt); 00346 if (i == end()) { 00347 return PT_EggVertex(); 00348 } else { 00349 // erase() calls prepare_remove_vertex(). 00350 erase(i); 00351 00352 vertex->test_pref_integrity(); 00353 test_vref_integrity(); 00354 00355 return vertex; 00356 } 00357 } 00358 00359 00360 //////////////////////////////////////////////////////////////////// 00361 // Function: EggPrimitive::copy_vertices 00362 // Access: Public 00363 // Description: Replaces the current primitive's list of vertices 00364 // with a copy of the list of vertices on the other 00365 // primitive. 00366 //////////////////////////////////////////////////////////////////// 00367 void EggPrimitive:: 00368 copy_vertices(const EggPrimitive &other) { 00369 clear(); 00370 _vertices.reserve(other.size()); 00371 00372 iterator vi; 00373 for (vi = other.begin(); vi != other.end(); ++vi) { 00374 add_vertex(*vi); 00375 } 00376 00377 test_vref_integrity(); 00378 other.test_vref_integrity(); 00379 } 00380 00381 #ifndef NDEBUG 00382 00383 //////////////////////////////////////////////////////////////////// 00384 // Function: EggPrimitive::test_vref_integrity 00385 // Access: Public 00386 // Description: Verifies that each vertex in the primitive exists and 00387 // that it knows it is referenced by the primitive. 00388 //////////////////////////////////////////////////////////////////// 00389 void EggPrimitive:: 00390 test_vref_integrity() const { 00391 test_ref_count_integrity(); 00392 00393 // First, we need to know how many times each vertex appears. 00394 // Usually, this will be only one, but it's possible for a vertex to 00395 // appear more than once. 00396 typedef pmap<const EggVertex *, int> VertexCount; 00397 VertexCount _count; 00398 00399 // Now count up the vertices. 00400 iterator vi; 00401 for (vi = begin(); vi != end(); ++vi) { 00402 const EggVertex *vert = *vi; 00403 vert->test_ref_count_integrity(); 00404 00405 VertexCount::iterator vci = _count.find(vert); 00406 if (vci == _count.end()) { 00407 _count[vert] = 1; 00408 } else { 00409 (*vci).second++; 00410 } 00411 } 00412 00413 // Ok, now walk through the vertices found and make sure the vertex 00414 // has the proper number of entries of this primitive in its pref. 00415 VertexCount::iterator vci; 00416 for (vci = _count.begin(); vci != _count.end(); ++vci) { 00417 const EggVertex *vert = (*vci).first; 00418 00419 int count = (*vci).second; 00420 int vert_count = vert->has_pref(this); 00421 00422 nassertv(count == vert_count); 00423 } 00424 } 00425 00426 #endif // NDEBUG 00427 00428 //////////////////////////////////////////////////////////////////// 00429 // Function: EggPrimitive::prepare_add_vertex 00430 // Access: Private 00431 // Description: Marks the vertex as belonging to the primitive. This 00432 // is an internal function called by the STL-like 00433 // functions push_back() and insert(), in preparation 00434 // for actually adding the vertex. 00435 //////////////////////////////////////////////////////////////////// 00436 void EggPrimitive:: 00437 prepare_add_vertex(EggVertex *vertex) { 00438 // We can't test integrity within this function, because it might be 00439 // called when the primitive is in an incomplete state. 00440 00441 // The vertex must have the same vertex pool as the vertices already 00442 // added. 00443 nassertv(empty() || vertex->get_pool() == get_pool()); 00444 00445 // Since a given vertex might appear more than once in a particular 00446 // primitive, we can't conclude anything about data integrity by 00447 // inspecting the return value of insert(). (In fact, the vertex's 00448 // pref is a multiset, so the insert() will always succeed.) 00449 00450 vertex->_pref.insert(this); 00451 } 00452 00453 00454 //////////////////////////////////////////////////////////////////// 00455 // Function: EggPrimitive::prepare_remove_vertex 00456 // Access: Private 00457 // Description: Marks the vertex as removed from the primitive. This 00458 // is an internal function called by the STL-like 00459 // functions pop_back() and erase(), in preparation for 00460 // actually doing the removal. 00461 // 00462 // It is an error to attempt to remove a vertex that is 00463 // not already a vertex of this primitive. 00464 //////////////////////////////////////////////////////////////////// 00465 void EggPrimitive:: 00466 prepare_remove_vertex(EggVertex *vertex) { 00467 // We can't test integrity within this function, because it might be 00468 // called when the primitive is in an incomplete state. 00469 00470 // Now we must remove the primitive from the vertex's pref. We 00471 // can't just use the simple erase() function, since that will 00472 // remove all instances of this primitive from the pref; instead, we 00473 // must find one instance and remove that. 00474 00475 EggVertex::PrimitiveRef::iterator pri = vertex->_pref.find(this); 00476 00477 // We should have found the primitive in the vertex's pref. If we 00478 // did not, something's out of sync internally. 00479 nassertv(pri != vertex->_pref.end()); 00480 00481 vertex->_pref.erase(pri); 00482 } 00483 00484 //////////////////////////////////////////////////////////////////// 00485 // Function: EggPrimitive::write_body 00486 // Access: Protected 00487 // Description: Writes the attributes and the vertices referenced by 00488 // the primitive to the indicated output stream in Egg 00489 // format. 00490 //////////////////////////////////////////////////////////////////// 00491 void EggPrimitive:: 00492 write_body(ostream &out, int indent_level) const { 00493 test_vref_integrity(); 00494 00495 EggAttributes::write(out, indent_level); 00496 EggRenderMode::write(out, indent_level); 00497 00498 if (has_texture()) { 00499 EggTexture *texture = get_texture(); 00500 00501 // Make sure the texture is named. 00502 nassertv(texture->has_name()); 00503 00504 indent(out, indent_level) << "<TRef> { "; 00505 enquote_string(out, texture->get_name()) 00506 << " }\n"; 00507 } 00508 00509 if (has_material()) { 00510 EggMaterial *material = get_material(); 00511 00512 // Make sure the material is named. 00513 nassertv(material->has_name()); 00514 00515 indent(out, indent_level) << "<MRef> { "; 00516 enquote_string(out, material->get_name()) 00517 << " }\n"; 00518 } 00519 00520 if (get_bface_flag()) { 00521 indent(out, indent_level) << "<BFace> { 1 }\n"; 00522 } 00523 00524 if (!empty()) { 00525 EggVertexPool *pool = get_pool(); 00526 00527 // Make sure the vertices belong to some vertex pool. 00528 nassertv(pool != NULL); 00529 00530 // Make sure the vertex pool is named. 00531 nassertv(pool->has_name()); 00532 00533 if ((int)size() < 10) { 00534 // A simple primitive gets all its vertex indices written on one 00535 // line. 00536 indent(out, indent_level) << "<VertexRef> {"; 00537 const_iterator i; 00538 for (i = begin(); i != end(); ++i) { 00539 EggVertex *vert = *i; 00540 vert->test_pref_integrity(); 00541 00542 // Make sure each vertex belongs to the same pool. 00543 nassertv(vert->get_pool() == pool); 00544 00545 out << " " << vert->get_index(); 00546 } 00547 out << " <Ref> { "; 00548 enquote_string(out, pool->get_name()) << " } }\n"; 00549 00550 } else { 00551 00552 // A larger primitive gets its vertex indices written as 00553 // multiple lines. 00554 vector_int indices; 00555 const_iterator i; 00556 for (i = begin(); i != end(); ++i) { 00557 EggVertex *vert = *i; 00558 vert->test_pref_integrity(); 00559 00560 // Make sure each vertex belongs to the same pool. 00561 nassertv(vert->get_pool() == pool); 00562 00563 indices.push_back(vert->get_index()); 00564 } 00565 00566 indent(out, indent_level) << "<VertexRef> {\n"; 00567 write_long_list(out, indent_level+2, indices.begin(), indices.end(), 00568 "", "", 72); 00569 indent(out, indent_level+2) << "<Ref> { "; 00570 enquote_string(out, pool->get_name()) << " }\n"; 00571 indent(out, indent_level) << "}\n"; 00572 } 00573 } 00574 } 00575 00576 //////////////////////////////////////////////////////////////////// 00577 // Function: EggPrimitive::egg_start_parse_body 00578 // Access: Protected, Virtual 00579 // Description: This function is called within parse_egg(). It 00580 // should call the appropriate function on the lexer to 00581 // initialize the parser into the state associated with 00582 // this object. If the object cannot be parsed into 00583 // directly, it should return false. 00584 //////////////////////////////////////////////////////////////////// 00585 bool EggPrimitive:: 00586 egg_start_parse_body() { 00587 egg_start_primitive_body(); 00588 return true; 00589 } 00590 00591 //////////////////////////////////////////////////////////////////// 00592 // Function: EggPrimitive::r_transform 00593 // Access: Protected, Virtual 00594 // Description: This is called from within the egg code by 00595 // transform(). It applies a transformation matrix 00596 // to the current node in some sensible way, then 00597 // continues down the tree. 00598 // 00599 // The first matrix is the transformation to apply; the 00600 // second is its inverse. The third parameter is the 00601 // coordinate system we are changing to, or CS_default 00602 // if we are not changing coordinate systems. 00603 //////////////////////////////////////////////////////////////////// 00604 void EggPrimitive:: 00605 r_transform(const LMatrix4d &mat, const LMatrix4d &, CoordinateSystem) { 00606 EggAttributes::transform(mat); 00607 } 00608 00609 //////////////////////////////////////////////////////////////////// 00610 // Function: EggPrimitive::r_flatten_transforms 00611 // Access: Protected, Virtual 00612 // Description: The recursive implementation of flatten_transforms(). 00613 //////////////////////////////////////////////////////////////////// 00614 void EggPrimitive:: 00615 r_flatten_transforms() { 00616 if (is_local_coord()) { 00617 LMatrix4d mat = get_vertex_frame(); 00618 EggAttributes::transform(mat); 00619 00620 // Transform each vertex by duplicating it in the vertex pool. 00621 size_t num_vertices = size(); 00622 for (size_t i = 0; i < num_vertices; i++) { 00623 EggVertex *vertex = get_vertex(i); 00624 EggVertexPool *pool = vertex->get_pool(); 00625 00626 EggVertex new_vertex(*vertex); 00627 new_vertex.transform(mat); 00628 EggVertex *unique = pool->create_unique_vertex(new_vertex); 00629 unique->copy_grefs_from(*vertex); 00630 00631 set_vertex(i, unique); 00632 } 00633 } 00634 } 00635 00636 //////////////////////////////////////////////////////////////////// 00637 // Function: EggPrimitive::r_apply_texmats 00638 // Access: Protected, Virtual 00639 // Description: The recursive implementation of apply_texmats(). 00640 //////////////////////////////////////////////////////////////////// 00641 void EggPrimitive:: 00642 r_apply_texmats(EggTextureCollection &textures) { 00643 if (has_texture()) { 00644 EggTexture *texture = get_texture(); 00645 if (texture->has_transform()) { 00646 if (texture->transform_is_identity()) { 00647 // Now, what's the point of a texture with an identity 00648 // transform? 00649 texture->clear_transform(); 00650 return; 00651 } 00652 00653 // We've got a texture with a matrix applied. Save the matrix, 00654 // and get a new texture without the matrix. 00655 LMatrix3d mat = texture->get_transform(); 00656 EggTexture new_texture(*texture); 00657 new_texture.clear_transform(); 00658 EggTexture *unique = textures.create_unique_texture(new_texture, ~0); 00659 00660 set_texture(unique); 00661 00662 // Now apply the matrix to the vertex UV's. Create new vertices 00663 // as necessary. 00664 size_t num_vertices = size(); 00665 for (size_t i = 0; i < num_vertices; i++) { 00666 EggVertex *vertex = get_vertex(i); 00667 00668 if (vertex->has_uv()) { 00669 EggVertexPool *pool = vertex->get_pool(); 00670 00671 EggVertex new_vertex(*vertex); 00672 new_vertex.set_uv(vertex->get_uv() * mat); 00673 EggVertex *unique = pool->create_unique_vertex(new_vertex); 00674 unique->copy_grefs_from(*vertex); 00675 00676 set_vertex(i, unique); 00677 } 00678 } 00679 } 00680 } 00681 }