Panda3D
|
00001 // Filename: eggCompositePrimitive.cxx 00002 // Created by: drose (13Mar05) 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 "eggCompositePrimitive.h" 00016 #include "eggGroupNode.h" 00017 #include "eggVertexPool.h" 00018 00019 TypeHandle EggCompositePrimitive::_type_handle; 00020 00021 00022 //////////////////////////////////////////////////////////////////// 00023 // Function: EggCompositePrimitive::Destructor 00024 // Access: Published, Virtual 00025 // Description: 00026 //////////////////////////////////////////////////////////////////// 00027 EggCompositePrimitive:: 00028 ~EggCompositePrimitive() { 00029 // Every derived class of EggCompositePrimitive must call clear() in 00030 // its destructor. 00031 nassertv(_components.empty()); 00032 } 00033 00034 //////////////////////////////////////////////////////////////////// 00035 // Function: EggCompositePrimitive::get_shading 00036 // Access: Published, Virtual 00037 // Description: Returns the shading properties apparent on this 00038 // particular primitive. This returns S_per_vertex if 00039 // the vertices have colors or normals (and they are not 00040 // all the same values), or for a simple primitive, 00041 // S_overall otherwise. A composite primitive may also 00042 // return S_per_face if the individual component 00043 // primitives have colors or normals that are not all 00044 // the same values. 00045 // 00046 // To get the most accurate results, you should call 00047 // clear_shading() on all connected primitives (or on 00048 // all primitives in the egg file), followed by 00049 // get_shading() on each primitive. You may find it 00050 // easiest to call these methods on the EggData root 00051 // node (they are defined on EggGroupNode). 00052 //////////////////////////////////////////////////////////////////// 00053 EggPrimitive::Shading EggCompositePrimitive:: 00054 get_shading() const { 00055 Shading basic_shading = EggPrimitive::get_shading(); 00056 if (basic_shading == S_per_vertex) { 00057 return basic_shading; 00058 } 00059 if (_components.empty()) { 00060 return S_overall; 00061 } 00062 00063 // Check if the components all have the same normal. 00064 { 00065 const EggAttributes *first_component = get_component(0); 00066 if (!first_component->has_normal()) { 00067 first_component = this; 00068 } 00069 for (int i = 1; i < get_num_components(); i++) { 00070 const EggAttributes *component = get_component(i); 00071 if (!component->has_normal()) { 00072 component = this; 00073 } 00074 if (!component->matches_normal(*first_component)) { 00075 return S_per_face; 00076 } 00077 } 00078 } 00079 00080 // Check if the components all have the same color. 00081 { 00082 const EggAttributes *first_component = get_component(0); 00083 if (!first_component->has_color()) { 00084 first_component = this; 00085 } 00086 for (int i = 1; i < get_num_components(); i++) { 00087 const EggAttributes *component = get_component(i); 00088 if (!component->has_color()) { 00089 component = this; 00090 } 00091 if (!component->matches_color(*first_component)) { 00092 return S_per_face; 00093 } 00094 } 00095 } 00096 00097 return S_overall; 00098 } 00099 00100 //////////////////////////////////////////////////////////////////// 00101 // Function: EggCompositePrimitive::triangulate_in_place 00102 // Access: Published 00103 // Description: Subdivides the composite primitive into triangles and 00104 // adds those triangles to the parent group node in 00105 // place of the original primitive. Returns a pointer 00106 // to the original primitive, which is likely about to 00107 // be destructed. 00108 // 00109 // If convex_also is true, both concave and convex 00110 // polygons will be subdivided into triangles; 00111 // otherwise, only concave polygons will be subdivided, 00112 // and convex polygons will be copied unchanged into the 00113 // container. 00114 //////////////////////////////////////////////////////////////////// 00115 PT(EggCompositePrimitive) EggCompositePrimitive:: 00116 triangulate_in_place() { 00117 EggGroupNode *parent = get_parent(); 00118 nassertr(parent != (EggGroupNode *)NULL, this); 00119 00120 PT(EggCompositePrimitive) save_me = this; 00121 parent->remove_child(this); 00122 do_triangulate(parent); 00123 00124 return save_me; 00125 } 00126 00127 //////////////////////////////////////////////////////////////////// 00128 // Function: EggCompositePrimitive::unify_attributes 00129 // Access: Published, Virtual 00130 // Description: If the shading property is S_per_vertex, ensures that 00131 // all vertices have a normal and a color, and the 00132 // overall primitive does not. 00133 // 00134 // If the shading property is S_per_face, and this is a 00135 // composite primitive, ensures that all components have 00136 // a normal and a color, and the vertices and overall 00137 // primitive do not. (If this is a simple primitive, 00138 // S_per_face works the same as S_overall, below). 00139 // 00140 // If the shading property is S_overall, ensures that no 00141 // vertices or components have a normal or a color, and 00142 // the overall primitive does (if any exists at all). 00143 // 00144 // After this call, either the primitive will have 00145 // normals or its vertices will, but not both. Ditto 00146 // for colors. 00147 // 00148 // This may create redundant vertices in the vertex 00149 // pool. 00150 //////////////////////////////////////////////////////////////////// 00151 void EggCompositePrimitive:: 00152 unify_attributes(EggPrimitive::Shading shading) { 00153 if (shading == S_unknown) { 00154 shading = get_shading(); 00155 } 00156 00157 switch (shading) { 00158 case S_per_vertex: 00159 // Propagate everything to the vertices. 00160 { 00161 Components::iterator ci; 00162 for (ci = _components.begin(); ci != _components.end(); ++ci) { 00163 EggAttributes *component = (*ci); 00164 if (component->has_normal()) { 00165 if (!has_normal()) { 00166 copy_normal(*component); 00167 } 00168 component->clear_normal(); 00169 } 00170 if (component->has_color()) { 00171 if (!has_color()) { 00172 copy_color(*component); 00173 } 00174 component->clear_color(); 00175 } 00176 } 00177 00178 // Not having a color is implicitly white. 00179 if (!has_color()) { 00180 set_color(LColor(1.0f, 1.0f, 1.0f, 1.0f)); 00181 } 00182 00183 iterator pi; 00184 for (pi = begin(); pi != end(); ++pi) { 00185 EggVertex *orig_vertex = (*pi); 00186 PT(EggVertex) vertex = new EggVertex(*orig_vertex); 00187 if (!vertex->has_normal() && has_normal()) { 00188 vertex->copy_normal(*this); 00189 } 00190 if (!vertex->has_color() && has_color()) { 00191 vertex->copy_color(*this); 00192 } 00193 00194 EggVertexPool *vertex_pool = orig_vertex->get_pool(); 00195 nassertv(vertex_pool != (EggVertexPool *)NULL); 00196 vertex = vertex_pool->create_unique_vertex(*vertex); 00197 vertex->copy_grefs_from(*orig_vertex); 00198 replace(pi, vertex); 00199 } 00200 clear_normal(); 00201 clear_color(); 00202 } 00203 break; 00204 00205 case S_per_face: 00206 // Propagate everything to the components. 00207 { 00208 iterator pi; 00209 for (pi = begin(); pi != end(); ++pi) { 00210 EggVertex *orig_vertex = (*pi); 00211 if (orig_vertex->has_normal() || orig_vertex->has_color()) { 00212 if (orig_vertex->has_normal() && !has_normal()) { 00213 copy_normal(*orig_vertex); 00214 } 00215 if (orig_vertex->has_color() && !has_color()) { 00216 copy_color(*orig_vertex); 00217 } 00218 00219 PT(EggVertex) vertex = new EggVertex(*orig_vertex); 00220 vertex->clear_normal(); 00221 vertex->clear_color(); 00222 00223 EggVertexPool *vertex_pool = orig_vertex->get_pool(); 00224 nassertv(vertex_pool != (EggVertexPool *)NULL); 00225 vertex = vertex_pool->create_unique_vertex(*vertex); 00226 vertex->copy_grefs_from(*orig_vertex); 00227 replace(pi, vertex); 00228 } 00229 } 00230 00231 // Not having a color is implicitly white. 00232 if (!has_color()) { 00233 set_color(LColor(1.0f, 1.0f, 1.0f, 1.0f)); 00234 } 00235 00236 Components::iterator ci; 00237 for (ci = _components.begin(); ci != _components.end(); ++ci) { 00238 EggAttributes *component = (*ci); 00239 if (!component->has_normal() && has_normal()) { 00240 component->copy_normal(*this); 00241 } 00242 if (!component->has_color() && has_color()) { 00243 component->copy_color(*this); 00244 } 00245 } 00246 clear_normal(); 00247 clear_color(); 00248 } 00249 break; 00250 00251 case S_overall: 00252 // Remove everything from the vertices and components. 00253 { 00254 iterator pi; 00255 for (pi = begin(); pi != end(); ++pi) { 00256 EggVertex *orig_vertex = (*pi); 00257 PT(EggVertex) vertex = new EggVertex(*orig_vertex); 00258 if (vertex->has_normal()) { 00259 if (!has_normal()) { 00260 copy_normal(*vertex); 00261 } 00262 vertex->clear_normal(); 00263 } 00264 if (vertex->has_color()) { 00265 if (!has_color()) { 00266 copy_color(*vertex); 00267 } 00268 vertex->clear_color(); 00269 } 00270 00271 EggVertexPool *vertex_pool = orig_vertex->get_pool(); 00272 nassertv(vertex_pool != (EggVertexPool *)NULL); 00273 vertex = vertex_pool->create_unique_vertex(*vertex); 00274 vertex->copy_grefs_from(*orig_vertex); 00275 replace(pi, vertex); 00276 } 00277 Components::iterator ci; 00278 for (ci = _components.begin(); ci != _components.end(); ++ci) { 00279 EggAttributes *component = (*ci); 00280 if (component->has_normal()) { 00281 if (!has_normal()) { 00282 copy_normal(*component); 00283 } 00284 component->clear_normal(); 00285 } 00286 if (component->has_color()) { 00287 if (!has_color()) { 00288 copy_color(*component); 00289 } 00290 component->clear_color(); 00291 } 00292 } 00293 00294 // Not having a color is implicitly white. 00295 if (!has_color()) { 00296 set_color(LColor(1.0f, 1.0f, 1.0f, 1.0f)); 00297 } 00298 } 00299 break; 00300 00301 case S_unknown: 00302 break; 00303 } 00304 } 00305 00306 //////////////////////////////////////////////////////////////////// 00307 // Function: EggCompositePrimitive::apply_last_attribute 00308 // Access: Published, Virtual 00309 // Description: Sets the last vertex of the triangle (or each 00310 // component) to the primitive normal and/or color, if 00311 // the primitive is flat-shaded. This reflects the 00312 // OpenGL convention of storing flat-shaded properties on 00313 // the last vertex, although it is not usually a 00314 // convention in Egg. 00315 // 00316 // This may introduce redundant vertices to the vertex 00317 // pool. 00318 //////////////////////////////////////////////////////////////////// 00319 void EggCompositePrimitive:: 00320 apply_last_attribute() { 00321 // The first component gets applied to the third vertex, and so on 00322 // from there. 00323 int num_lead_vertices = get_num_lead_vertices(); 00324 for (int i = 0; i < get_num_components(); i++) { 00325 EggAttributes *component = get_component(i); 00326 do_apply_flat_attribute(i + num_lead_vertices, component); 00327 } 00328 } 00329 00330 //////////////////////////////////////////////////////////////////// 00331 // Function: EggCompositePrimitive::apply_first_attribute 00332 // Access: Published, Virtual 00333 // Description: Sets the first vertex of the triangle (or each 00334 // component) to the primitive normal and/or color, if 00335 // the primitive is flat-shaded. This reflects the 00336 // DirectX convention of storing flat-shaded properties 00337 // on the first vertex, although it is not usually a 00338 // convention in Egg. 00339 // 00340 // This may introduce redundant vertices to the vertex 00341 // pool. 00342 //////////////////////////////////////////////////////////////////// 00343 void EggCompositePrimitive:: 00344 apply_first_attribute() { 00345 // The first component gets applied to the first vertex, and so on 00346 // from there. 00347 for (int i = 0; i < get_num_components(); i++) { 00348 EggAttributes *component = get_component(i); 00349 do_apply_flat_attribute(i, component); 00350 } 00351 } 00352 00353 //////////////////////////////////////////////////////////////////// 00354 // Function: EggCompositePrimitive::post_apply_flat_attribute 00355 // Access: Published, Virtual 00356 // Description: Intended as a followup to apply_last_attribute(), 00357 // this also sets an attribute on the first vertices of 00358 // the primitive, if they don't already have an 00359 // attribute set, just so they end up with *something*. 00360 //////////////////////////////////////////////////////////////////// 00361 void EggCompositePrimitive:: 00362 post_apply_flat_attribute() { 00363 if (!empty()) { 00364 int num_lead_vertices = get_num_lead_vertices(); 00365 for (int i = 0; i < (int)size(); i++) { 00366 EggVertex *vertex = get_vertex(i); 00367 EggAttributes *component = get_component(max(i - num_lead_vertices, 0)); 00368 00369 // Use set_normal() instead of copy_normal(), to avoid getting 00370 // the morphs--we don't want them here, since we're just putting 00371 // a bogus value on the normal anyway. 00372 00373 if (component->has_normal() && !vertex->has_normal()) { 00374 vertex->set_normal(component->get_normal()); 00375 } else if (has_normal() && !vertex->has_normal()) { 00376 vertex->set_normal(get_normal()); 00377 } 00378 00379 if (component->has_color() && !vertex->has_color()) { 00380 vertex->set_color(component->get_color()); 00381 } else if (has_color() && !vertex->has_color()) { 00382 vertex->set_color(get_color()); 00383 } 00384 } 00385 } 00386 } 00387 00388 //////////////////////////////////////////////////////////////////// 00389 // Function: EggCompositePrimitive::cleanup 00390 // Access: Published, Virtual 00391 // Description: Cleans up modeling errors in whatever context this 00392 // makes sense. For instance, for a polygon, this calls 00393 // remove_doubled_verts(true). For a point, it calls 00394 // remove_nonunique_verts(). Returns true if the 00395 // primitive is valid, or false if it is degenerate. 00396 //////////////////////////////////////////////////////////////////// 00397 bool EggCompositePrimitive:: 00398 cleanup() { 00399 return (int)size() >= get_num_lead_vertices() + 1; 00400 } 00401 00402 //////////////////////////////////////////////////////////////////// 00403 // Function: EggCompositePrimitive::prepare_add_vertex 00404 // Access: Protected, Virtual 00405 // Description: Marks the vertex as belonging to the primitive. This 00406 // is an internal function called by the STL-like 00407 // functions push_back() and insert(), in preparation 00408 // for actually adding the vertex. 00409 // 00410 // i indicates the new position of the vertex in the 00411 // list; n indicates the new number of vertices after 00412 // the operation has completed. 00413 //////////////////////////////////////////////////////////////////// 00414 void EggCompositePrimitive:: 00415 prepare_add_vertex(EggVertex *vertex, int i, int n) { 00416 EggPrimitive::prepare_add_vertex(vertex, i, n); 00417 00418 int num_lead_vertices = get_num_lead_vertices(); 00419 if (n >= num_lead_vertices + 1) { 00420 i = max(i - num_lead_vertices, 0); 00421 nassertv(i <= (int)_components.size()); 00422 _components.insert(_components.begin() + i, new EggAttributes(*this)); 00423 } 00424 } 00425 00426 00427 //////////////////////////////////////////////////////////////////// 00428 // Function: EggCompositePrimitive::prepare_remove_vertex 00429 // Access: Protected, Virtual 00430 // Description: Marks the vertex as removed from the primitive. This 00431 // is an internal function called by the STL-like 00432 // functions pop_back() and erase(), in preparation for 00433 // actually doing the removal. 00434 // 00435 // i indicates the former position of the vertex in the 00436 // list; n indicates the current number of vertices 00437 // before the operation has completed. 00438 // 00439 // It is an error to attempt to remove a vertex that is 00440 // not already a vertex of this primitive. 00441 //////////////////////////////////////////////////////////////////// 00442 void EggCompositePrimitive:: 00443 prepare_remove_vertex(EggVertex *vertex, int i, int n) { 00444 EggPrimitive::prepare_remove_vertex(vertex, i, n); 00445 00446 int num_lead_vertices = get_num_lead_vertices(); 00447 if (n >= num_lead_vertices + 1) { 00448 i = max(i - num_lead_vertices, 0); 00449 nassertv(i < (int)_components.size()); 00450 delete _components[i]; 00451 _components.erase(_components.begin() + i); 00452 } 00453 } 00454 00455 //////////////////////////////////////////////////////////////////// 00456 // Function: EggCompositePrimitive::triangulate_poly 00457 // Access: Protected, Virtual 00458 // Description: Fills the container up with EggPolygons that 00459 // represent the component triangles of this triangle 00460 // strip. 00461 // 00462 // It is assumed that the EggCompositePrimitive is not 00463 // already a child of any other group when this function 00464 // is called. 00465 // 00466 // Returns true if the triangulation is successful, or 00467 // false if there was some error (in which case the 00468 // container may contain some partial triangulation). 00469 //////////////////////////////////////////////////////////////////// 00470 bool EggCompositePrimitive:: 00471 do_triangulate(EggGroupNode *container) const { 00472 container->add_child((EggCompositePrimitive *)this); 00473 return true; 00474 } 00475 00476 //////////////////////////////////////////////////////////////////// 00477 // Function: EggCompositePrimitive::write_body 00478 // Access: Protected 00479 // Description: Writes the attributes and the vertices referenced by 00480 // the primitive to the indicated output stream in Egg 00481 // format. 00482 //////////////////////////////////////////////////////////////////// 00483 void EggCompositePrimitive:: 00484 write_body(ostream &out, int indent_level) const { 00485 EggPrimitive::write_body(out, indent_level); 00486 00487 for (int i = 0; i < get_num_components(); i++) { 00488 const EggAttributes *attrib = get_component(i); 00489 if (attrib->compare_to(*this) != 0 && 00490 (attrib->has_color() || attrib->has_normal())) { 00491 indent(out, indent_level) 00492 << "<Component> " << i << " {\n"; 00493 attrib->write(out, indent_level + 2); 00494 indent(out, indent_level) << "}\n"; 00495 } 00496 } 00497 }