Panda3D
|
00001 // Filename: eggPrimitive.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 "eggPrimitive.h" 00016 #include "eggVertexPool.h" 00017 #include "eggMiscFuncs.h" 00018 #include "eggTextureCollection.h" 00019 #include "lexerDefs.h" 00020 #include "config_egg.h" 00021 00022 #include "indent.h" 00023 #include "vector_int.h" 00024 00025 TypeHandle EggPrimitive::_type_handle; 00026 00027 00028 //////////////////////////////////////////////////////////////////// 00029 // Function: EggPrimitive::determine_alpha_mode 00030 // Access: Published, Virtual 00031 // Description: Walks back up the hierarchy, looking for an EggGroup 00032 // or EggPrimitive or some such object at this level or 00033 // above this primitive that has an alpha_mode other than 00034 // AM_unspecified. Returns a valid EggRenderMode pointer 00035 // if one is found, or NULL otherwise. 00036 //////////////////////////////////////////////////////////////////// 00037 EggRenderMode *EggPrimitive:: 00038 determine_alpha_mode() { 00039 if (get_alpha_mode() != AM_unspecified) { 00040 return this; 00041 } 00042 00043 EggRenderMode *result = EggNode::determine_alpha_mode(); 00044 if (result == (EggRenderMode *)NULL) { 00045 int num_textures = get_num_textures(); 00046 for (int i = 0; i < num_textures && result == (EggRenderMode *)NULL; i++) { 00047 EggTexture *egg_tex = get_texture(i); 00048 00049 // We only want to consider the alpha mode on those textures 00050 // that can affect the transparency of the polygon. This 00051 // mostly depends on the envtype flag. 00052 if (egg_tex->affects_polygon_alpha()) { 00053 // This texture might affect the polygon alpha, so it gets to 00054 // decide the polygon transparency mode. 00055 if (egg_tex->get_alpha_mode() != AM_unspecified) { 00056 result = get_texture(i); 00057 } 00058 } 00059 } 00060 } 00061 return result; 00062 } 00063 00064 //////////////////////////////////////////////////////////////////// 00065 // Function: EggPrimitive::determine_depth_write_mode 00066 // Access: Published, Virtual 00067 // Description: Walks back up the hierarchy, looking for an EggGroup 00068 // or EggPrimitive or some such object at this level or 00069 // above this node that has a depth_write_mode other than 00070 // DWM_unspecified. Returns a valid EggRenderMode pointer 00071 // if one is found, or NULL otherwise. 00072 //////////////////////////////////////////////////////////////////// 00073 EggRenderMode *EggPrimitive:: 00074 determine_depth_write_mode() { 00075 if (get_depth_write_mode() != DWM_unspecified) { 00076 return this; 00077 } 00078 00079 EggRenderMode *result = EggNode::determine_depth_write_mode(); 00080 if (result == (EggRenderMode *)NULL) { 00081 int num_textures = get_num_textures(); 00082 for (int i = 0; i < num_textures && result == (EggRenderMode *)NULL; i++) { 00083 if (get_texture(i)->get_depth_write_mode() != DWM_unspecified) { 00084 result = get_texture(i); 00085 } 00086 } 00087 } 00088 return result; 00089 } 00090 00091 //////////////////////////////////////////////////////////////////// 00092 // Function: EggPrimitive::determine_depth_test_mode 00093 // Access: Published, Virtual 00094 // Description: Walks back up the hierarchy, looking for an EggGroup 00095 // or EggPrimitive or some such object at this level or 00096 // above this node that has a depth_test_mode other than 00097 // DTM_unspecified. Returns a valid EggRenderMode pointer 00098 // if one is found, or NULL otherwise. 00099 //////////////////////////////////////////////////////////////////// 00100 EggRenderMode *EggPrimitive:: 00101 determine_depth_test_mode() { 00102 if (get_depth_test_mode() != DTM_unspecified) { 00103 return this; 00104 } 00105 00106 EggRenderMode *result = EggNode::determine_depth_test_mode(); 00107 if (result == (EggRenderMode *)NULL) { 00108 int num_textures = get_num_textures(); 00109 for (int i = 0; i < num_textures && result == (EggRenderMode *)NULL; i++) { 00110 if (get_texture(i)->get_depth_test_mode() != DTM_unspecified) { 00111 result = get_texture(i); 00112 } 00113 } 00114 } 00115 return result; 00116 } 00117 00118 //////////////////////////////////////////////////////////////////// 00119 // Function: EggPrimitive::determine_visibility_mode 00120 // Access: Published, Virtual 00121 // Description: Walks back up the hierarchy, looking for an EggGroup 00122 // or EggPrimitive or some such object at this level or 00123 // above this node that has a visibility_mode other than 00124 // VM_unspecified. Returns a valid EggRenderMode pointer 00125 // if one is found, or NULL otherwise. 00126 //////////////////////////////////////////////////////////////////// 00127 EggRenderMode *EggPrimitive:: 00128 determine_visibility_mode() { 00129 if (get_visibility_mode() != VM_unspecified) { 00130 return this; 00131 } 00132 00133 EggRenderMode *result = EggNode::determine_visibility_mode(); 00134 if (result == (EggRenderMode *)NULL) { 00135 int num_textures = get_num_textures(); 00136 for (int i = 0; i < num_textures && result == (EggRenderMode *)NULL; i++) { 00137 if (get_texture(i)->get_visibility_mode() != VM_unspecified) { 00138 result = get_texture(i); 00139 } 00140 } 00141 } 00142 return result; 00143 } 00144 00145 //////////////////////////////////////////////////////////////////// 00146 // Function: EggPrimitive::determine_depth_offset 00147 // Access: Published, Virtual 00148 // Description: Walks back up the hierarchy, looking for an EggGroup 00149 // or EggPrimitive or some such object at this level or 00150 // above this primitive that has a depth_offset specified. 00151 // Returns a valid EggRenderMode pointer if one is found, 00152 // or NULL otherwise. 00153 //////////////////////////////////////////////////////////////////// 00154 EggRenderMode *EggPrimitive:: 00155 determine_depth_offset() { 00156 if (has_depth_offset()) { 00157 return this; 00158 } 00159 00160 EggRenderMode *result = EggNode::determine_depth_offset(); 00161 if (result == (EggRenderMode *)NULL) { 00162 int num_textures = get_num_textures(); 00163 for (int i = 0; i < num_textures && result == (EggRenderMode *)NULL; i++) { 00164 if (get_texture(i)->has_depth_offset()) { 00165 result = get_texture(i); 00166 } 00167 } 00168 } 00169 return result; 00170 } 00171 00172 //////////////////////////////////////////////////////////////////// 00173 // Function: EggPrimitive::determine_draw_order 00174 // Access: Published, Virtual 00175 // Description: Walks back up the hierarchy, looking for an EggGroup 00176 // or EggPrimitive or some such object at this level or 00177 // above this primitive that has a draw_order specified. 00178 // Returns a valid EggRenderMode pointer if one is found, 00179 // or NULL otherwise. 00180 //////////////////////////////////////////////////////////////////// 00181 EggRenderMode *EggPrimitive:: 00182 determine_draw_order() { 00183 if (has_draw_order()) { 00184 return this; 00185 } 00186 00187 EggRenderMode *result = EggNode::determine_draw_order(); 00188 if (result == (EggRenderMode *)NULL) { 00189 int num_textures = get_num_textures(); 00190 for (int i = 0; i < num_textures && result == (EggRenderMode *)NULL; i++) { 00191 if (get_texture(i)->has_draw_order()) { 00192 result = get_texture(i); 00193 } 00194 } 00195 } 00196 return result; 00197 } 00198 00199 //////////////////////////////////////////////////////////////////// 00200 // Function: EggPrimitive::determine_bin 00201 // Access: Published, Virtual 00202 // Description: Walks back up the hierarchy, looking for an EggGroup 00203 // or EggPrimitive or some such object at this level or 00204 // above this primitive that has a bin specified. Returns a 00205 // valid EggRenderMode pointer if one is found, or NULL 00206 // otherwise. 00207 //////////////////////////////////////////////////////////////////// 00208 EggRenderMode *EggPrimitive:: 00209 determine_bin() { 00210 if (has_bin()) { 00211 return this; 00212 } 00213 00214 EggRenderMode *result = EggNode::determine_bin(); 00215 if (result == (EggRenderMode *)NULL) { 00216 int num_textures = get_num_textures(); 00217 for (int i = 0; i < num_textures && result == (EggRenderMode *)NULL; i++) { 00218 if (get_texture(i)->has_bin()) { 00219 result = get_texture(i); 00220 } 00221 } 00222 } 00223 return result; 00224 } 00225 00226 00227 //////////////////////////////////////////////////////////////////// 00228 // Function: EggPrimitive::get_shading 00229 // Access: Published, Virtual 00230 // Description: Returns the shading properties apparent on this 00231 // particular primitive. This returns S_per_vertex if 00232 // the vertices have colors or normals (and they are not 00233 // all the same values), or for a simple primitive, 00234 // S_overall otherwise. A composite primitive may also 00235 // return S_per_face if the individual component 00236 // primitives have colors or normals that are not all 00237 // the same values. 00238 // 00239 // To get the most accurate results, you should call 00240 // clear_shading() on all connected primitives (or on 00241 // all primitives in the egg file), followed by 00242 // get_shading() on each primitive. You may find it 00243 // easiest to call these methods on the EggData root 00244 // node (they are defined on EggGroupNode). 00245 //////////////////////////////////////////////////////////////////// 00246 EggPrimitive::Shading EggPrimitive:: 00247 get_shading() const { 00248 if (empty()) { 00249 return S_overall; 00250 } 00251 00252 if (has_vertex_normal()) { 00253 // Check if the vertices all have the same normal. 00254 const EggAttributes *first_vertex = get_vertex(0); 00255 if (!first_vertex->has_normal()) { 00256 first_vertex = this; 00257 } 00258 for (int i = 1; i < get_num_vertices(); i++) { 00259 const EggAttributes *vertex = get_vertex(i); 00260 if (!vertex->has_normal()) { 00261 vertex = this; 00262 } 00263 if (!vertex->matches_normal(*first_vertex)) { 00264 return S_per_vertex; 00265 } 00266 } 00267 } 00268 00269 if (has_vertex_color()) { 00270 // Check if the vertices all have the same color. 00271 const EggAttributes *first_vertex = get_vertex(0); 00272 if (!first_vertex->has_color()) { 00273 first_vertex = this; 00274 } 00275 for (int i = 1; i < get_num_vertices(); i++) { 00276 const EggAttributes *vertex = get_vertex(i); 00277 if (!vertex->has_color()) { 00278 vertex = this; 00279 } 00280 if (!vertex->matches_color(*first_vertex)) { 00281 return S_per_vertex; 00282 } 00283 } 00284 } 00285 00286 return S_overall; 00287 } 00288 00289 //////////////////////////////////////////////////////////////////// 00290 // Function: EggPrimitive::copy_attributes 00291 // Access: Published 00292 // Description: Copies the rendering attributes from the indicated 00293 // primitive. 00294 //////////////////////////////////////////////////////////////////// 00295 void EggPrimitive:: 00296 copy_attributes(const EggAttributes &other) { 00297 EggAttributes::operator = (other); 00298 } 00299 00300 //////////////////////////////////////////////////////////////////// 00301 // Function: EggPrimitive::copy_attributes 00302 // Access: Published 00303 // Description: Copies the rendering attributes from the indicated 00304 // primitive. 00305 //////////////////////////////////////////////////////////////////// 00306 void EggPrimitive:: 00307 copy_attributes(const EggPrimitive &other) { 00308 EggAttributes::operator = (other); 00309 _textures = other._textures; 00310 set_material(other.get_material()); 00311 set_bface_flag(other.get_bface_flag()); 00312 } 00313 00314 //////////////////////////////////////////////////////////////////// 00315 // Function: EggPrimitive::has_vertex_normal 00316 // Access: Published 00317 // Description: Returns true if any vertex on the primitive has a 00318 // specific normal set, false otherwise. 00319 // 00320 // If you call unify_attributes() first, this will also 00321 // return false even if all the vertices were set to the 00322 // same value (since unify_attributes() removes 00323 // redundant vertex properties). 00324 //////////////////////////////////////////////////////////////////// 00325 bool EggPrimitive:: 00326 has_vertex_normal() const { 00327 Vertices::const_iterator vi; 00328 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) { 00329 if ((*vi)->has_normal()) { 00330 return true; 00331 } 00332 } 00333 return false; 00334 } 00335 00336 //////////////////////////////////////////////////////////////////// 00337 // Function: EggPrimitive::has_vertex_color 00338 // Access: Published 00339 // Description: Returns true if any vertex on the primitive has a 00340 // specific color set, false otherwise. 00341 // 00342 // If you call unify_attributes() first, this will also 00343 // return false even if all the vertices were set to the 00344 // same value (since unify_attributes() removes 00345 // redundant vertex properties). 00346 //////////////////////////////////////////////////////////////////// 00347 bool EggPrimitive:: 00348 has_vertex_color() const { 00349 Vertices::const_iterator vi; 00350 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) { 00351 if ((*vi)->has_color()) { 00352 return true; 00353 } 00354 } 00355 return false; 00356 } 00357 00358 //////////////////////////////////////////////////////////////////// 00359 // Function: EggPrimitive::unify_attributes 00360 // Access: Published, Virtual 00361 // Description: If the shading property is S_per_vertex, ensures that 00362 // all vertices have a normal and a color, and the 00363 // overall primitive does not. 00364 // 00365 // If the shading property is S_per_face, and this is a 00366 // composite primitive, ensures that all components have 00367 // a normal and a color, and the vertices and overall 00368 // primitive do not. (If this is a simple primitive, 00369 // S_per_face works the same as S_overall, below). 00370 // 00371 // If the shading property is S_overall, ensures that no 00372 // vertices or components have a normal or a color, and 00373 // the overall primitive does (if any exists at all). 00374 // 00375 // After this call, either the primitive will have 00376 // normals or its vertices will, but not both. Ditto 00377 // for colors. 00378 // 00379 // This may create redundant vertices in the vertex 00380 // pool. 00381 //////////////////////////////////////////////////////////////////// 00382 void EggPrimitive:: 00383 unify_attributes(EggPrimitive::Shading shading) { 00384 if (shading == S_unknown) { 00385 shading = get_shading(); 00386 } 00387 00388 // Does the primitive have an explicit color? 00389 if (!has_color() && shading != S_overall) { 00390 if (shading != S_per_vertex) { 00391 // If there is no color set, first we check the vertices. If the 00392 // vertices have a color, we inherit the color from there. 00393 iterator pi; 00394 for (pi = begin(); pi != end() && !has_color(); ++pi) { 00395 EggVertex *vertex = (*pi); 00396 if (vertex->has_color()) { 00397 set_color(vertex->get_color()); 00398 } 00399 } 00400 } 00401 if (!has_color()) { 00402 // If we still don't have a color, the implicit color is white. 00403 set_color(LColor(1.0f, 1.0f, 1.0f, 1.0f)); 00404 } 00405 } 00406 00407 switch (shading) { 00408 case S_per_vertex: 00409 // Propagate everything to the vertices. 00410 { 00411 iterator pi; 00412 for (pi = begin(); pi != end(); ++pi) { 00413 EggVertex *orig_vertex = (*pi); 00414 PT(EggVertex) vertex = new EggVertex(*orig_vertex); 00415 if (!vertex->has_normal() && has_normal()) { 00416 vertex->copy_normal(*this); 00417 } 00418 if (!vertex->has_color() && has_color()) { 00419 vertex->copy_color(*this); 00420 } 00421 00422 EggVertexPool *vertex_pool = orig_vertex->get_pool(); 00423 nassertv(vertex_pool != (EggVertexPool *)NULL); 00424 vertex = vertex_pool->create_unique_vertex(*vertex); 00425 vertex->copy_grefs_from(*orig_vertex); 00426 replace(pi, vertex); 00427 } 00428 clear_normal(); 00429 clear_color(); 00430 } 00431 break; 00432 00433 case S_per_face: 00434 case S_overall: 00435 // Remove everything from the vertices. 00436 { 00437 iterator pi; 00438 for (pi = begin(); pi != end(); ++pi) { 00439 EggVertex *orig_vertex = (*pi); 00440 PT(EggVertex) vertex = new EggVertex(*orig_vertex); 00441 if (vertex->has_normal()) { 00442 if (!has_normal()) { 00443 copy_normal(*vertex); 00444 } 00445 vertex->clear_normal(); 00446 } 00447 if (vertex->has_color()) { 00448 if (!has_color()) { 00449 copy_color(*vertex); 00450 } 00451 vertex->clear_color(); 00452 } 00453 00454 EggVertexPool *vertex_pool = orig_vertex->get_pool(); 00455 nassertv(vertex_pool != (EggVertexPool *)NULL); 00456 vertex = vertex_pool->create_unique_vertex(*vertex); 00457 vertex->copy_grefs_from(*orig_vertex); 00458 replace(pi, vertex); 00459 } 00460 } 00461 break; 00462 00463 case S_unknown: 00464 break; 00465 } 00466 00467 if (!has_color() && shading == S_overall) { 00468 set_color(LColor(1.0f, 1.0f, 1.0f, 1.0f)); 00469 } 00470 } 00471 00472 //////////////////////////////////////////////////////////////////// 00473 // Function: EggPrimitive::apply_last_attribute 00474 // Access: Published, Virtual 00475 // Description: Sets the last vertex of the triangle (or each 00476 // component) to the primitive normal and/or color, if 00477 // the primitive is flat-shaded. This reflects the 00478 // OpenGL convention of storing flat-shaded properties on 00479 // the last vertex, although it is not usually a 00480 // convention in Egg. 00481 // 00482 // This may introduce redundant vertices to the vertex 00483 // pool. 00484 //////////////////////////////////////////////////////////////////// 00485 void EggPrimitive:: 00486 apply_last_attribute() { 00487 if (!empty()) { 00488 do_apply_flat_attribute(size() - 1, this); 00489 } 00490 } 00491 00492 //////////////////////////////////////////////////////////////////// 00493 // Function: EggPrimitive::apply_first_attribute 00494 // Access: Published, Virtual 00495 // Description: Sets the first vertex of the triangle (or each 00496 // component) to the primitive normal and/or color, if 00497 // the primitive is flat-shaded. This reflects the 00498 // DirectX convention of storing flat-shaded properties on 00499 // the first vertex, although it is not usually a 00500 // convention in Egg. 00501 // 00502 // This may introduce redundant vertices to the vertex 00503 // pool. 00504 //////////////////////////////////////////////////////////////////// 00505 void EggPrimitive:: 00506 apply_first_attribute() { 00507 if (!empty()) { 00508 do_apply_flat_attribute(0, this); 00509 } 00510 } 00511 00512 //////////////////////////////////////////////////////////////////// 00513 // Function: EggPrimitive::post_apply_flat_attribute 00514 // Access: Published, Virtual 00515 // Description: Intended as a followup to apply_last_attribute(), 00516 // this also sets an attribute on the first vertices of 00517 // the primitive, if they don't already have an 00518 // attribute set, just so they end up with *something*. 00519 //////////////////////////////////////////////////////////////////// 00520 void EggPrimitive:: 00521 post_apply_flat_attribute() { 00522 if (!empty()) { 00523 for (int i = 0; i < (int)size(); i++) { 00524 EggVertex *vertex = get_vertex(i); 00525 00526 // Use set_normal() instead of copy_normal(), to avoid getting 00527 // the morphs--we don't want them here, since we're just putting 00528 // a bogus value on the normal anyway. 00529 00530 if (has_normal() && !vertex->has_normal()) { 00531 vertex->set_normal(get_normal()); 00532 } 00533 if (has_color() && !vertex->has_color()) { 00534 vertex->set_color(get_color()); 00535 } 00536 } 00537 } 00538 } 00539 00540 //////////////////////////////////////////////////////////////////// 00541 // Function: EggPrimitive::reverse_vertex_ordering 00542 // Access: Published, Virtual 00543 // Description: Reverses the ordering of the vertices in this 00544 // primitive, if appropriate, in order to change the 00545 // direction the polygon appears to be facing. Does not 00546 // adjust the surface normal, if any. 00547 //////////////////////////////////////////////////////////////////// 00548 void EggPrimitive:: 00549 reverse_vertex_ordering() { 00550 // This really only makes sense for polygons. Lights don't care 00551 // about vertex ordering, and NURBS surfaces have to do a bit more 00552 // work in addition to this. 00553 reverse(_vertices.begin(), _vertices.end()); 00554 } 00555 00556 //////////////////////////////////////////////////////////////////// 00557 // Function: EggPrimitive::cleanup 00558 // Access: Published, Virtual 00559 // Description: Cleans up modeling errors in whatever context this 00560 // makes sense. For instance, for a polygon, this calls 00561 // remove_doubled_verts(true). For a point, it calls 00562 // remove_nonunique_verts(). Returns true if the 00563 // primitive is valid, or false if it is degenerate. 00564 //////////////////////////////////////////////////////////////////// 00565 bool EggPrimitive:: 00566 cleanup() { 00567 return !empty(); 00568 } 00569 00570 //////////////////////////////////////////////////////////////////// 00571 // Function: EggPrimitive::remove_doubled_verts 00572 // Access: Published 00573 // Description: Certain kinds of primitives, particularly polygons, 00574 // don't like to have the same vertex repeated 00575 // consecutively. Unfortunately, some modeling programs 00576 // (like MultiGen) make this an easy mistake to make. 00577 // 00578 // It's handy to have a function to remove these 00579 // redundant vertices. If closed is true, it also 00580 // checks that the first and last vertices are not the 00581 // same. 00582 // 00583 // This function identifies repeated vertices by 00584 // position only; it does not consider any other 00585 // properties, such as color or UV, significant in 00586 // differentiating vertices. 00587 //////////////////////////////////////////////////////////////////// 00588 void EggPrimitive:: 00589 remove_doubled_verts(bool closed) { 00590 if (!_vertices.empty()) { 00591 Vertices new_vertices; 00592 Vertices::iterator vi, vlast; 00593 vi = _vertices.begin(); 00594 new_vertices.push_back(*vi); 00595 int num_removed = 0; 00596 00597 vlast = vi; 00598 ++vi; 00599 while (vi != _vertices.end()) { 00600 if ((*vi)->get_pos4() != (*vlast)->get_pos4()) { 00601 new_vertices.push_back(*vi); 00602 } else { 00603 prepare_remove_vertex(*vi, vi - _vertices.begin() - num_removed, 00604 _vertices.size() - num_removed); 00605 num_removed++; 00606 } 00607 vlast = vi; 00608 ++vi; 00609 } 00610 _vertices.swap(new_vertices); 00611 } 00612 00613 if (closed) { 00614 // Then, if this is a polygon (which will be closed anyway), 00615 // remove the vertex from the end if it's a repeat of the 00616 // beginning. 00617 while (_vertices.size() > 1 && 00618 _vertices.back()->get_pos4() == _vertices.front()->get_pos4()) { 00619 prepare_remove_vertex(_vertices.back(), _vertices.size() - 1, 00620 _vertices.size()); 00621 _vertices.pop_back(); 00622 } 00623 } 00624 } 00625 00626 //////////////////////////////////////////////////////////////////// 00627 // Function: EggPrimitive::remove_nonunique_verts 00628 // Access: Published 00629 // Description: Removes any multiple appearances of the same vertex 00630 // from the primitive. This primarily makes sense for a 00631 // point primitive, which is really a collection of 00632 // points and which doesn't make sense to include the 00633 // same point twice, in any order. 00634 //////////////////////////////////////////////////////////////////// 00635 void EggPrimitive:: 00636 remove_nonunique_verts() { 00637 Vertices::iterator vi, vj; 00638 Vertices new_vertices; 00639 int num_removed = 0; 00640 00641 pset<EggVertex *> unique_vertices; 00642 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) { 00643 bool inserted = unique_vertices.insert(*vi).second; 00644 if (inserted) { 00645 new_vertices.push_back(*vi); 00646 } else { 00647 prepare_remove_vertex(*vi, vi - _vertices.begin() - num_removed, 00648 _vertices.size() - num_removed); 00649 num_removed++; 00650 } 00651 } 00652 00653 _vertices.swap(new_vertices); 00654 } 00655 00656 //////////////////////////////////////////////////////////////////// 00657 // Function: EggPrimitive::has_primitives 00658 // Access: Published, Virtual 00659 // Description: Returns true if there are any primitives 00660 // (e.g. polygons) defined within this group or below, 00661 // false otherwise. 00662 //////////////////////////////////////////////////////////////////// 00663 bool EggPrimitive:: 00664 has_primitives() const { 00665 return true; 00666 } 00667 00668 //////////////////////////////////////////////////////////////////// 00669 // Function: EggPrimitive::joint_has_primitives 00670 // Access: Published, Virtual 00671 // Description: Returns true if there are any primitives 00672 // (e.g. polygons) defined within this group or below, 00673 // but the search does not include nested joints. 00674 //////////////////////////////////////////////////////////////////// 00675 bool EggPrimitive:: 00676 joint_has_primitives() const { 00677 return true; 00678 } 00679 00680 //////////////////////////////////////////////////////////////////// 00681 // Function: EggPrimitive::has_normals 00682 // Access: Published, Virtual 00683 // Description: Returns true if any of the primitives (e.g. polygons) 00684 // defined within this group or below have either face 00685 // or vertex normals defined, false otherwise. 00686 //////////////////////////////////////////////////////////////////// 00687 bool EggPrimitive:: 00688 has_normals() const { 00689 if (has_normal()) { 00690 return true; 00691 } 00692 00693 const_iterator vi; 00694 for (vi = begin(); vi != end(); ++vi) { 00695 if ((*vi)->has_normal()) { 00696 return true; 00697 } 00698 } 00699 00700 return false; 00701 } 00702 00703 00704 //////////////////////////////////////////////////////////////////// 00705 // Function: EggPrimitive::erase 00706 // Access: Public 00707 // Description: Part of the implementaion of the EggPrimitive as an 00708 // STL container. Most of the rest of these functions 00709 // are inline and declared in EggPrimitive.I. 00710 //////////////////////////////////////////////////////////////////// 00711 EggPrimitive::iterator EggPrimitive:: 00712 erase(iterator first, iterator last) { 00713 iterator i; 00714 int num_removed = 0; 00715 for (i = first; i != last; ++i) { 00716 prepare_remove_vertex(*i, first - _vertices.begin(), 00717 _vertices.size() - num_removed); 00718 num_removed++; 00719 } 00720 iterator result = _vertices.erase((Vertices::iterator &)first, 00721 (Vertices::iterator &)last); 00722 test_vref_integrity(); 00723 return result; 00724 } 00725 00726 //////////////////////////////////////////////////////////////////// 00727 // Function: EggPrimitive::find 00728 // Access: Public 00729 // Description: Returns the iterator pointing to the indicated 00730 // vertex, or end() if the vertex is not part of the 00731 // primitive. 00732 //////////////////////////////////////////////////////////////////// 00733 EggPrimitive::iterator EggPrimitive:: 00734 find(EggVertex *vertex) { 00735 PT_EggVertex vpt = vertex; 00736 return ::find(begin(), end(), vpt); 00737 } 00738 00739 00740 //////////////////////////////////////////////////////////////////// 00741 // Function: EggPrimitive::add_vertex 00742 // Access: Published 00743 // Description: Adds the indicated vertex to the end of the 00744 // primitive's list of vertices, and returns it. 00745 //////////////////////////////////////////////////////////////////// 00746 EggVertex *EggPrimitive:: 00747 add_vertex(EggVertex *vertex) { 00748 prepare_add_vertex(vertex, _vertices.size(), _vertices.size() + 1); 00749 _vertices.push_back(vertex); 00750 00751 vertex->test_pref_integrity(); 00752 test_vref_integrity(); 00753 00754 return vertex; 00755 } 00756 00757 //////////////////////////////////////////////////////////////////// 00758 // Function: EggPrimitive::remove_vertex 00759 // Access: Published 00760 // Description: Removes the indicated vertex from the 00761 // primitive and returns it. If the vertex was not 00762 // already in the primitive, does nothing and returns 00763 // NULL. 00764 //////////////////////////////////////////////////////////////////// 00765 EggVertex *EggPrimitive:: 00766 remove_vertex(EggVertex *vertex) { 00767 PT_EggVertex vpt = vertex; 00768 iterator i = ::find(begin(), end(), vpt); 00769 if (i == end()) { 00770 return PT_EggVertex(); 00771 } else { 00772 // erase() calls prepare_remove_vertex(). 00773 erase(i); 00774 00775 vertex->test_pref_integrity(); 00776 test_vref_integrity(); 00777 00778 return vertex; 00779 } 00780 } 00781 00782 00783 //////////////////////////////////////////////////////////////////// 00784 // Function: EggPrimitive::copy_vertices 00785 // Access: Published 00786 // Description: Replaces the current primitive's list of vertices 00787 // with a copy of the list of vertices on the other 00788 // primitive. 00789 //////////////////////////////////////////////////////////////////// 00790 void EggPrimitive:: 00791 copy_vertices(const EggPrimitive &other) { 00792 clear(); 00793 _vertices.reserve(other.size()); 00794 00795 iterator vi; 00796 for (vi = other.begin(); vi != other.end(); ++vi) { 00797 add_vertex(*vi); 00798 } 00799 00800 test_vref_integrity(); 00801 other.test_vref_integrity(); 00802 } 00803 00804 #ifdef _DEBUG 00805 00806 //////////////////////////////////////////////////////////////////// 00807 // Function: EggPrimitive::test_vref_integrity 00808 // Access: Published 00809 // Description: Verifies that each vertex in the primitive exists and 00810 // that it knows it is referenced by the primitive. 00811 //////////////////////////////////////////////////////////////////// 00812 void EggPrimitive:: 00813 test_vref_integrity() const { 00814 test_ref_count_integrity(); 00815 00816 if ((int)size() <= egg_test_vref_integrity) { 00817 // First, we need to know how many times each vertex appears. 00818 // Usually, this will be only one, but it's possible for a vertex to 00819 // appear more than once. 00820 typedef pmap<const EggVertex *, int> VertexCount; 00821 VertexCount _count; 00822 00823 // Now count up the vertices. 00824 iterator vi; 00825 for (vi = begin(); vi != end(); ++vi) { 00826 const EggVertex *vert = *vi; 00827 vert->test_ref_count_integrity(); 00828 00829 VertexCount::iterator vci = _count.find(vert); 00830 if (vci == _count.end()) { 00831 _count[vert] = 1; 00832 } else { 00833 (*vci).second++; 00834 } 00835 } 00836 00837 // Ok, now walk through the vertices found and make sure the vertex 00838 // has the proper number of entries of this primitive in its pref. 00839 VertexCount::iterator vci; 00840 for (vci = _count.begin(); vci != _count.end(); ++vci) { 00841 const EggVertex *vert = (*vci).first; 00842 00843 int count = (*vci).second; 00844 int vert_count = vert->has_pref(this); 00845 00846 nassertv(count == vert_count); 00847 } 00848 } 00849 } 00850 00851 #endif // _DEBUG 00852 00853 //////////////////////////////////////////////////////////////////// 00854 // Function: EggPrimitive::prepare_add_vertex 00855 // Access: Protected, Virtual 00856 // Description: Marks the vertex as belonging to the primitive. This 00857 // is an internal function called by the STL-like 00858 // functions push_back() and insert(), in preparation 00859 // for actually adding the vertex. 00860 // 00861 // i indicates the new position of the vertex in the 00862 // list; n indicates the new number of vertices after 00863 // the operation has completed. 00864 //////////////////////////////////////////////////////////////////// 00865 void EggPrimitive:: 00866 prepare_add_vertex(EggVertex *vertex, int i, int n) { 00867 // We can't test integrity within this function, because it might be 00868 // called when the primitive is in an incomplete state. 00869 00870 // The vertex must have the same vertex pool as the vertices already 00871 // added. 00872 nassertv(empty() || vertex->get_pool() == get_pool()); 00873 00874 // Since a given vertex might appear more than once in a particular 00875 // primitive, we can't conclude anything about data integrity by 00876 // inspecting the return value of insert(). (In fact, the vertex's 00877 // pref is a multiset, so the insert() will always succeed.) 00878 00879 vertex->_pref.insert(this); 00880 } 00881 00882 00883 //////////////////////////////////////////////////////////////////// 00884 // Function: EggPrimitive::prepare_remove_vertex 00885 // Access: Protected, Virtual 00886 // Description: Marks the vertex as removed from the primitive. This 00887 // is an internal function called by the STL-like 00888 // functions pop_back() and erase(), in preparation for 00889 // actually doing the removal. 00890 // 00891 // i indicates the former position of the vertex in the 00892 // list; n indicates the current number of vertices 00893 // before the operation has completed. 00894 // 00895 // It is an error to attempt to remove a vertex that is 00896 // not already a vertex of this primitive. 00897 //////////////////////////////////////////////////////////////////// 00898 void EggPrimitive:: 00899 prepare_remove_vertex(EggVertex *vertex, int i, int n) { 00900 // We can't test integrity within this function, because it might be 00901 // called when the primitive is in an incomplete state. 00902 00903 // Now we must remove the primitive from the vertex's pref. We 00904 // can't just use the simple erase() function, since that will 00905 // remove all instances of this primitive from the pref; instead, we 00906 // must find one instance and remove that. 00907 00908 EggVertex::PrimitiveRef::iterator pri = vertex->_pref.find(this); 00909 00910 // We should have found the primitive in the vertex's pref. If we 00911 // did not, something's out of sync internally. 00912 nassertv(pri != vertex->_pref.end()); 00913 00914 vertex->_pref.erase(pri); 00915 } 00916 00917 //////////////////////////////////////////////////////////////////// 00918 // Function: EggPrimitive::write_body 00919 // Access: Protected 00920 // Description: Writes the attributes and the vertices referenced by 00921 // the primitive to the indicated output stream in Egg 00922 // format. 00923 //////////////////////////////////////////////////////////////////// 00924 void EggPrimitive:: 00925 write_body(ostream &out, int indent_level) const { 00926 test_vref_integrity(); 00927 00928 EggAttributes::write(out, indent_level); 00929 EggRenderMode::write(out, indent_level); 00930 00931 int num_textures = get_num_textures(); 00932 for (int i = 0; i < num_textures; i++) { 00933 EggTexture *texture = get_texture(i); 00934 00935 indent(out, indent_level) << "<TRef> { "; 00936 enquote_string(out, texture->get_name()) 00937 << " }\n"; 00938 } 00939 00940 if (has_material()) { 00941 EggMaterial *material = get_material(); 00942 00943 indent(out, indent_level) << "<MRef> { "; 00944 enquote_string(out, material->get_name()) 00945 << " }\n"; 00946 } 00947 00948 if (get_bface_flag()) { 00949 indent(out, indent_level) << "<BFace> { 1 }\n"; 00950 } 00951 00952 if (!empty()) { 00953 EggVertexPool *pool = get_pool(); 00954 00955 // Make sure the vertices belong to some vertex pool. 00956 nassertv(pool != NULL); 00957 00958 // Make sure the vertex pool is named. 00959 nassertv(pool->has_name()); 00960 00961 if ((int)size() < 10) { 00962 // A simple primitive gets all its vertex indices written on one 00963 // line. 00964 indent(out, indent_level) << "<VertexRef> {"; 00965 const_iterator i; 00966 for (i = begin(); i != end(); ++i) { 00967 EggVertex *vert = *i; 00968 vert->test_pref_integrity(); 00969 00970 // Make sure each vertex belongs to the same pool. 00971 nassertv(vert->get_pool() == pool); 00972 00973 out << " " << vert->get_index(); 00974 } 00975 out << " <Ref> { "; 00976 enquote_string(out, pool->get_name()) << " } }\n"; 00977 00978 } else { 00979 00980 // A larger primitive gets its vertex indices written as 00981 // multiple lines. 00982 vector_int indices; 00983 const_iterator i; 00984 for (i = begin(); i != end(); ++i) { 00985 EggVertex *vert = *i; 00986 vert->test_pref_integrity(); 00987 00988 // Make sure each vertex belongs to the same pool. 00989 nassertv(vert->get_pool() == pool); 00990 00991 indices.push_back(vert->get_index()); 00992 } 00993 00994 indent(out, indent_level) << "<VertexRef> {\n"; 00995 write_long_list(out, indent_level+2, indices.begin(), indices.end(), 00996 "", "", 72); 00997 indent(out, indent_level+2) << "<Ref> { "; 00998 enquote_string(out, pool->get_name()) << " }\n"; 00999 indent(out, indent_level) << "}\n"; 01000 } 01001 } 01002 } 01003 01004 //////////////////////////////////////////////////////////////////// 01005 // Function: EggPrimitive::egg_start_parse_body 01006 // Access: Protected, Virtual 01007 // Description: This function is called within parse_egg(). It 01008 // should call the appropriate function on the lexer to 01009 // initialize the parser into the state associated with 01010 // this object. If the object cannot be parsed into 01011 // directly, it should return false. 01012 //////////////////////////////////////////////////////////////////// 01013 bool EggPrimitive:: 01014 egg_start_parse_body() { 01015 egg_start_primitive_body(); 01016 return true; 01017 } 01018 01019 //////////////////////////////////////////////////////////////////// 01020 // Function: EggPrimitive::r_transform 01021 // Access: Protected, Virtual 01022 // Description: This is called from within the egg code by 01023 // transform(). It applies a transformation matrix 01024 // to the current node in some sensible way, then 01025 // continues down the tree. 01026 // 01027 // The first matrix is the transformation to apply; the 01028 // second is its inverse. The third parameter is the 01029 // coordinate system we are changing to, or CS_default 01030 // if we are not changing coordinate systems. 01031 //////////////////////////////////////////////////////////////////// 01032 void EggPrimitive:: 01033 r_transform(const LMatrix4d &mat, const LMatrix4d &, CoordinateSystem) { 01034 EggAttributes::transform(mat); 01035 } 01036 01037 //////////////////////////////////////////////////////////////////// 01038 // Function: EggPrimitive::r_flatten_transforms 01039 // Access: Protected, Virtual 01040 // Description: The recursive implementation of flatten_transforms(). 01041 //////////////////////////////////////////////////////////////////// 01042 void EggPrimitive:: 01043 r_flatten_transforms() { 01044 if (is_local_coord()) { 01045 LMatrix4d mat = get_vertex_frame(); 01046 EggAttributes::transform(mat); 01047 01048 // Transform each vertex by duplicating it in the vertex pool. 01049 size_t num_vertices = size(); 01050 for (size_t i = 0; i < num_vertices; i++) { 01051 EggVertex *vertex = get_vertex(i); 01052 EggVertexPool *pool = vertex->get_pool(); 01053 01054 EggVertex new_vertex(*vertex); 01055 new_vertex.transform(mat); 01056 EggVertex *unique = pool->create_unique_vertex(new_vertex); 01057 unique->copy_grefs_from(*vertex); 01058 01059 set_vertex(i, unique); 01060 } 01061 } 01062 } 01063 01064 //////////////////////////////////////////////////////////////////// 01065 // Function: EggPrimitive::r_apply_texmats 01066 // Access: Protected, Virtual 01067 // Description: The recursive implementation of apply_texmats(). 01068 //////////////////////////////////////////////////////////////////// 01069 void EggPrimitive:: 01070 r_apply_texmats(EggTextureCollection &textures) { 01071 Textures new_textures; 01072 Textures::const_iterator ti; 01073 for (ti = _textures.begin(); ti != _textures.end(); ++ti) { 01074 EggTexture *texture = (*ti); 01075 01076 if (!texture->has_transform()) { 01077 new_textures.push_back(texture); 01078 01079 } else if (texture->transform_is_identity()) { 01080 // Now, what's the point of a texture with an identity 01081 // transform? 01082 texture->clear_transform(); 01083 new_textures.push_back(texture); 01084 01085 } else { 01086 01087 // We've got a texture with a matrix applied. Save the matrix, 01088 // and get a new texture without the matrix. 01089 LMatrix4d mat = texture->get_transform3d(); 01090 EggTexture new_texture(*texture); 01091 new_texture.clear_transform(); 01092 EggTexture *unique = textures.create_unique_texture(new_texture, ~0); 01093 01094 new_textures.push_back(unique); 01095 string uv_name = unique->get_uv_name(); 01096 01097 // Now apply the matrix to the vertex UV's. Create new vertices 01098 // as necessary. 01099 size_t num_vertices = size(); 01100 for (size_t i = 0; i < num_vertices; i++) { 01101 EggVertex *vertex = get_vertex(i); 01102 01103 const EggVertexUV *uv_obj = vertex->get_uv_obj(uv_name); 01104 if (uv_obj != (EggVertexUV *)NULL) { 01105 EggVertex new_vertex(*vertex); 01106 PT(EggVertexUV) new_uv_obj = new EggVertexUV(*uv_obj); 01107 LTexCoord3d uvw = uv_obj->get_uvw() * mat; 01108 if (uv_obj->has_w() || texture->has_transform3d()) { 01109 new_uv_obj->set_uvw(uvw); 01110 } else { 01111 new_uv_obj->set_uv(LTexCoordd(uvw[0], uvw[1])); 01112 } 01113 new_vertex.set_uv_obj(new_uv_obj); 01114 01115 EggVertexPool *pool = vertex->get_pool(); 01116 EggVertex *unique = pool->create_unique_vertex(new_vertex); 01117 unique->copy_grefs_from(*vertex); 01118 01119 set_vertex(i, unique); 01120 } 01121 } 01122 } 01123 } 01124 01125 _textures.swap(new_textures); 01126 } 01127 01128 //////////////////////////////////////////////////////////////////// 01129 // Function: EggPrimitive::apply_attribute_to_vertex 01130 // Access: Protected 01131 // Description: This is used to implement apply_first_attribute() and 01132 // apply_last_attribute(). It copies the indicated 01133 // attributes to the specified vertex. 01134 //////////////////////////////////////////////////////////////////// 01135 void EggPrimitive:: 01136 do_apply_flat_attribute(int vertex_index, EggAttributes *attrib) { 01137 // The significant_change flag is set if we have changed the 01138 // vertex in some important way, that will invalidate it for other 01139 // primitives that might share it. We don't consider *adding* a 01140 // normal where there wasn't one before to be significant, but we 01141 // do consider it significant to change a vertex's normal to 01142 // something different. Similarly for color. 01143 bool significant_change = false; 01144 01145 EggVertex *orig_vertex = get_vertex(vertex_index); 01146 PT(EggVertex) new_vertex = new EggVertex(*orig_vertex); 01147 01148 if (attrib->has_normal()) { 01149 new_vertex->copy_normal(*attrib); 01150 01151 if (orig_vertex->has_normal() && 01152 !orig_vertex->matches_normal(*new_vertex)) { 01153 significant_change = true; 01154 } 01155 } else if (has_normal()) { 01156 new_vertex->copy_normal(*this); 01157 01158 if (orig_vertex->has_normal() && 01159 !orig_vertex->matches_normal(*new_vertex)) { 01160 significant_change = true; 01161 } 01162 } 01163 01164 if (attrib->has_color()) { 01165 new_vertex->copy_color(*attrib); 01166 01167 if (orig_vertex->has_color() && 01168 !orig_vertex->matches_color(*new_vertex)) { 01169 significant_change = true; 01170 } 01171 } else if (has_color()) { 01172 new_vertex->copy_color(*this); 01173 01174 if (orig_vertex->has_color() && 01175 !orig_vertex->matches_color(*new_vertex)) { 01176 significant_change = true; 01177 } 01178 } 01179 01180 if (significant_change) { 01181 new_vertex = get_pool()->create_unique_vertex(*new_vertex); 01182 new_vertex->copy_grefs_from(*orig_vertex); 01183 set_vertex(vertex_index, new_vertex); 01184 } else { 01185 // Just copy the new attributes back into the pool. 01186 ((EggAttributes *)orig_vertex)->operator = (*new_vertex); 01187 } 01188 } 01189 01190 //////////////////////////////////////////////////////////////////// 01191 // Function: EggPrimitive::set_connected_shading 01192 // Access: Private 01193 // Description: Recursively updates the connected_shading member in 01194 // all connected primitives. 01195 //////////////////////////////////////////////////////////////////// 01196 void EggPrimitive:: 01197 set_connected_shading(EggPrimitive::Shading shading, 01198 const EggAttributes *neighbor) { 01199 ConnectedShadingNodes connected_nodes; 01200 01201 r_set_connected_shading(0, shading, neighbor, connected_nodes); 01202 01203 // Pick up any additional nodes we couldn't visit because of the 01204 // stack depth restrictions. 01205 while (!connected_nodes.empty()) { 01206 ConnectedShadingNodes next_nodes; 01207 next_nodes.swap(connected_nodes); 01208 01209 ConnectedShadingNodes::iterator ni; 01210 for (ni = next_nodes.begin(); ni != next_nodes.end(); ++ni) { 01211 r_set_connected_shading(0, (*ni)._shading, (*ni)._neighbor, connected_nodes); 01212 } 01213 } 01214 } 01215 01216 //////////////////////////////////////////////////////////////////// 01217 // Function: EggPrimitive::r_set_connected_shading 01218 // Access: Private 01219 // Description: Implements set_connected_shading, with some 01220 // restrictions to prevent stack overflow. 01221 //////////////////////////////////////////////////////////////////// 01222 void EggPrimitive:: 01223 r_set_connected_shading(int stack_depth, EggPrimitive::Shading shading, 01224 const EggAttributes *neighbor, 01225 ConnectedShadingNodes &next_nodes) { 01226 if (stack_depth > egg_recursion_limit) { 01227 // Too deep. Limit recursion. 01228 ConnectedShadingNode next; 01229 next._shading = shading; 01230 next._neighbor = neighbor; 01231 next_nodes.push_back(next); 01232 return; 01233 } 01234 01235 bool propagate = false; 01236 01237 if (_connected_shading == S_unknown) { 01238 // We haven't visited this node before; propagate now. 01239 _connected_shading = get_shading(); 01240 propagate = true; 01241 } 01242 01243 if (shading > _connected_shading) { 01244 // More specific information just came in. Save it, and propagate 01245 // it to all connected primitives. 01246 _connected_shading = shading; 01247 propagate = true; 01248 01249 } else if (shading == S_overall && _connected_shading == S_overall) { 01250 // If both neighbors are overall shaded, check if the two 01251 // neighbors have different properties. If they do, elevate to 01252 // per_face. 01253 bool matches_normal = this->matches_normal(*neighbor); 01254 bool matches_color = this->matches_color(*neighbor); 01255 01256 if (!matches_color) { 01257 // Make a special case for not having an overall color: that's 01258 // implicitly white. 01259 if (!neighbor->has_color() && has_color() && _drgbas.empty() && 01260 get_color() == LColor(1.0f, 1.0f, 1.0f, 1.0f)) { 01261 matches_color = true; 01262 } else if (!has_color() && neighbor->has_color() && neighbor->_drgbas.empty() && 01263 neighbor->get_color() == LColor(1.0f, 1.0f, 1.0f, 1.0f)) { 01264 matches_color = true; 01265 } 01266 } 01267 if (!matches_normal || !matches_color) { 01268 _connected_shading = S_per_face; 01269 propagate = true; 01270 } 01271 } 01272 01273 if (propagate) { 01274 Vertices::const_iterator vi; 01275 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) { 01276 EggVertex *vertex = (*vi); 01277 EggVertex::PrimitiveRef::const_iterator pi; 01278 for (pi = vertex->pref_begin(); 01279 pi != vertex->pref_end(); 01280 ++pi) { 01281 (*pi)->r_set_connected_shading(stack_depth + 1, _connected_shading, this, 01282 next_nodes); 01283 } 01284 } 01285 } 01286 }