Browse Source

properly prevent flat-shaded trifans and odd-length tristrips

David Rose 21 years ago
parent
commit
6212af0b1b

+ 1 - 1
panda/src/egg/eggGroupNode.cxx

@@ -753,7 +753,7 @@ triangulate_polygons(int flags) {
 void EggGroupNode::
 void EggGroupNode::
 mesh_triangles(int flags) {
 mesh_triangles(int flags) {
   EggMesher mesher;
   EggMesher mesher;
-  mesher.mesh(this);
+  mesher.mesh(this, (flags & T_flat_shaded) != 0);
 
 
   if ((flags & T_recurse) != 0) {
   if ((flags & T_recurse) != 0) {
     EggGroupNode::iterator ci;
     EggGroupNode::iterator ci;

+ 5 - 4
panda/src/egg/eggGroupNode.h

@@ -131,10 +131,11 @@ PUBLISHED:
   void strip_normals();
   void strip_normals();
 
 
   enum TriangulateFlags {
   enum TriangulateFlags {
-    T_polygon   = 0x001,
-    T_convex    = 0x002,
-    T_composite = 0x004,
-    T_recurse   = 0x008
+    T_polygon     = 0x001,
+    T_convex      = 0x002,
+    T_composite   = 0x004,
+    T_recurse     = 0x008,
+    T_flat_shaded = 0x010,
   };
   };
 
 
   int triangulate_polygons(int flags);
   int triangulate_polygons(int flags);

+ 12 - 3
panda/src/egg/eggMesher.cxx

@@ -46,9 +46,17 @@ EggMesher() {
 //               children.  Removes these primitives and replaces them
 //               children.  Removes these primitives and replaces them
 //               with (mostly) equivalent EggTriangleStrips and
 //               with (mostly) equivalent EggTriangleStrips and
 //               EggTriangleFans where possible.
 //               EggTriangleFans where possible.
+//
+//               If flat_shaded is true, then odd-length triangle
+//               strips, and triangle fans of any length, are not
+//               permitted (because these can't be rotated when
+//               required to move the colored vertex of each triangle
+//               to the first or last position).
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void EggMesher::
 void EggMesher::
-mesh(EggGroupNode *group) {
+mesh(EggGroupNode *group, bool flat_shaded) {
+  _flat_shaded = flat_shaded;
+
   // Create a temporary node to hold the children of group that aren't
   // Create a temporary node to hold the children of group that aren't
   // involved in the meshing, as well as the newly-generate triangle
   // involved in the meshing, as well as the newly-generate triangle
   // strips.
   // strips.
@@ -204,7 +212,8 @@ add_polygon(const EggPolygon *egg_poly, EggMesherStrip::MesherOrigin origin) {
   }
   }
 
 
   // Define an initial strip (probably of length 1) for the prim.
   // Define an initial strip (probably of length 1) for the prim.
-  EggMesherStrip temp_strip(egg_poly, _strip_index++, _vertex_pool);
+  EggMesherStrip temp_strip(egg_poly, _strip_index++, _vertex_pool, 
+                            _flat_shaded);
   Strips &list = choose_strip_list(temp_strip);
   Strips &list = choose_strip_list(temp_strip);
   list.push_back(temp_strip);
   list.push_back(temp_strip);
   EggMesherStrip &strip = list.back();
   EggMesherStrip &strip = list.back();
@@ -267,7 +276,7 @@ add_polygon(const EggPolygon *egg_poly, EggMesherStrip::MesherOrigin origin) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void EggMesher::
 void EggMesher::
 do_mesh() {
 do_mesh() {
-  if (egg_consider_fans) {
+  if (egg_consider_fans && !_flat_shaded) {
     find_fans();
     find_fans();
   }
   }
 
 

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

@@ -40,7 +40,7 @@ class EggMesher {
 public:
 public:
   EggMesher();
   EggMesher();
 
 
-  void mesh(EggGroupNode *group);
+  void mesh(EggGroupNode *group, bool flat_shaded);
 
 
   void write(ostream &out) const;
   void write(ostream &out) const;
 
 
@@ -73,6 +73,7 @@ private:
   void mesh_list(Strips &strips);
   void mesh_list(Strips &strips);
   static void make_random_color(Colorf &color);
   static void make_random_color(Colorf &color);
 
 
+  bool _flat_shaded;
   Strips _tris, _quads, _strips;
   Strips _tris, _quads, _strips;
   Strips _dead, _done;
   Strips _dead, _done;
   Verts _verts;
   Verts _verts;

+ 1 - 3
panda/src/egg/eggMesherFanMaker.cxx

@@ -237,9 +237,7 @@ build(EggGroupNode *unrolled_tris) {
     return count;
     return count;
 
 
   } else {
   } else {
-    EggMesherStrip new_fan;
-    new_fan._type = EggMesherStrip::PT_trifan;
-    new_fan._origin = EggMesherStrip::MO_fanpoly;
+    EggMesherStrip new_fan(EggMesherStrip::PT_trifan, EggMesherStrip::MO_fanpoly);
     new_fan._verts.push_back(_vertex);
     new_fan._verts.push_back(_vertex);
 
 
     new_fan._verts.push_back(_edges.front()->_vi_a);
     new_fan._verts.push_back(_edges.front()->_vi_a);

+ 2 - 10
panda/src/egg/eggMesherStrip.I

@@ -17,15 +17,6 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: EggMesherStrip::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE EggMesherStrip::
-EggMesherStrip() {
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggMesherStrip::Copy Constructor
 //     Function: EggMesherStrip::Copy Constructor
 //       Access: Public
 //       Access: Public
@@ -42,7 +33,8 @@ EggMesherStrip(const EggMesherStrip &copy) :
   _planar(copy._planar),
   _planar(copy._planar),
   _plane_normal(copy._plane_normal),
   _plane_normal(copy._plane_normal),
   _plane_offset(copy._plane_offset),
   _plane_offset(copy._plane_offset),
-  _row_id(copy._row_id)
+  _row_id(copy._row_id),
+  _flat_shaded(copy._flat_shaded)
 {
 {
 }
 }
 
 

+ 32 - 3
panda/src/egg/eggMesherStrip.cxx

@@ -25,6 +25,23 @@
 #include "dcast.h"
 #include "dcast.h"
 #include "config_egg.h"
 #include "config_egg.h"
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherStrip::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+EggMesherStrip::
+EggMesherStrip(PrimType prim_type, MesherOrigin origin) {
+  _origin = origin;
+  _type = prim_type;
+
+  _index = -1;
+  _row_id = 0;
+  _status = MS_alive;
+  _planar = false;
+  _flat_shaded = false;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggMesherStrip::Constructor
 //     Function: EggMesherStrip::Constructor
 //       Access: Public
 //       Access: Public
@@ -32,11 +49,13 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 EggMesherStrip::
 EggMesherStrip::
 EggMesherStrip(const EggPrimitive *prim, int index, 
 EggMesherStrip(const EggPrimitive *prim, int index, 
-               const EggVertexPool *vertex_pool) {
+               const EggVertexPool *vertex_pool,
+               bool flat_shaded) {
   _index = index;
   _index = index;
   _row_id = 0;
   _row_id = 0;
   _status = MS_alive;
   _status = MS_alive;
   _origin = MO_unknown;
   _origin = MO_unknown;
+  _flat_shaded = flat_shaded;
 
 
   _type = PT_poly; //prim.get_type();
   _type = PT_poly; //prim.get_type();
 
 
@@ -430,7 +449,7 @@ mate(const EggVertexPool *vertex_pool) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool EggMesherStrip::
 bool EggMesherStrip::
 find_ideal_mate(EggMesherStrip *&mate, EggMesherEdge *&common_edge,
 find_ideal_mate(EggMesherStrip *&mate, EggMesherEdge *&common_edge,
-              const EggVertexPool *vertex_pool) {
+                const EggVertexPool *vertex_pool) {
   Edges::iterator ei;
   Edges::iterator ei;
 
 
   mate = NULL;
   mate = NULL;
@@ -442,7 +461,7 @@ find_ideal_mate(EggMesherStrip *&mate, EggMesherEdge *&common_edge,
     for (si = strips.begin(); si != strips.end(); ++si) {
     for (si = strips.begin(); si != strips.end(); ++si) {
       if (*si != this) {
       if (*si != this) {
         if (mate==NULL || pick_mate(**si, *mate, **ei, *common_edge,
         if (mate==NULL || pick_mate(**si, *mate, **ei, *common_edge,
-                                   vertex_pool)) {
+                                    vertex_pool)) {
           mate = *si;
           mate = *si;
           common_edge = *ei;
           common_edge = *ei;
         }
         }
@@ -616,6 +635,16 @@ mate_pieces(EggMesherEdge *common_edge, EggMesherStrip &front,
 bool EggMesherStrip::
 bool EggMesherStrip::
 mate_strips(EggMesherEdge *common_edge, EggMesherStrip &front, 
 mate_strips(EggMesherEdge *common_edge, EggMesherStrip &front, 
             EggMesherStrip &back, EggMesherStrip::PrimType type) {
             EggMesherStrip &back, EggMesherStrip::PrimType type) {
+  // If we're flat-shaded, we don't allow ending up with an odd-length
+  // strip.
+  if (front._flat_shaded && 
+      ((front._type != PT_tri && back._type == PT_tri) ||
+       (front._type == PT_tri && back._type != PT_tri) ||
+       (front._type == PT_tristrip && back._type == PT_tristrip &&
+        ((front._verts.size() + back._verts.size()) & 1) != 0))) {
+    return false;
+  }
+
   // If we start with a quad or tri, rotate the vertices around so we
   // If we start with a quad or tri, rotate the vertices around so we
   // start with the common edge.
   // start with the common edge.
   if (front._type == PT_tri || front._type == PT_quad) {
   if (front._type == PT_tri || front._type == PT_quad) {

+ 4 - 2
panda/src/egg/eggMesherStrip.h

@@ -56,8 +56,9 @@ public:
     MO_mate
     MO_mate
   };
   };
 
 
-  INLINE EggMesherStrip();
-  EggMesherStrip(const EggPrimitive *prim, int index, const EggVertexPool *vertex_pool);
+  EggMesherStrip(PrimType prim_type, MesherOrigin origin);
+  EggMesherStrip(const EggPrimitive *prim, int index, const EggVertexPool *vertex_pool,
+                 bool flat_shaded);
   INLINE EggMesherStrip(const EggMesherStrip &copy);
   INLINE EggMesherStrip(const EggMesherStrip &copy);
 
 
   PT(EggPrimitive) make_prim(const EggVertexPool *vertex_pool);
   PT(EggPrimitive) make_prim(const EggVertexPool *vertex_pool);
@@ -147,6 +148,7 @@ public:
   float _plane_offset;
   float _plane_offset;
   int _row_id, _row_distance;
   int _row_id, _row_distance;
   MesherOrigin _origin;
   MesherOrigin _origin;
+  bool _flat_shaded;
 };
 };
 
 
 INLINE ostream &
 INLINE ostream &

+ 3 - 3
panda/src/egg2pg/eggLoader.cxx

@@ -582,7 +582,7 @@ make_polyset(EggBin *egg_bin, PandaNode *parent, const LMatrix4d *transform,
 
 
   if (egg_mesh) {
   if (egg_mesh) {
     // If we're using the mesher, mesh now.
     // If we're using the mesher, mesh now.
-    egg_bin->mesh_triangles(0);
+    egg_bin->mesh_triangles(render_state->_flat_shaded ? EggGroupNode::T_flat_shaded : 0);
 
 
   } else {
   } else {
     // If we're not using the mesher, at least triangulate any
     // If we're not using the mesher, at least triangulate any
@@ -592,7 +592,7 @@ make_polyset(EggBin *egg_bin, PandaNode *parent, const LMatrix4d *transform,
 
 
   // Now that we've meshed, apply the per-prim attributes onto the
   // Now that we've meshed, apply the per-prim attributes onto the
   // vertices, so we can copy them to the GeomVertexData.
   // vertices, so we can copy them to the GeomVertexData.
-  egg_bin->apply_last_attribute(false);
+  egg_bin->apply_first_attribute(false);
   egg_bin->post_apply_flat_attribute(false);
   egg_bin->post_apply_flat_attribute(false);
   vertex_pool->remove_unused_vertices();
   vertex_pool->remove_unused_vertices();
 
 
@@ -2232,7 +2232,7 @@ make_primitive(const EggRenderState *render_state, EggPrimitive *egg_prim,
   }
   }
 
 
   if (render_state->_flat_shaded) {
   if (render_state->_flat_shaded) {
-    primitive->set_shade_model(qpGeomPrimitive::SM_flat_last_vertex);
+    primitive->set_shade_model(qpGeomPrimitive::SM_flat_first_vertex);
 
 
   } else if (egg_prim->get_shading() == EggPrimitive::S_overall) {
   } else if (egg_prim->get_shading() == EggPrimitive::S_overall) {
     primitive->set_shade_model(qpGeomPrimitive::SM_uniform);
     primitive->set_shade_model(qpGeomPrimitive::SM_uniform);

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

@@ -128,7 +128,7 @@ get_flat_first_vertices() const {
   CDReader cdata(_cycler);
   CDReader cdata(_cycler);
   if (cdata->_shade_model == SM_flat_last_vertex) {
   if (cdata->_shade_model == SM_flat_last_vertex) {
     if (cdata->_rotated_vertices == (const ushort *)NULL) {
     if (cdata->_rotated_vertices == (const ushort *)NULL) {
-      ((qpGeomPrimitive *)this)->do_rotate();
+      return ((qpGeomPrimitive *)this)->do_rotate(cdata);
     }
     }
     return cdata->_rotated_vertices;
     return cdata->_rotated_vertices;
   } else {
   } else {
@@ -157,7 +157,7 @@ get_flat_last_vertices() const {
   CDReader cdata(_cycler);
   CDReader cdata(_cycler);
   if (cdata->_shade_model == SM_flat_first_vertex) {
   if (cdata->_shade_model == SM_flat_first_vertex) {
     if (cdata->_rotated_vertices == (const ushort *)NULL) {
     if (cdata->_rotated_vertices == (const ushort *)NULL) {
-      ((qpGeomPrimitive *)this)->do_rotate();
+      return ((qpGeomPrimitive *)this)->do_rotate(cdata);
     }
     }
     return cdata->_rotated_vertices;
     return cdata->_rotated_vertices;
   } else {
   } else {

+ 3 - 3
panda/src/gobj/qpgeomPrimitive.cxx

@@ -769,19 +769,19 @@ rotate_impl() const {
 //               implement get_flat_first_vertices() and
 //               implement get_flat_first_vertices() and
 //               get_flat_last_vertices().
 //               get_flat_last_vertices().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void qpGeomPrimitive::
-do_rotate() {
+CPTA_ushort qpGeomPrimitive::
+do_rotate(qpGeomPrimitive::CDReader &cdata) {
   if (gobj_cat.is_debug()) {
   if (gobj_cat.is_debug()) {
     gobj_cat.debug()
     gobj_cat.debug()
       << "Rotating " << get_type() << ": " << (void *)this << "\n";
       << "Rotating " << get_type() << ": " << (void *)this << "\n";
   }
   }
 
 
   PStatTimer timer(_rotate_pcollector);
   PStatTimer timer(_rotate_pcollector);
-  CDReader cdata(_cycler);
   CPTA_ushort rotated_vertices = rotate_impl();
   CPTA_ushort rotated_vertices = rotate_impl();
 
 
   CDWriter cdataw(_cycler, cdata);
   CDWriter cdataw(_cycler, cdata);
   cdataw->_rotated_vertices = rotated_vertices;
   cdataw->_rotated_vertices = rotated_vertices;
+  return rotated_vertices;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 3
panda/src/gobj/qpgeomPrimitive.h

@@ -171,9 +171,6 @@ protected:
   virtual CPT(qpGeomPrimitive) decompose_impl() const;
   virtual CPT(qpGeomPrimitive) decompose_impl() const;
   virtual CPTA_ushort rotate_impl() const;
   virtual CPTA_ushort rotate_impl() const;
 
 
-private: 
-  void do_rotate();
-
 protected:
 protected:
   static PStatCollector _rotate_pcollector;
   static PStatCollector _rotate_pcollector;
 
 
@@ -228,6 +225,7 @@ private:
   typedef CycleDataReader<CData> CDReader;
   typedef CycleDataReader<CData> CDReader;
   typedef CycleDataWriter<CData> CDWriter;
   typedef CycleDataWriter<CData> CDWriter;
 
 
+  CPTA_ushort do_rotate(CDReader &cdata);
   void recompute_minmax(CDWriter &cdata);
   void recompute_minmax(CDWriter &cdata);
 
 
 public:
 public: