瀏覽代碼

more new geom work

David Rose 21 年之前
父節點
當前提交
d4401c9c43

+ 17 - 0
panda/src/egg/eggCompositePrimitive.I

@@ -104,3 +104,20 @@ set_component(int i, const EggAttributes *attrib) {
   nassertv(i >= 0 && i < (int)_components.size());
   _components[i] = new EggAttributes(*attrib);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggCompositePrimitive::triangulate_into
+//       Access: Published
+//  Description: Subdivides the composite primitive into triangles and
+//               adds those triangles to the indicated container.
+//               Does not remove the primitive from its existing
+//               parent or modify it in any way.
+//
+//               Returns true if the triangulation is successful, or
+//               false if there was some error (in which case the
+//               container may contain some partial triangulation).
+////////////////////////////////////////////////////////////////////
+INLINE bool EggCompositePrimitive::
+triangulate_into(EggGroupNode *container) const {
+  return do_triangulate(container);
+}

+ 2 - 1
panda/src/egg/eggCompositePrimitive.h

@@ -42,13 +42,14 @@ PUBLISHED:
   INLINE EggAttributes *get_component(int i);
   INLINE void set_component(int i, const EggAttributes *attrib);
 
+  INLINE bool triangulate_into(EggGroupNode *container) const;
   PT(EggCompositePrimitive) triangulate_in_place();
 
 protected:
   virtual void prepare_add_vertex(EggVertex *vertex, int i, int n);
   virtual void prepare_remove_vertex(EggVertex *vertex, int i, int n);
 
-  virtual void do_triangulate(EggGroupNode *container)=0;
+  virtual bool do_triangulate(EggGroupNode *container) const=0;
 
   void write_body(ostream &out, int indent_level) const;
 

+ 2 - 0
panda/src/egg/eggGroupNode.cxx

@@ -1253,6 +1253,8 @@ r_load_externals(const DSearchPath &searchpath, CoordinateSystem coordsys) {
 void EggGroupNode::
 prepare_add_child(EggNode *node) {
   nassertv(node != (EggNode *)NULL);
+  test_ref_count_integrity();
+  node->test_ref_count_integrity();
   // Make sure the node is not already a child of some other group.
   nassertv(node->get_parent() == NULL);
   nassertv(node->get_depth() == 0);

+ 76 - 36
panda/src/egg/eggMesher.cxx

@@ -42,54 +42,74 @@ EggMesher() {
 //       Access: Public
 //  Description: Accepts an EggGroupNode, which contains a set of
 //               EggPrimitives--typically, triangles and quads--as
-//               children.  All of the EggPrimitives must reference
-//               the same vertex pool.
-//
-//               At the completion of this function, the triangles in
-//               the group will have been replaced with
-//               EggTriangleStrips as appropriate.
+//               children.  Removes these primitives and replaces them
+//               with (mostly) equivalent EggTriangleStrips and
+//               EggTriangleFans where possible.
 ////////////////////////////////////////////////////////////////////
 void EggMesher::
 mesh(EggGroupNode *group) {
-  _vertex_pool = NULL;
-  _strip_index = 0;
+  // Create a temporary node to hold the children of group that aren't
+  // involved in the meshing, as well as the newly-generate triangle
+  // strips.
+  PT(EggGroupNode) output_children = new EggGroupNode;
+
+  // And another to hold the children that will be processed next
+  // time.
+  PT(EggGroupNode) next_children = new EggGroupNode;
+  PT(EggGroupNode) this_children = group;
+
+  // Only primitives that share a common vertex pool can be meshed
+  // together.  Thus, pull out the primitives with the same vertex
+  // pool in groups.
+  while (this_children->size() != 0) {
+    clear();
+
+    // Add each polygon in the group to the mesh pool.
+    while (!this_children->empty()) {
+      PT(EggNode) child = this_children->get_first_child();
+      this_children->remove_child(child);
+      
+      if (child->is_of_type(EggPolygon::get_class_type())) {
+        EggPolygon *poly = DCAST(EggPolygon, child);
 
-  // Create a temporary node to hold the children of groupthat aren't
-  // involved in the meshing.
-  PT(EggGroupNode) saved_children = new EggGroupNode;
+        if (_vertex_pool == (EggVertexPool *)NULL) {
+          _vertex_pool = poly->get_pool();
+          add_polygon(poly, EggMesherStrip::MO_user);
 
-  // Add each primitive in the group to the mesh pool.
-  EggGroupNode::iterator ci = group->begin();
-  while (ci != group->end()) {
-    EggGroupNode::iterator cnext = ci;
-    ++cnext;
+        } else if (_vertex_pool == poly->get_pool()) {
+          add_polygon(poly, EggMesherStrip::MO_user);
 
-    if ((*ci)->is_of_type(EggPolygon::get_class_type())) {
-      add_polygon(DCAST(EggPolygon, *ci), EggMesherStrip::MO_user);
-    } else {
-      // If it's not a polygon, preserve it.
-      saved_children->add_child(*ci);
+        } else {
+          // A different vertex pool; save this one for next pass.
+          next_children->add_child(poly);
+        }
+
+      } else {
+        // If it's not a polygon of any kind, just output it
+        // unchanged.
+        output_children->add_child(child);
+      }
+    }
+    
+    do_mesh();
+    
+    Strips::iterator si;
+    for (si = _done.begin(); si != _done.end(); ++si) {
+      PT(EggPrimitive) egg_prim = get_prim(*si);
+      if (egg_prim != (EggPrimitive *)NULL) {
+        output_children->add_child(egg_prim);
+      }
     }
-    ci = cnext;
-  }
 
-  do_mesh();
+    this_children = next_children;
+    next_children = new EggGroupNode;
+  }
 
   // Now copy the newly-meshed primitives back to the group.
   group->clear();
-  group->steal_children(*saved_children);
+  group->steal_children(*output_children);
 
-  Strips::iterator si;
-  for (si = _done.begin(); si != _done.end(); ++si) {
-    PT(EggPrimitive) egg_prim = get_prim(*si);
-    if (egg_prim != (EggPrimitive *)NULL) {
-      group->add_child(egg_prim);
-    }
-  }
-
-  _vertex_pool = NULL;
-  _strip_index = 0;
-  _color_sheets.clear();
+  clear();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -136,6 +156,26 @@ write(ostream &out) const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesher::clear
+//       Access: Private
+//  Description: Empties the pool of meshable primitives and resets to
+//               an initial state.
+////////////////////////////////////////////////////////////////////
+void EggMesher::
+clear() {
+  _tris.clear();
+  _quads.clear();
+  _strips.clear();
+  _dead.clear();
+  _done.clear();
+  _verts.clear();
+  _edges.clear();
+  _strip_index = 0;
+  _vertex_pool = NULL;
+  _color_sheets.clear();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggMesher::add_polygon
 //       Access: Private

+ 1 - 0
panda/src/egg/eggMesher.h

@@ -53,6 +53,7 @@ public:
   bool _show_qsheets;
 
 private:
+  void clear();
   bool add_polygon(const EggPolygon *egg_poly, 
                    EggMesherStrip::MesherOrigin origin);
   void do_mesh();

+ 10 - 4
panda/src/egg/eggTriangleStrip.cxx

@@ -65,13 +65,17 @@ write(ostream &out, int indent_level) const {
 //               It is assumed that the EggTriangleStrip is not
 //               already a child of any other group when this function
 //               is called.
+//
+//               Returns true if the triangulation is successful, or
+//               false if there was some error (in which case the
+//               container may contain some partial triangulation).
 ////////////////////////////////////////////////////////////////////
-void EggTriangleStrip::
-do_triangulate(EggGroupNode *container) {
+bool EggTriangleStrip::
+do_triangulate(EggGroupNode *container) const {
   if (size() < 3) {
-    return;
+    return false;
   }
-  iterator vi = begin();
+  const_iterator vi = begin();
   EggVertex *v0 = (*vi);
   ++vi;
   EggVertex *v1 = (*vi);
@@ -104,4 +108,6 @@ do_triangulate(EggGroupNode *container) {
     container->add_child(poly);
     ++vi;
   }
+
+  return true;
 }

+ 1 - 1
panda/src/egg/eggTriangleStrip.h

@@ -40,7 +40,7 @@ PUBLISHED:
   virtual void write(ostream &out, int indent_level) const;
 
 protected:
-  virtual void do_triangulate(EggGroupNode *container);
+  virtual bool do_triangulate(EggGroupNode *container) const;
 
 public:
   static TypeHandle get_class_type() {

+ 30 - 9
panda/src/egg2pg/eggLoader.cxx

@@ -134,11 +134,12 @@ EggLoader() {
 ////////////////////////////////////////////////////////////////////
 //     Function: EggLoader::Constructor
 //       Access: Public
-//  Description:
+//  Description: The EggLoader constructor makes a copy of the EggData
+//               passed in.
 ////////////////////////////////////////////////////////////////////
 EggLoader::
-EggLoader(const EggData &data) :
-  _data(new EggData(data))
+EggLoader(const EggData *data) :
+  _data(new EggData(*data))
 {
   _error = false;
 }
@@ -1595,8 +1596,8 @@ make_node(EggGroup *egg_group, PandaNode *parent) {
     if (pnode->get_num_vertices() == 0) {
       egg2pg_cat.warning()
         << "Portal " << egg_group->get_name() << " has no vertices!\n";
-	}
-
+    }
+    
   } else if (egg_group->get_polylight_flag()) {
     // Create a polylight instead of a regular polyset.
     // use make_sphere to get the center, radius and color
@@ -1987,7 +1988,7 @@ void EggLoader::
 set_portal_polygon(EggGroup *egg_group, PortalNode *pnode) {
   pnode->clear_vertices();
 
-  EggPolygon *poly = find_first_polygon(egg_group);
+  PT(EggPolygon) poly = find_first_polygon(egg_group);
   if (poly != (EggPolygon *)NULL) {
     LMatrix4d mat = poly->get_vertex_to_node();
 
@@ -2005,7 +2006,7 @@ set_portal_polygon(EggGroup *egg_group, PortalNode *pnode) {
 //  Description: Returns the first EggPolygon found at or below the
 //               indicated node.
 ////////////////////////////////////////////////////////////////////
-EggPolygon *EggLoader::
+PT(EggPolygon) EggLoader::
 find_first_polygon(EggGroup *egg_group) {
   // Does this group have any polygons?
   EggGroup::const_iterator ci;
@@ -2021,8 +2022,8 @@ find_first_polygon(EggGroup *egg_group) {
   for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
     if ((*ci)->is_of_type(EggGroup::get_class_type())) {
       EggGroup *child_group = DCAST(EggGroup, *ci);
-      EggPolygon *found = find_first_polygon(child_group);
-      if (found != NULL) {
+      PT(EggPolygon) found = find_first_polygon(child_group);
+      if (found != (EggPolygon *)NULL) {
         return found;
       }
     }
@@ -2181,6 +2182,13 @@ make_collision_plane(EggGroup *egg_group, CollisionNode *cnode,
           cnode->add_solid(csplane);
           return;
         }
+      } else if ((*ci)->is_of_type(EggCompositePrimitive::get_class_type())) {
+        EggCompositePrimitive *comp = DCAST(EggCompositePrimitive, *ci);
+        PT(EggGroup) temp_group = new EggGroup;
+        if (comp->triangulate_into(temp_group)) {
+          make_collision_plane(temp_group, cnode, flags);
+          return;
+        }
       }
     }
   }
@@ -2203,6 +2211,13 @@ make_collision_polygon(EggGroup *egg_group, CollisionNode *cnode,
       if ((*ci)->is_of_type(EggPolygon::get_class_type())) {
         create_collision_polygons(cnode, DCAST(EggPolygon, *ci),
                                   egg_group, flags);
+      } else if ((*ci)->is_of_type(EggCompositePrimitive::get_class_type())) {
+        EggCompositePrimitive *comp = DCAST(EggCompositePrimitive, *ci);
+        PT(EggGroup) temp_group = new EggGroup;
+        if (comp->triangulate_into(temp_group)) {
+          make_collision_polygon(temp_group, cnode, flags);
+          return;
+        }
       }
     }
   }
@@ -2224,6 +2239,12 @@ make_collision_polyset(EggGroup *egg_group, CollisionNode *cnode,
       if ((*ci)->is_of_type(EggPolygon::get_class_type())) {
         create_collision_polygons(cnode, DCAST(EggPolygon, *ci),
                                   egg_group, flags);
+      } else if ((*ci)->is_of_type(EggCompositePrimitive::get_class_type())) {
+        EggCompositePrimitive *comp = DCAST(EggCompositePrimitive, *ci);
+        PT(EggGroup) temp_group = new EggGroup;
+        if (comp->triangulate_into(temp_group)) {
+          make_collision_polyset(temp_group, cnode, flags);
+        }
       }
     }
   }

+ 2 - 2
panda/src/egg2pg/eggLoader.h

@@ -69,7 +69,7 @@ class PolylightNode;
 class EggLoader {
 public:
   EggLoader();
-  EggLoader(const EggData &data);
+  EggLoader(const EggData *data);
 
   void build_graph();
   void reparent_decals();
@@ -133,7 +133,7 @@ private:
   void make_primitive(EggPrimitive *egg_prim, Primitives &primitives);
 
   void set_portal_polygon(EggGroup *egg_group, PortalNode *pnode);
-  EggPolygon *find_first_polygon(EggGroup *egg_group);
+  PT(EggPolygon) find_first_polygon(EggGroup *egg_group);
 
   bool make_sphere(EggGroup *start_group, EggGroup::CollideFlags flags,
                    LPoint3f &center, float &radius, Colorf &color);

+ 2 - 2
panda/src/egg2pg/load_egg_file.cxx

@@ -117,11 +117,11 @@ load_egg_file(const string &filename, CoordinateSystem cs) {
 //               loading.
 ////////////////////////////////////////////////////////////////////
 PT(PandaNode)
-load_egg_data(EggData &data, CoordinateSystem cs) {
+load_egg_data(EggData *data, CoordinateSystem cs) {
   // We temporarily shuttle the children to a holding node so we can
   // copy them into the EggLoader's structure without it complaining.
   EggGroupNode children_holder;
-  children_holder.steal_children(data);
+  children_holder.steal_children(*data);
 
   EggLoader loader(data);
   loader._data->steal_children(children_holder);

+ 1 - 1
panda/src/egg2pg/load_egg_file.h

@@ -48,7 +48,7 @@ load_egg_file(const string &filename, CoordinateSystem cs = CS_default);
 //               loading.
 ////////////////////////////////////////////////////////////////////
 EXPCL_PANDAEGG PT(PandaNode)
-load_egg_data(EggData &data, CoordinateSystem cs = CS_default);
+load_egg_data(EggData *data, CoordinateSystem cs = CS_default);
 END_PUBLISH
 
 #endif

+ 6 - 6
panda/src/gobj/qpgeomPrimitive.I

@@ -58,19 +58,19 @@ get_vertices() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::get_vertices
 //       Access: Published
-//  Description: Returns a const pointer to the primitive lengths
+//  Description: Returns a const pointer to the primitive ends
 //               array so application code can read it directly.  Do
 //               not attempt to modify the returned array; use
-//               modify_lengths() or set_lengths() for this.
+//               modify_ends() or set_ends() for this.
 //
 //               Note that simple primitive types, like triangles, do
-//               not have a lengths array: since all the primitives
+//               not have a ends array: since all the primitives
 //               have the same number of vertices, it is not needed.
 ////////////////////////////////////////////////////////////////////
 INLINE CPTA_int qpGeomPrimitive::
-get_lengths() const {
+get_ends() const {
   CDReader cdata(_cycler);
-  return cdata->_lengths;
+  return cdata->_ends;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -124,7 +124,7 @@ CData() :
 INLINE qpGeomPrimitive::CData::
 CData(const qpGeomPrimitive::CData &copy) :
   _vertices(copy._vertices),
-  _lengths(copy._lengths),
+  _ends(copy._ends),
   _got_minmax(copy._got_minmax),
   _min_vertex(copy._min_vertex),
   _max_vertex(copy._max_vertex)

+ 43 - 23
panda/src/gobj/qpgeomPrimitive.cxx

@@ -141,11 +141,16 @@ close_primitive() {
   if (num_vertices_per_primitive == 0) {
     // This is a complex primitive type like a triangle strip: each
     // primitive uses a different number of vertices.
-    if (cdata->_lengths.empty()) {
-      cdata->_lengths.push_back((int)cdata->_vertices.size());
-    } else if (cdata->_lengths.back() != (int)cdata->_vertices.size()) {
-      cdata->_lengths.push_back((int)cdata->_vertices.size() - cdata->_lengths.back());
+#ifndef NDEBUG
+    int num_added;
+    if (cdata->_ends.empty()) {
+      num_added = (int)cdata->_vertices.size();
+    } else {
+      num_added = (int)cdata->_vertices.size() - cdata->_ends.back();
     }
+    nassertv(num_added >= get_min_num_vertices_per_primitive());
+#endif
+    cdata->_ends.push_back((int)cdata->_vertices.size());
 
   } else {
     // This is a simple primitive type like a triangle: each primitive
@@ -166,7 +171,7 @@ clear_vertices() {
   clear_cache();
   CDWriter cdata(_cycler);
   cdata->_vertices.clear();
-  cdata->_lengths.clear();
+  cdata->_ends.clear();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -189,7 +194,7 @@ modify_vertices() {
 //       Access: Published
 //  Description: Completely replaces the vertex index list with a new
 //               table.  Chances are good that you should also replace
-//               the lengths list with set_lengths() at the same time.
+//               the ends list with set_ends() at the same time.
 ////////////////////////////////////////////////////////////////////
 void qpGeomPrimitive::
 set_vertices(PTA_ushort vertices) {
@@ -199,41 +204,41 @@ set_vertices(PTA_ushort vertices) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: qpGeomPrimitive::modify_lengths
+//     Function: qpGeomPrimitive::modify_ends
 //       Access: Published
-//  Description: Returns a modifiable pointer to the primitive lengths
+//  Description: Returns a modifiable pointer to the primitive ends
 //               array, so application code can directly fiddle with
 //               this data.  Use with caution, since there are no
 //               checks that the data will be left in a stable state.
 //
 //               Note that simple primitive types, like triangles, do
-//               not have a lengths array: since all the primitives
+//               not have a ends array: since all the primitives
 //               have the same number of vertices, it is not needed.
 ////////////////////////////////////////////////////////////////////
 PTA_int qpGeomPrimitive::
-modify_lengths() {
+modify_ends() {
   clear_cache();
   CDWriter cdata(_cycler);
-  return cdata->_lengths;
+  return cdata->_ends;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: qpGeomPrimitive::set_lengths
+//     Function: qpGeomPrimitive::set_ends
 //       Access: Published
-//  Description: Completely replaces the primitive lengths array with
+//  Description: Completely replaces the primitive ends array with
 //               a new table.  Chances are good that you should also
 //               replace the vertices list with set_vertices() at the
 //               same time.
 //
 //               Note that simple primitive types, like triangles, do
-//               not have a lengths array: since all the primitives
+//               not have a ends array: since all the primitives
 //               have the same number of vertices, it is not needed.
 ////////////////////////////////////////////////////////////////////
 void qpGeomPrimitive::
-set_lengths(PTA_int lengths) {
+set_ends(PTA_int ends) {
   clear_cache();
   CDWriter cdata(_cycler);
-  cdata->_lengths = lengths;
+  cdata->_ends = ends;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -246,7 +251,7 @@ int qpGeomPrimitive::
 get_num_bytes() const {
   CDReader cdata(_cycler);
   return cdata->_vertices.size() * sizeof(short) +
-    cdata->_lengths.size() * sizeof(int);
+    cdata->_ends.size() * sizeof(int);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -265,6 +270,17 @@ get_num_vertices_per_primitive() const {
   return 0;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_min_num_vertices_per_primitive
+//       Access: Published, Virtual
+//  Description: Returns the minimum number of vertices that must be
+//               added before close_primitive() may legally be called.
+////////////////////////////////////////////////////////////////////
+int qpGeomPrimitive::
+get_min_num_vertices_per_primitive() const {
+  return 3;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::get_num_primitives
 //       Access: Published
@@ -280,7 +296,7 @@ get_num_primitives() const {
   if (num_vertices_per_primitive == 0) {
     // This is a complex primitive type like a triangle strip: each
     // primitive uses a different number of vertices.
-    return cdata->_lengths.size();
+    return cdata->_ends.size();
 
   } else {
     // This is a simple primitive type like a triangle: each primitive
@@ -293,7 +309,7 @@ get_num_primitives() const {
 //     Function: qpGeomPrimitive::get_primitive_start
 //       Access: Published
 //  Description: Returns the element within the _vertices list at which
-//               the ith primitive starts.  
+//               the ith primitive ends.  
 //
 //               If i is one more than the highest valid primitive
 //               vertex, the return value will be one more than the
@@ -310,11 +326,11 @@ get_primitive_start(int i) const {
     // This is a complex primitive type like a triangle strip: each
     // primitive uses a different number of vertices.
     CDReader cdata(_cycler);
-    nassertr(i >= 0 && i <= (int)cdata->_lengths.size(), -1);
+    nassertr(i >= 0 && i <= (int)cdata->_ends.size(), -1);
     if (i == 0) {
       return 0;
     } else {
-      return cdata->_lengths[i - 1];
+      return cdata->_ends[i - 1];
     }
 
   } else {
@@ -338,8 +354,12 @@ get_primitive_num_vertices(int i) const {
     // This is a complex primitive type like a triangle strip: each
     // primitive uses a different number of vertices.
     CDReader cdata(_cycler);
-    nassertr(i >= 0 && i < (int)cdata->_lengths.size(), 0);
-    return cdata->_lengths[i];
+    nassertr(i >= 0 && i < (int)cdata->_ends.size(), 0);
+    if (i == 0) {
+      return cdata->_ends[0];
+    } else {
+      return cdata->_ends[i] - cdata->_ends[i - 1];
+    }      
 
   } else {
     // This is a simple primitive type like a triangle: each primitive

+ 5 - 4
panda/src/gobj/qpgeomPrimitive.h

@@ -75,9 +75,9 @@ PUBLISHED:
   PTA_ushort modify_vertices();
   void set_vertices(PTA_ushort vertices);
 
-  INLINE CPTA_int get_lengths() const;
-  PTA_int modify_lengths();
-  void set_lengths(PTA_int lengths);
+  INLINE CPTA_int get_ends() const;
+  PTA_int modify_ends();
+  void set_ends(PTA_int ends);
 
   int get_num_bytes() const;
 
@@ -85,6 +85,7 @@ PUBLISHED:
   INLINE int get_max_vertex() const;
 
   virtual int get_num_vertices_per_primitive() const;
+  virtual int get_min_num_vertices_per_primitive() const;
   int get_num_primitives() const;
   int get_primitive_start(int i) const;
   int get_primitive_num_vertices(int i) const;
@@ -121,7 +122,7 @@ private:
     virtual void fillin(DatagramIterator &scan, BamReader *manager);
 
     PTA_ushort _vertices;
-    PTA_int _lengths;
+    PTA_int _ends;
 
     bool _got_minmax;
     unsigned short _min_vertex;

+ 15 - 12
panda/src/gobj/qpgeomTrifans.cxx

@@ -81,28 +81,31 @@ PT(qpGeomPrimitive) qpGeomTrifans::
 decompose_impl() {
   PT(qpGeomTriangles) triangles = new qpGeomTriangles;
   CPTA_ushort vertices = get_vertices();
-  CPTA_int lengths = get_lengths();
+  CPTA_int ends = get_ends();
 
-  CPTA_ushort::const_iterator vi;
-  vi = vertices.begin();
-
-  CPTA_int::const_iterator li;
-  for (li = lengths.begin(); li != lengths.end(); ++li) {
-    int length = (*li);
-    nassertr(length >= 2, triangles.p());
-    int v0 = (*vi);
+  int vi = 0;
+  int li = 0;
+  while (li < (int)ends.size()) {
+    int end = ends[li];
+    nassertr(vi + 2 <= end, triangles.p());
+    nassertr(vi < (int)vertices.size(), this);
+    int v0 = vertices[vi];
     ++vi;
-    int v1 = (*vi);
+    nassertr(vi < (int)vertices.size(), this);
+    int v1 = vertices[vi];
     ++vi;
-    for (int i = 2; i < length; i++) {
+    while (vi < end) {
       triangles->add_vertex(v0);
       triangles->add_vertex(v1);
-      triangles->add_vertex(*vi);
+      triangles->add_vertex(vertices[vi]);
       triangles->close_primitive();
       ++vi;
     }
+    ++li;
   }
 
+  nassertr(vi == (int)vertices.size(), triangles.p());
+
   return triangles.p();
 }
 

+ 16 - 20
panda/src/gobj/qpgeomTristrips.cxx

@@ -81,26 +81,21 @@ PT(qpGeomPrimitive) qpGeomTristrips::
 decompose_impl() {
   PT(qpGeomTriangles) triangles = new qpGeomTriangles;
   CPTA_ushort vertices = get_vertices();
-  CPTA_int lengths = get_lengths();
+  CPTA_int ends = get_ends();
 
-  CPTA_ushort::const_iterator vi;
-  vi = vertices.begin();
-
-  cerr << "starting vertices, size = " << vertices.size() << "\n";
-
-  CPTA_int::const_iterator li;
-  for (li = lengths.begin(); li != lengths.end(); ++li) {
-    int length = (*li);
-    cerr << "length = " << length << "\n";
-    nassertr(length >= 2, triangles.p());
-    nassertr(vi != vertices.end(), this);
-    int v0 = (*vi);
+  int vi = 0;
+  int li = 0;
+  while (li < (int)ends.size()) {
+    int end = ends[li];
+    nassertr(vi + 2 <= end, triangles.p());
+    nassertr(vi < (int)vertices.size(), this);
+    int v0 = vertices[vi];
     ++vi;
-    nassertr(vi != vertices.end(), this);
-    int v1 = (*vi);
+    nassertr(vi < (int)vertices.size(), this);
+    int v1 = vertices[vi];
     ++vi;
     bool reversed = false;
-    for (int i = 2; i < length; i++) {
+    while (vi < end) {
       if (reversed) {
         triangles->add_vertex(v1);
         triangles->add_vertex(v0);
@@ -110,16 +105,17 @@ decompose_impl() {
         triangles->add_vertex(v1);
         reversed = true;
       }
-      triangles->add_vertex(*vi);
+      triangles->add_vertex(vertices[vi]);
       v0 = v1;
-      nassertr(vi != vertices.end(), this);
-      v1 = *vi;
+      nassertr(vi < (int)vertices.size(), this);
+      v1 = vertices[vi];
       triangles->close_primitive();
       ++vi;
     }
+    ++li;
   }
 
-  triangles->write(cerr, 0);
+  nassertr(vi == (int)vertices.size(), triangles.p());
 
   return triangles.p();
 }

+ 2 - 0
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -78,6 +78,7 @@ class CgShaderAttrib;
 class CullFaceAttrib;
 class StencilAttrib;
 class ClipPlaneAttrib;
+class ShadeModelAttrib;
 class TransparencyAttrib;
 class FogAttrib;
 class LinesmoothAttrib;
@@ -212,6 +213,7 @@ public:
   virtual void issue_cg_shader_bind(const CgShaderAttrib *){}
   virtual void issue_stencil(const StencilAttrib *) { }
   virtual void issue_clip_plane(const ClipPlaneAttrib *) { }
+  virtual void issue_shade_model(const ShadeModelAttrib *) { }
 
   virtual void bind_light(PointLight *light_obj, const NodePath &light, 
                           int light_id) { }

+ 3 - 0
panda/src/pgraph/Sources.pp

@@ -87,6 +87,7 @@
     sceneSetup.I sceneSetup.h \
     selectiveChildNode.I selectiveChildNode.h \
     sequenceNode.I sequenceNode.h \
+    shadeModelAttrib.I shadeModelAttrib.h \
     showBoundsEffect.I showBoundsEffect.h \
     spotlight.I spotlight.h \
     switchNode.I switchNode.h \
@@ -181,6 +182,7 @@
     sceneSetup.cxx \
     selectiveChildNode.cxx \
     sequenceNode.cxx \
+    shadeModelAttrib.cxx \
     showBoundsEffect.cxx \
     spotlight.cxx \
     switchNode.cxx \
@@ -273,6 +275,7 @@
     sceneSetup.I sceneSetup.h \
     selectiveChildNode.I selectiveChildNode.h \
     sequenceNode.I sequenceNode.h \
+    shadeModelAttrib.I shadeModelAttrib.h \
     showBoundsEffect.I showBoundsEffect.h \
     spotlight.I spotlight.h \
     switchNode.I switchNode.h \

+ 3 - 0
panda/src/pgraph/config_pgraph.cxx

@@ -78,6 +78,7 @@
 #include "rescaleNormalAttrib.h"
 #include "selectiveChildNode.h"
 #include "sequenceNode.h"
+#include "shadeModelAttrib.h"
 #include "showBoundsEffect.h"
 #include "spotlight.h"
 #include "switchNode.h"
@@ -277,6 +278,7 @@ init_libpgraph() {
   RescaleNormalAttrib::init_type();
   SelectiveChildNode::init_type();
   SequenceNode::init_type();
+  ShadeModelAttrib::init_type();
   ShowBoundsEffect::init_type();
   Spotlight::init_type();
   SwitchNode::init_type();
@@ -332,6 +334,7 @@ init_libpgraph() {
   RenderModeAttrib::register_with_read_factory();
   RenderState::register_with_read_factory();
   SequenceNode::register_with_read_factory();
+  ShadeModelAttrib::register_with_read_factory();
   ShowBoundsEffect::register_with_read_factory();
   Spotlight::register_with_read_factory();
   SwitchNode::register_with_read_factory();

+ 1 - 0
panda/src/pgraph/pgraph_composite2.cxx

@@ -32,6 +32,7 @@
 #include "sceneGraphReducer.cxx"
 #include "selectiveChildNode.cxx"
 #include "sequenceNode.cxx"
+#include "shadeModelAttrib.cxx"
 #include "showBoundsEffect.cxx"
 #include "spotlight.cxx"
 #include "switchNode.cxx"

+ 40 - 0
panda/src/pgraph/shadeModelAttrib.I

@@ -0,0 +1,40 @@
+// Filename: shadeModelAttrib.I
+// Created by:  drose (14Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShadeModelAttrib::Constructor
+//       Access: Private
+//  Description: Use ShadeModelAttrib::make() to construct a new
+//               ShadeModelAttrib object.
+////////////////////////////////////////////////////////////////////
+INLINE ShadeModelAttrib::
+ShadeModelAttrib(ShadeModelAttrib::Mode mode) :
+  _mode(mode)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShadeModelAttrib::get_mode
+//       Access: Published
+//  Description: Returns the shade mode.
+////////////////////////////////////////////////////////////////////
+INLINE ShadeModelAttrib::Mode ShadeModelAttrib::
+get_mode() const {
+  return _mode;
+}

+ 194 - 0
panda/src/pgraph/shadeModelAttrib.cxx

@@ -0,0 +1,194 @@
+// Filename: shadeModelAttrib.cxx
+// Created by:  drose (14Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "shadeModelAttrib.h"
+#include "graphicsStateGuardianBase.h"
+#include "dcast.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "datagram.h"
+#include "datagramIterator.h"
+
+TypeHandle ShadeModelAttrib::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShadeModelAttrib::make
+//       Access: Published, Static
+//  Description: Constructs a new ShadeModelAttrib object that specifies
+//               whether to draw polygons with flat shading or with
+//               per-vertex (smooth) shading.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) ShadeModelAttrib::
+make(ShadeModelAttrib::Mode mode) {
+  ShadeModelAttrib *attrib = new ShadeModelAttrib(mode);
+  return return_new(attrib);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShadeModelAttrib::issue
+//       Access: Public, Virtual
+//  Description: Calls the appropriate method on the indicated GSG
+//               to issue the graphics commands appropriate to the
+//               given attribute.  This is normally called
+//               (indirectly) only from
+//               GraphicsStateGuardian::set_state() or modify_state().
+////////////////////////////////////////////////////////////////////
+void ShadeModelAttrib::
+issue(GraphicsStateGuardianBase *gsg) const {
+  gsg->issue_shade_model(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShadeModelAttrib::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void ShadeModelAttrib::
+output(ostream &out) const {
+  out << get_type() << ":";
+  switch (get_mode()) {
+  case M_flat:
+    out << "flat";
+
+  case M_smooth:
+    out << "smooth";
+    break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShadeModelAttrib::compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived ShadeModelAttrib
+//               types to return a unique number indicating whether
+//               this ShadeModelAttrib is equivalent to the other one.
+//
+//               This should return 0 if the two ShadeModelAttrib objects
+//               are equivalent, a number less than zero if this one
+//               should be sorted before the other one, and a number
+//               greater than zero otherwise.
+//
+//               This will only be called with two ShadeModelAttrib
+//               objects whose get_type() functions return the same.
+////////////////////////////////////////////////////////////////////
+int ShadeModelAttrib::
+compare_to_impl(const RenderAttrib *other) const {
+  const ShadeModelAttrib *ta;
+  DCAST_INTO_R(ta, other, 0);
+  return (int)_mode - (int)ta->_mode;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShadeModelAttrib::compose_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived RenderAttrib
+//               types to specify how two consecutive RenderAttrib
+//               objects of the same type interact.
+//
+//               This should return the result of applying the other
+//               RenderAttrib to a node in the scene graph below this
+//               RenderAttrib, which was already applied.  In most
+//               cases, the result is the same as the other
+//               RenderAttrib (that is, a subsequent RenderAttrib
+//               completely replaces the preceding one).  On the other
+//               hand, some kinds of RenderAttrib (for instance,
+//               ColorTransformAttrib) might combine in meaningful
+//               ways.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) ShadeModelAttrib::
+compose_impl(const RenderAttrib *other) const {
+  const ShadeModelAttrib *ta;
+  DCAST_INTO_R(ta, other, 0);
+
+  Mode mode = ta->get_mode();
+  return make(mode);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShadeModelAttrib::make_default_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived ShadeModelAttrib
+//               types to specify what the default property for a
+//               ShadeModelAttrib of this type should be.
+//
+//               This should return a newly-allocated ShadeModelAttrib of
+//               the same type that corresponds to whatever the
+//               standard default for this kind of ShadeModelAttrib is.
+////////////////////////////////////////////////////////////////////
+RenderAttrib *ShadeModelAttrib::
+make_default_impl() const {
+  return new ShadeModelAttrib(M_smooth);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShadeModelAttrib::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               ShadeModelAttrib.
+////////////////////////////////////////////////////////////////////
+void ShadeModelAttrib::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShadeModelAttrib::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void ShadeModelAttrib::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  RenderAttrib::write_datagram(manager, dg);
+
+  dg.add_int8(_mode);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShadeModelAttrib::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type ShadeModelAttrib is encountered
+//               in the Bam file.  It should create the ShadeModelAttrib
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *ShadeModelAttrib::
+make_from_bam(const FactoryParams &params) {
+  ShadeModelAttrib *attrib = new ShadeModelAttrib(M_smooth);
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  attrib->fillin(scan, manager);
+
+  return attrib;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShadeModelAttrib::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new ShadeModelAttrib.
+////////////////////////////////////////////////////////////////////
+void ShadeModelAttrib::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  RenderAttrib::fillin(scan, manager);
+
+  _mode = (Mode)scan.get_int8();
+}

+ 89 - 0
panda/src/pgraph/shadeModelAttrib.h

@@ -0,0 +1,89 @@
+// Filename: shadeModelAttrib.h
+// Created by:  drose (14Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef SHADEMODELATTRIB_H
+#define SHADEMODELATTRIB_H
+
+#include "pandabase.h"
+
+#include "renderAttrib.h"
+
+class FactoryParams;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ShadeModelAttrib
+// Description : Specifies whether flat shading (per-polygon) or
+//               smooth shading (per-vertex) is in effect.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA ShadeModelAttrib : public RenderAttrib {
+PUBLISHED:
+  enum Mode {
+    M_flat,
+    M_smooth,
+  };
+
+private:
+  INLINE ShadeModelAttrib(Mode mode);
+
+PUBLISHED:
+  static CPT(RenderAttrib) make(Mode mode);
+
+  INLINE Mode get_mode() const;
+
+public:
+  virtual void issue(GraphicsStateGuardianBase *gsg) const;
+  virtual void output(ostream &out) const;
+
+protected:
+  virtual int compare_to_impl(const RenderAttrib *other) const;
+  virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const;
+  virtual RenderAttrib *make_default_impl() const;
+
+private:
+  Mode _mode;
+
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    RenderAttrib::init_type();
+    register_type(_type_handle, "ShadeModelAttrib",
+                  RenderAttrib::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "shadeModelAttrib.I"
+
+#endif
+