Panda3D

eggCompositePrimitive.cxx

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 }
 All Classes Functions Variables Enumerations