瀏覽代碼

egg triagle fans

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

+ 5 - 0
panda/src/egg/Sources.pp

@@ -25,6 +25,7 @@
      eggMaterialCollection.h \
      eggMaterialCollection.h \
      eggMesher.h eggMesher.I \
      eggMesher.h eggMesher.I \
      eggMesherEdge.h eggMesherEdge.I \
      eggMesherEdge.h eggMesherEdge.I \
+     eggMesherFanMaker.h eggMesherFanMaker.I \
      eggMesherStrip.h eggMesherStrip.I \
      eggMesherStrip.h eggMesherStrip.I \
      eggMiscFuncs.I eggMiscFuncs.h  \
      eggMiscFuncs.I eggMiscFuncs.h  \
      eggMorph.I eggMorph.h eggMorphList.I eggMorphList.h  \
      eggMorph.I eggMorph.h eggMorphList.I eggMorphList.h  \
@@ -38,6 +39,7 @@
      eggSAnimData.I eggSAnimData.h eggSurface.I eggSurface.h  \
      eggSAnimData.I eggSAnimData.h eggSurface.I eggSurface.h  \
      eggSwitchCondition.h eggTable.I eggTable.h eggTexture.I  \
      eggSwitchCondition.h eggTable.I eggTable.h eggTexture.I  \
      eggTexture.h eggTextureCollection.I eggTextureCollection.h  \
      eggTexture.h eggTextureCollection.I eggTextureCollection.h  \
+     eggTriangleFan.I eggTriangleFan.h \
      eggTriangleStrip.I eggTriangleStrip.h \
      eggTriangleStrip.I eggTriangleStrip.h \
      eggTransform3d.I eggTransform3d.h \
      eggTransform3d.I eggTransform3d.h \
      eggUserData.I eggUserData.h \
      eggUserData.I eggUserData.h \
@@ -61,6 +63,7 @@
      eggMaterialCollection.cxx \
      eggMaterialCollection.cxx \
      eggMesher.cxx \
      eggMesher.cxx \
      eggMesherEdge.cxx \
      eggMesherEdge.cxx \
+     eggMesherFanMaker.cxx \
      eggMesherStrip.cxx \
      eggMesherStrip.cxx \
      eggMiscFuncs.cxx eggMorphList.cxx  \
      eggMiscFuncs.cxx eggMorphList.cxx  \
      eggNamedObject.cxx eggNameUniquifier.cxx eggNode.cxx  \
      eggNamedObject.cxx eggNameUniquifier.cxx eggNode.cxx  \
@@ -70,6 +73,7 @@
      eggSAnimData.cxx eggSurface.cxx eggSwitchCondition.cxx  \
      eggSAnimData.cxx eggSurface.cxx eggSwitchCondition.cxx  \
      eggTable.cxx eggTexture.cxx eggTextureCollection.cxx  \
      eggTable.cxx eggTexture.cxx eggTextureCollection.cxx  \
      eggTransform3d.cxx \
      eggTransform3d.cxx \
+     eggTriangleFan.cxx \
      eggTriangleStrip.cxx \
      eggTriangleStrip.cxx \
      eggUserData.cxx \
      eggUserData.cxx \
      eggUtilities.cxx eggVertex.cxx eggVertexPool.cxx eggVertexUV.cxx \
      eggUtilities.cxx eggVertex.cxx eggVertexPool.cxx eggVertexUV.cxx \
@@ -101,6 +105,7 @@
     eggSwitchCondition.h eggTable.I eggTable.h eggTexture.I \
     eggSwitchCondition.h eggTable.I eggTable.h eggTexture.I \
     eggTexture.h eggTextureCollection.I eggTextureCollection.h \
     eggTexture.h eggTextureCollection.I eggTextureCollection.h \
     eggTransform3d.I eggTransform3d.h \
     eggTransform3d.I eggTransform3d.h \
+    eggTriangleFan.I eggTriangleFan.h \
     eggTriangleStrip.I eggTriangleStrip.h \
     eggTriangleStrip.I eggTriangleStrip.h \
     eggUserData.I eggUserData.h \
     eggUserData.I eggUserData.h \
     eggUtilities.I eggUtilities.h eggVertex.I eggVertex.h \
     eggUtilities.I eggUtilities.h eggVertex.I eggVertex.h \

+ 65 - 11
panda/src/egg/config_egg.cxx

@@ -47,6 +47,7 @@
 #include "eggSwitchCondition.h"
 #include "eggSwitchCondition.h"
 #include "eggTable.h"
 #include "eggTable.h"
 #include "eggTexture.h"
 #include "eggTexture.h"
+#include "eggTriangleFan.h"
 #include "eggTriangleStrip.h"
 #include "eggTriangleStrip.h"
 #include "eggUserData.h"
 #include "eggUserData.h"
 #include "eggVertex.h"
 #include "eggVertex.h"
@@ -75,27 +76,79 @@ ConfigVariableBool egg_support_old_anims
           "had the convention that the order \"phr\" implied a reversed roll."));
           "had the convention that the order \"phr\" implied a reversed roll."));
 
 
 ConfigVariableBool egg_mesh
 ConfigVariableBool egg_mesh
-("egg-mesh", true);
+("egg-mesh", true,
+ PRC_DESC("Set this true to convert triangles and higher-order polygons "
+          "into triangle strips and triangle fans when an egg file is "
+          "loaded or converted to bam.  Set this false just to triangulate "
+          "everything into independent triangles."));
+
 ConfigVariableBool egg_retesselate_coplanar
 ConfigVariableBool egg_retesselate_coplanar
-("egg-retesselate-coplanar", true);
+("egg-retesselate-coplanar", true,
+ PRC_DESC("If this is true, the egg loader may reverse the "
+          "tesselation direction of a single pair of planar triangles that "
+          "share the same properties, if that will help get a better "
+          "triangle strip.  In some rare cases, doing so can distort the "
+          "UV's on a face; turning this off should eliminate that artifact "
+          "(at the cost of less-effective triangle stripping)."));
+
 ConfigVariableBool egg_unroll_fans
 ConfigVariableBool egg_unroll_fans
-("egg-unroll-fans", true);
+("egg-unroll-fans", true,
+ PRC_DESC("Set this true to allow the egg loader to convert weak triangle "
+          "fans--triangles that share the same vertex but aren't "
+          "connected enough to justify making a triangle fan primitive "
+          "from them--into a series of zig-zag triangles that can make "
+          "a triangle strip that might connect better with its neighbors."));
+
 ConfigVariableBool egg_show_tstrips
 ConfigVariableBool egg_show_tstrips
-("egg-show-tstrips", false);
+("egg-show-tstrips", false,
+ PRC_DESC("Set this true to color each triangle strip a random color, with "
+          "the leading triangle a little bit darker, so you can visually "
+          "observe the quality of the triangle stripping algorithm."));
+
 ConfigVariableBool egg_show_qsheets
 ConfigVariableBool egg_show_qsheets
-("egg-show-qsheets", false);
+("egg-show-qsheets", false,
+ PRC_DESC("Set this true to color each quadsheet a random color, so you "
+          "can visually observe the quadsheet algorithm."));
+
 ConfigVariableBool egg_show_quads
 ConfigVariableBool egg_show_quads
-("egg-show-quads", false);
+("egg-show-quads", false,
+ PRC_DESC("Set this true to color each detected quad a random color, so "
+          "you can visually observe the algorithm that unifies pairs of "
+          "triangles into quads (prior to generating triangle strips)."));
+
 ConfigVariableBool egg_subdivide_polys
 ConfigVariableBool egg_subdivide_polys
-("egg-subdivide-polys", true);
+("egg-subdivide-polys", true,
+ PRC_DESC("This is obsolete.  In the old Geom implementation, it used to "
+          "be true to force higher-order polygons that were not otherwise "
+          "meshed to be subdivided into triangles.  In the new experimental "
+          "Geom implementation, this happens anyway."));
+
 ConfigVariableBool egg_consider_fans
 ConfigVariableBool egg_consider_fans
-("egg-consider-fans", true);
+("egg-consider-fans", true,
+ PRC_DESC("Set this true to enable the egg mesher to consider making "
+          "triangle fans out of triangles that are connected at a common "
+          "vertex.  This may help if your scene involves lots of such "
+          "connected triangles, but it can also make the overall stripping "
+          "less effective (by interfering with triangle strips)."));
+ 
 ConfigVariableDouble egg_max_tfan_angle
 ConfigVariableDouble egg_max_tfan_angle
-("egg-max-tfan-angle", 40.0);
+("egg-max-tfan-angle", 40.0,
+ PRC_DESC("The maximum average angle per triangle to allow in a triangle "
+          "fan.  If triangles are larger than this--that is, more loosely "
+          "packed--then we figure a triangle strip is likely to do a "
+          "more effective job than a triangle fan, and the fan maker leaves "
+          "it alone."));
+
 ConfigVariableInt egg_min_tfan_tris
 ConfigVariableInt egg_min_tfan_tris
-("egg-min-tfan-tris", 4);
+("egg-min-tfan-tris", 4,
+ PRC_DESC("The minimum number of triangles that must be involved in order "
+          "to generate a triangle fan.  Fewer than this is just interrupting "
+          "a triangle strip."));
+
 ConfigVariableDouble egg_coplanar_threshold
 ConfigVariableDouble egg_coplanar_threshold
-("egg-coplanar-threshold", 0.01);
+("egg-coplanar-threshold", 0.01,
+ PRC_DESC("The numerical threshold below which polygons are considered "
+          "to be coplanar.  Determined empirically."));
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: init_libegg
 //     Function: init_libegg
@@ -145,6 +198,7 @@ init_libegg() {
   EggSwitchConditionDistance::init_type();
   EggSwitchConditionDistance::init_type();
   EggTable::init_type();
   EggTable::init_type();
   EggTexture::init_type();
   EggTexture::init_type();
+  EggTriangleFan::init_type();
   EggTriangleStrip::init_type();
   EggTriangleStrip::init_type();
   EggUserData::init_type();
   EggUserData::init_type();
   EggVertex::init_type();
   EggVertex::init_type();

+ 50 - 24
panda/src/egg/eggCompositePrimitive.cxx

@@ -157,15 +157,32 @@ unify_attributes(EggPrimitive::Shading shading) {
     shading = get_shading();
     shading = get_shading();
   }
   }
 
 
-  // Not having a color is implicitly white.
-  if (!has_color() && shading != S_overall) {
-    set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
-  }
-
   switch (shading) {
   switch (shading) {
   case S_per_vertex:
   case S_per_vertex:
     // Propagate everything to the vertices.
     // Propagate everything to the vertices.
     {
     {
+      Components::iterator ci;
+      for (ci = _components.begin(); ci != _components.end(); ++ci) {
+        EggAttributes *component = (*ci);
+        if (component->has_normal()) {
+          if (!has_normal()) {
+            copy_normal(*component);
+          }
+          component->clear_normal();
+        }
+        if (component->has_color()) {
+          if (!has_color()) {
+            copy_color(*component);
+          }
+          component->clear_color();
+        }
+      }
+
+      // Not having a color is implicitly white.
+      if (!has_color()) {
+        set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
+      }
+
       iterator pi;
       iterator pi;
       for (pi = begin(); pi != end(); ++pi) {
       for (pi = begin(); pi != end(); ++pi) {
         EggVertex *orig_vertex = (*pi);
         EggVertex *orig_vertex = (*pi);
@@ -182,11 +199,6 @@ unify_attributes(EggPrimitive::Shading shading) {
         vertex = vertex_pool->create_unique_vertex(*vertex);
         vertex = vertex_pool->create_unique_vertex(*vertex);
         replace(pi, vertex);
         replace(pi, vertex);
       }
       }
-      Components::iterator ci;
-      for (ci = _components.begin(); ci != _components.end(); ++ci) {
-        (*ci)->clear_normal();
-        (*ci)->clear_color();
-      }
       clear_normal();
       clear_normal();
       clear_color();
       clear_color();
     }
     }
@@ -195,20 +207,17 @@ unify_attributes(EggPrimitive::Shading shading) {
   case S_per_face:
   case S_per_face:
     // Propagate everything to the components.
     // Propagate everything to the components.
     {
     {
-      Components::iterator ci;
-      for (ci = _components.begin(); ci != _components.end(); ++ci) {
-        EggAttributes *component = (*ci);
-        if (!component->has_normal() && has_normal()) {
-          component->copy_normal(*this);
-        }
-        if (!component->has_color() && has_color()) {
-          component->copy_color(*this);
-        }
-      }
       iterator pi;
       iterator pi;
       for (pi = begin(); pi != end(); ++pi) {
       for (pi = begin(); pi != end(); ++pi) {
         EggVertex *orig_vertex = (*pi);
         EggVertex *orig_vertex = (*pi);
         if (orig_vertex->has_normal() || orig_vertex->has_color()) {
         if (orig_vertex->has_normal() || orig_vertex->has_color()) {
+          if (orig_vertex->has_normal() && !has_normal()) {
+            copy_normal(*orig_vertex);
+          }
+          if (orig_vertex->has_color() && !has_color()) {
+            copy_color(*orig_vertex);
+          }
+
           PT(EggVertex) vertex = new EggVertex(*orig_vertex);
           PT(EggVertex) vertex = new EggVertex(*orig_vertex);
           vertex->clear_normal();
           vertex->clear_normal();
           vertex->clear_color();
           vertex->clear_color();
@@ -219,6 +228,22 @@ unify_attributes(EggPrimitive::Shading shading) {
           replace(pi, vertex);
           replace(pi, vertex);
         }
         }
       }
       }
+
+      // Not having a color is implicitly white.
+      if (!has_color()) {
+        set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
+      }
+
+      Components::iterator ci;
+      for (ci = _components.begin(); ci != _components.end(); ++ci) {
+        EggAttributes *component = (*ci);
+        if (!component->has_normal() && has_normal()) {
+          component->copy_normal(*this);
+        }
+        if (!component->has_color() && has_color()) {
+          component->copy_color(*this);
+        }
+      }
       clear_normal();
       clear_normal();
       clear_color();
       clear_color();
     }
     }
@@ -259,16 +284,17 @@ unify_attributes(EggPrimitive::Shading shading) {
           component->clear_color();
           component->clear_color();
         }
         }
       }
       }
+
+      // Not having a color is implicitly white.
+      if (!has_color()) {
+        set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
+      }
     }
     }
     break;
     break;
 
 
   case S_unknown:
   case S_unknown:
     break;
     break;
   }
   }
-
-  if (!has_color() && shading == S_overall) {
-    set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
-  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 13 - 15
panda/src/egg/eggMesher.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "eggMesher.h"
 #include "eggMesher.h"
+#include "eggMesherFanMaker.h"
 #include "eggPolygon.h"
 #include "eggPolygon.h"
 #include "eggCompositePrimitive.h"
 #include "eggCompositePrimitive.h"
 #include "eggTriangleStrip.h"
 #include "eggTriangleStrip.h"
@@ -80,7 +81,7 @@ mesh(EggGroupNode *group) {
           add_polygon(poly, EggMesherStrip::MO_user);
           add_polygon(poly, EggMesherStrip::MO_user);
 
 
         } else {
         } else {
-          // A different vertex pool; save this one for next pass.
+          // A different vertex pool; save this one for the next pass.
           next_children->add_child(poly);
           next_children->add_child(poly);
         }
         }
 
 
@@ -320,8 +321,8 @@ get_prim(EggMesherStrip &strip) {
 
 
     Colorf color1, color2;
     Colorf color1, color2;
 
 
-    if (egg_prim->is_of_type(EggTriangleStrip::get_class_type()) /*||
-                egg_prim->is_of_type(EggTriangleFan::get_class_type())*/) {
+    if (egg_prim->is_of_type(EggTriangleStrip::get_class_type()) ||
+        egg_prim->is_of_type(EggTriangleFan::get_class_type())) {
       make_random_color(color2);
       make_random_color(color2);
       color1 = (color2 * 0.8);   // somewhat darker.
       color1 = (color2 * 0.8);   // somewhat darker.
 
 
@@ -621,8 +622,7 @@ build_sheets() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void EggMesher::
 void EggMesher::
 find_fans() {
 find_fans() {
-#if 0
-  pvector<Prim> unrolled_tris;
+  PT(EggGroupNode) unrolled_tris = new EggGroup;
 
 
   // Consider all vertices.  Any vertex with over a certain number of
   // Consider all vertices.  Any vertex with over a certain number of
   // edges connected to it is eligible to become a fan.
   // edges connected to it is eligible to become a fan.
@@ -639,22 +639,21 @@ find_fans() {
     // the quadsheets anyway.  We bump this up to 14 because some
     // the quadsheets anyway.  We bump this up to 14 because some
     // quadsheets are defined with triangles flipped here and there.
     // quadsheets are defined with triangles flipped here and there.
     if (edges.size() > 6) {
     if (edges.size() > 6) {
-      const Vertex &v = (*vi).first;
+      int v = (*vi).first;
 
 
       // Build up a list of far fan edges.
       // Build up a list of far fan edges.
-      typedef pvector<FanMaker> FanMakers;
-
+      typedef pvector<EggMesherFanMaker> FanMakers;
       FanMakers fans;
       FanMakers fans;
 
 
       EdgePtrs::iterator ei;
       EdgePtrs::iterator ei;
-      Edge::Strips::iterator si;
+      EggMesherEdge::Strips::iterator si;
       for (ei = edges.begin(); ei != edges.end(); ++ei) {
       for (ei = edges.begin(); ei != edges.end(); ++ei) {
         for (si = (*ei)->_strips.begin();
         for (si = (*ei)->_strips.begin();
              si != (*ei)->_strips.end();
              si != (*ei)->_strips.end();
              ++si) {
              ++si) {
           EggMesherStrip *strip = *si;
           EggMesherStrip *strip = *si;
           if (strip->_type == EggMesherStrip::PT_tri) {
           if (strip->_type == EggMesherStrip::PT_tri) {
-            FanMaker fan(&v, strip, this);
+            EggMesherFanMaker fan(v, strip, this);
             if (!fan._edges.empty()) {
             if (!fan._edges.empty()) {
               fans.push_back(fan);
               fans.push_back(fan);
             }
             }
@@ -670,7 +669,7 @@ find_fans() {
       FanMakers::iterator fi, fi2;
       FanMakers::iterator fi, fi2;
 
 
       // Now pull out connected edges.
       // Now pull out connected edges.
-      int joined_any;
+      bool joined_any;
       do {
       do {
         joined_any = false;
         joined_any = false;
         for (fi = fans.begin(); fi != fans.end(); ++fi) {
         for (fi = fans.begin(); fi != fans.end(); ++fi) {
@@ -698,11 +697,10 @@ find_fans() {
   // until we're done traversing all the vertices and primitives we
   // until we're done traversing all the vertices and primitives we
   // had in the first place (since adding them will affect the edge
   // had in the first place (since adding them will affect the edge
   // lists).
   // lists).
-  pvector<Prim>::iterator ti;
-  for (ti = unrolled_tris.begin(); ti != unrolled_tris.end(); ++ti) {
-    add_prim(*ti);
+  EggGroupNode::iterator ti;
+  for (ti = unrolled_tris->begin(); ti != unrolled_tris->end(); ++ti) {
+    add_polygon(DCAST(EggPolygon, (*ti)), EggMesherStrip::MO_fanpoly);
   }
   }
-#endif
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

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

@@ -22,7 +22,6 @@
 #include "pandabase.h"
 #include "pandabase.h"
 #include "eggMesherEdge.h"
 #include "eggMesherEdge.h"
 #include "eggMesherStrip.h"
 #include "eggMesherStrip.h"
-//#include "eggMesherFanMaker.h"
 #include "eggPolygon.h"
 #include "eggPolygon.h"
 #include "pvector.h"
 #include "pvector.h"
 #include "plist.h"
 #include "plist.h"
@@ -31,8 +30,6 @@
 
 
 #include <algorithm>
 #include <algorithm>
 
 
-class MesherFanMaker;
-
 ///////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////
 //       Class : EggMesher
 //       Class : EggMesher
 // Description : Collects together unrelated EggPrimitives, determines
 // Description : Collects together unrelated EggPrimitives, determines

+ 93 - 0
panda/src/egg/eggMesherFanMaker.I

@@ -0,0 +1,93 @@
+// Filename: eggMesherFanMaker.I
+// Created by:  drose (22Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: EggMesherFanMaker::operator <
+//       Access: Public
+//  Description: Provides a unique ordering between different fan
+//               makers based on the leading edge.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggMesherFanMaker::
+operator < (const EggMesherFanMaker &other) const {
+  nassertr(!_edges.empty() && !other._edges.empty(), false);
+  return _edges.front() < other._edges.front();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherFanMaker::operator !=
+//       Access: Public
+//  Description: Provides a unique ordering between different fan
+//               makers based on the leading edge.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggMesherFanMaker::
+operator != (const EggMesherFanMaker &other) const {
+  return !operator == (other);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherFanMaker::operator ==
+//       Access: Public
+//  Description: Provides a unique ordering between different fan
+//               makers based on the leading edge.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggMesherFanMaker::
+operator == (const EggMesherFanMaker &other) const {
+  return _edges.front() == other._edges.front();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherFanMaker::is_empty
+//       Access: Public
+//  Description: Returns true if the fan maker has no edges, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggMesherFanMaker::
+is_empty() const {
+  return (_edges.empty());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherFanMaker::is_valid
+//       Access: Public
+//  Description: Returns true if the fan maker has enough edges to
+//               define at least one fan, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggMesherFanMaker::
+is_valid() const {
+  return (_edges.size() > 2);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherFanMaker::is_coplanar_with
+//       Access: Public
+//  Description: Returns true if the strip and the other strip are
+//               coplanar.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggMesherFanMaker::
+is_coplanar_with(const EggMesherFanMaker &other) const {
+  return _planar && other._planar &&
+    _strips.front()->is_coplanar_with(*other._strips.front(),
+                                      egg_coplanar_threshold);
+}
+
+INLINE ostream &
+operator << (ostream &out, const EggMesherFanMaker &fm) {
+  fm.output(out);
+  return out;
+}

+ 371 - 0
panda/src/egg/eggMesherFanMaker.cxx

@@ -0,0 +1,371 @@
+// Filename: eggMesherFanMaker.cxx
+// Created by:  drose (22Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "eggMesherFanMaker.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherFanMaker::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+EggMesherFanMaker::
+EggMesherFanMaker(int vertex, EggMesherStrip *tri, 
+                  EggMesher *mesher) {
+  _vertex = vertex;
+  const EggMesherEdge *edge = tri->find_opposite_edge(vertex);
+  if (edge != (const EggMesherEdge *)NULL) {
+    _edges.push_back(edge);
+  }
+  _strips.push_back(tri);
+  _planar = tri->_planar;
+  _mesher = mesher;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherFanMaker::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+EggMesherFanMaker::
+EggMesherFanMaker(const EggMesherFanMaker &copy) :
+  _vertex(copy._vertex),
+  _edges(copy._edges),
+  _strips(copy._strips),
+  _planar(copy._planar),
+  _mesher(copy._mesher)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherFanMaker::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void EggMesherFanMaker::
+operator = (const EggMesherFanMaker &copy) {
+  _vertex = copy._vertex;
+  _edges = copy._edges;
+  _strips = copy._strips;
+  _planar = copy._planar;
+  _mesher = copy._mesher;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherFanMaker::join
+//       Access: Public
+//  Description: Attempts to connect two fans end-to-end.  They must
+//               both share the same common vertex and a common edge.
+//
+//               The return value is true if the fans were
+//               successfully joined, or false if they could not be.
+////////////////////////////////////////////////////////////////////
+bool EggMesherFanMaker::
+join(EggMesherFanMaker &other) {
+  nassertr(_vertex == other._vertex, false);
+  nassertr(_mesher == other._mesher, false);
+
+  nassertr(!_edges.empty() && !other._edges.empty(), false);
+
+  const EggMesherEdge *my_back = _edges.back();
+  const EggMesherEdge *other_front = other._edges.front();
+  nassertr(my_back != (EggMesherEdge *)NULL && 
+           other_front != (EggMesherEdge *)NULL, false);
+
+  int my_back_b = my_back->_vi_b;
+  int other_front_a = other_front->_vi_a;
+
+  if (my_back_b == other_front_a) {
+    _planar = is_coplanar_with(other);
+    _edges.splice(_edges.end(), other._edges);
+    _strips.splice(_strips.end(), other._strips);
+    return true;
+  }
+
+  const EggMesherEdge *my_front = _edges.front();
+  const EggMesherEdge *other_back = other._edges.back();
+  nassertr(my_front != (EggMesherEdge *)NULL && 
+           other_back != (EggMesherEdge *)NULL, false);
+
+  int my_front_a = my_front->_vi_a;
+  int other_back_b = other_back->_vi_b;
+
+  if (my_front_a == other_back_b) {
+    _planar = is_coplanar_with(other);
+    _edges.splice(_edges.begin(), other._edges);
+    _strips.splice(_strips.begin(), other._strips);
+    return true;
+  }
+
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherFanMaker::compute_angle
+//       Access: Public
+//  Description: Returns the overall angle subtended by the fan, from
+//               the leading edge to the trailing edge, in degrees.
+////////////////////////////////////////////////////////////////////
+double EggMesherFanMaker::
+compute_angle() const {
+  // We sum up the angles of each triangle.  This is more correct than
+  // taking the net angle from the first edge to the last (since we
+  // may not be in a plane).
+  nassertr(is_valid(), 0.0);
+
+  EggVertexPool *vertex_pool = _mesher->_vertex_pool;
+  
+  double angle = 0.0;
+  LPoint3d v0 = vertex_pool->get_vertex(_vertex)->get_pos3();
+
+  Edges::const_iterator ei;
+  for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
+    LVector3d v1 = vertex_pool->get_vertex((*ei)->_vi_a)->get_pos3() - v0;
+    LVector3d v2 = vertex_pool->get_vertex((*ei)->_vi_b)->get_pos3() - v0;
+
+    v1 = normalize(v1);
+    v2 = normalize(v2);
+    angle += acos(dot(v1, v2));
+  }
+
+  return rad_2_deg(angle);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherFanMaker::build
+//       Access: Public
+//  Description: Begins the fanning process.  Searches for triangles
+//               and connects them into a fan.
+//
+//               In certain cases, if egg_unroll_fans is enabled, the
+//               resulting fan may be retesselated into a series of
+//               zig-zag triangles, which are stored in unrolled_tris.
+//               Otherwise, an EggMesherStrip (representing the fan)
+//               is created and added to the mesher.
+//
+//               The return value is (loosely) the number of
+//               primitives created.
+////////////////////////////////////////////////////////////////////
+int EggMesherFanMaker::
+build(EggGroupNode *unrolled_tris) {
+  nassertr(_edges.size() == _strips.size(), 0);
+
+  int num_tris = _edges.size();
+  double net_angle = compute_angle();
+  double avg_angle = net_angle / (double)num_tris;
+
+  if (avg_angle > egg_max_tfan_angle) {
+    // The triangles are too loose to justify making a fan; it'll
+    // probably make a better quadsheet.
+    return 0;
+  }
+
+  if (egg_min_tfan_tris == 0 || num_tris < egg_min_tfan_tris) {
+    // Oops, not enough triangles to justify a fan.
+    if (!egg_unroll_fans) {
+      return 0;
+    }
+
+    // However, we could (maybe) make it a few tristrips!
+
+    // Each section of the fan which is made up of coplanar tris, with
+    // identical properties, may be retesselated into a tristrip.
+    // What a sneaky trick!  To do this, we must first identify each
+    // such qualifying section.
+
+    // We define a seam as the edge between any two tris which are
+    // noncoplanar or have different properties.  Then we can send
+    // each piece between the seams to unroll().
+
+    Strips::iterator si, last_si;
+    Edges::iterator ei, last_ei;
+
+    // First, rotate the fan so it begins at a seam.  We do this so we
+    // won't be left out with part of one piece at the beginning and
+    // also at the end.
+    si = _strips.begin();
+    last_si = si;
+    ei = _edges.begin();
+    last_ei = ei;
+    int found_seam = false;
+
+    for (++si, ++ei; si != _strips.end() && !found_seam; ++si, ++ei) {
+      nassertr(ei != _edges.end(), 0);
+      if ( ((*si)->_prims.front()->compare_to(*(*last_si)->_prims.front()) != 0) ||
+           !(*si)->is_coplanar_with(*(*last_si), egg_coplanar_threshold)) {
+        // Here's a seam.  Break the fan here.
+        found_seam = true;
+        _edges.splice(_edges.begin(), _edges, ei, _edges.end());
+        _strips.splice(_strips.begin(), _strips, si, _strips.end());
+      }
+    }
+
+    // Now break the fan up along its seams and unroll each piece
+    // separately.
+    si = _strips.begin();
+    last_si = si;
+    ei = _edges.begin();
+    last_ei = ei;
+
+    int count = 0;
+    for (++si, ++ei; si != _strips.end(); ++si, ++ei) {
+      nassertr(ei != _edges.end(), 0);
+      if ( ((*si)->_prims.front()->compare_to(*(*last_si)->_prims.front()) != 0) ||
+           !(*si)->is_coplanar_with(*(*last_si), egg_coplanar_threshold)) {
+        // Here's the end of a run of matching pieces.
+        count += unroll(last_si, si, last_ei, ei, unrolled_tris);
+        last_si = si;
+        last_ei = ei;
+      }
+    }
+    count += unroll(last_si, si, last_ei, ei, unrolled_tris);
+
+    return count;
+
+  } else {
+    EggMesherStrip new_fan;
+    new_fan._type = EggMesherStrip::PT_trifan;
+    new_fan._origin = EggMesherStrip::MO_fanpoly;
+    new_fan._verts.push_back(_vertex);
+
+    new_fan._verts.push_back(_edges.front()->_vi_a);
+    Edges::iterator ei;
+    for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
+      new_fan._verts.push_back((*ei)->_vi_b);
+    }
+
+    Strips::iterator si;
+    for (si = _strips.begin(); si != _strips.end(); ++si) {
+      new_fan._prims.splice(new_fan._prims.end(), (*si)->_prims);
+      (*si)->remove_all_edges();
+      (*si)->_verts.clear();
+      (*si)->_status = EggMesherStrip::MS_dead;
+    }
+
+    // If we'd built our list of edges and strips right, this sum should
+    // come out so that there are two more vertices than triangles in
+    // the new fan.
+    nassertr(new_fan._verts.size() == new_fan._prims.size() + 2, 0);
+
+    // Now we've built a fan, and it won't be able to mate with
+    // anything else, so add it to the done list.
+    _mesher->_done.push_back(new_fan);
+  }
+
+  return 1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherFanMaker::unroll
+//       Access: Public
+//  Description: Unrolls a planar subset of the current working fan,
+//               defined by the given iterators, into a series of
+//               triangles that zig-zag back and forth for better
+//               tristripping properties.  The new triangles are added
+//               to unrolled_tris; the return value is 1 if
+//               successful, or 0 otherwise.
+////////////////////////////////////////////////////////////////////
+int EggMesherFanMaker::
+unroll(Strips::iterator strip_begin, Strips::iterator strip_end,
+       Edges::iterator edge_begin, Edges::iterator edge_end,
+       EggGroupNode *unrolled_tris) {
+  Edges::iterator ei;
+  Strips::iterator si;
+
+  int num_tris = 0;
+  for (ei = edge_begin; ei != edge_end; ++ei) {
+    num_tris++;
+  }
+
+  if (num_tris < 3) {
+    // Don't even bother.
+    return 0;
+  }
+
+  PT(EggPolygon) poly = new EggPolygon;
+
+  // Now we build an n-sided polygon the same shape as the fan.  We'll
+  // decompose it into tris in a second.
+  poly->copy_attributes(*(*strip_begin)->_prims.front());
+  EggVertexPool *vertex_pool = _mesher->_vertex_pool;
+
+  ei = edge_end;
+  --ei;
+  if ((*ei)->_vi_b != (*edge_begin)->_vi_a) {
+    // If the fan is less than a full circle, we need to keep the
+    // hub vertex and initial vertex in the poly.  Otherwise, we'll
+    // discard them.
+    poly->add_vertex(vertex_pool->get_vertex(_vertex));
+    poly->add_vertex(vertex_pool->get_vertex((*edge_begin)->_vi_a));
+  }
+
+  for (ei = edge_begin; ei != edge_end; ++ei) {
+    poly->add_vertex(vertex_pool->get_vertex((*ei)->_vi_b));
+  }
+
+  bool result = true;
+
+  if (egg_show_quads) {
+    // If we're showing quads, also show retesselated triangles.
+
+    // We can't add it directly to the mesher, that's unsafe; instead,
+    // we'll just add it to the end of the unrolled_tris list.  This
+    // does mean we won't be able to color it a fancy color, but too
+    // bad.
+    //_mesher->add_polygon(poly, EggMesherStrip::MO_fanpoly);
+    unrolled_tris->add_child(poly);
+
+  } else {
+    // Now decompose the new polygon into triangles.
+    result = poly->triangulate_into(unrolled_tris, true);
+  }
+
+  if (result) {
+    // Now that we've created a new poly, kill off all the old ones.
+    for (si = strip_begin; si != strip_end; ++si) {
+      (*si)->remove_all_edges();
+      (*si)->_verts.clear();
+      (*si)->_prims.clear();
+      (*si)->_status = EggMesherStrip::MS_dead;
+    }
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMesherFanMaker::output
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void EggMesherFanMaker::
+output(ostream &out) const {
+  out << _vertex << ":[";
+  if (!_edges.empty()) {
+    Edges::const_iterator ei;
+    for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
+      out << " " << (*ei)->_vi_a;
+    }
+    out << " " << _edges.back()->_vi_b;
+  }
+  out << " ]";
+
+  if (_planar) {
+    out << " (planar)";
+  }
+}

+ 80 - 0
panda/src/egg/eggMesherFanMaker.h

@@ -0,0 +1,80 @@
+// Filename: eggMesherFanMaker.h
+// Created by:  drose (22Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 EGGMESHERFANMAKER_H
+#define EGGMESHERFANMAKER_H
+
+#include "pandabase.h"
+
+#include "eggMesherEdge.h"
+#include "eggMesherStrip.h"
+
+#include "plist.h"
+#include "pvector.h"
+
+#include "notify.h"
+#include "mathNumbers.h"
+
+class EggMesher;
+
+///////////////////////////////////////////////////////////////////
+//       Class : EggMesherFanMaker
+// Description : This class is used by EggMesher::find_fans() to
+//               attempt to make an EggTriangleFan out of the polygons
+//               connected to the indicated vertex.
+////////////////////////////////////////////////////////////////////
+class EggMesherFanMaker {
+public:
+  typedef plist<const EggMesherEdge *> Edges;
+  typedef plist<EggMesherStrip *> Strips;
+
+  EggMesherFanMaker(int vertex, EggMesherStrip *tri, 
+                    EggMesher *mesher);
+  EggMesherFanMaker(const EggMesherFanMaker &copy);
+  void operator = (const EggMesherFanMaker &copy);
+
+  INLINE bool operator < (const EggMesherFanMaker &other) const;
+  INLINE bool operator != (const EggMesherFanMaker &other) const;
+  INLINE bool operator == (const EggMesherFanMaker &other) const;
+
+  INLINE bool is_empty() const;
+  INLINE bool is_valid() const;
+  INLINE bool is_coplanar_with(const EggMesherFanMaker &other) const;
+
+  bool join(EggMesherFanMaker &other);
+  double compute_angle() const;
+
+  int build(EggGroupNode *unrolled_tris);
+  int unroll(Strips::iterator strip_begin, Strips::iterator strip_end,
+             Edges::iterator edge_begin, Edges::iterator edge_end,
+             EggGroupNode *unrolled_tris);
+
+  void output(ostream &out) const;
+
+  int _vertex;
+  Edges _edges;
+  Strips _strips;
+  bool _planar;
+  EggMesher *_mesher;
+};
+
+INLINE ostream &operator << (ostream &out, const EggMesherFanMaker &fm);
+
+#include "eggMesherFanMaker.I"
+
+#endif

+ 6 - 1
panda/src/egg/eggMesherStrip.cxx

@@ -19,6 +19,7 @@
 #include "eggMesherStrip.h"
 #include "eggMesherStrip.h"
 #include "eggMesherEdge.h"
 #include "eggMesherEdge.h"
 #include "eggPrimitive.h"
 #include "eggPrimitive.h"
+#include "eggTriangleFan.h"
 #include "eggTriangleStrip.h"
 #include "eggTriangleStrip.h"
 #include "eggPolygon.h"
 #include "eggPolygon.h"
 #include "dcast.h"
 #include "dcast.h"
@@ -115,7 +116,11 @@ make_prim(const EggVertexPool *vertex_pool) {
   } else {
   } else {
     // The harder case: a tristrip of some kind.
     // The harder case: a tristrip of some kind.
     convert_to_type(dest_type);
     convert_to_type(dest_type);
-    prim = new EggTriangleStrip;
+    if (dest_type == PT_trifan) {
+      prim = new EggTriangleFan;
+    } else {
+      prim = new EggTriangleStrip;
+    }
     prim->copy_attributes(*_prims.front());
     prim->copy_attributes(*_prims.front());
 
 
     // Now store all the vertices.  Each individual triangle's
     // Now store all the vertices.  Each individual triangle's

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

@@ -142,7 +142,7 @@ public:
   int _index;
   int _index;
   MesherStatus _status;
   MesherStatus _status;
 
 
-  int _planar;
+  bool _planar;
   Normald _plane_normal;
   Normald _plane_normal;
   float _plane_offset;
   float _plane_offset;
   int _row_id, _row_distance;
   int _row_id, _row_distance;

+ 47 - 0
panda/src/egg/eggTriangleFan.I

@@ -0,0 +1,47 @@
+// Filename: eggTriangleFan.I
+// Created by:  drose (23Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: EggTriangleFan::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE EggTriangleFan::
+EggTriangleFan(const string &name) : EggCompositePrimitive(name) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTriangleFan::Copy constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE EggTriangleFan::
+EggTriangleFan(const EggTriangleFan &copy) : EggCompositePrimitive(copy) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTriangleFan::Copy assignment operator
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE EggTriangleFan &EggTriangleFan::
+operator = (const EggTriangleFan &copy) {
+  EggCompositePrimitive::operator = (copy);
+  return *this;
+}

+ 133 - 0
panda/src/egg/eggTriangleFan.cxx

@@ -0,0 +1,133 @@
+// Filename: eggTriangleFan.cxx
+// Created by:  drose (23Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "eggTriangleFan.h"
+#include "eggGroupNode.h"
+#include "eggPolygon.h"
+#include "indent.h"
+
+TypeHandle EggTriangleFan::_type_handle;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTriangleFan::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+EggTriangleFan::
+~EggTriangleFan() {
+  clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTriangleFan::write
+//       Access: Published, Virtual
+//  Description: Writes the triangle fan to the indicated output
+//               stream in Egg format.
+////////////////////////////////////////////////////////////////////
+void EggTriangleFan::
+write(ostream &out, int indent_level) const {
+  write_header(out, indent_level, "<TriangleFan>");
+  write_body(out, indent_level+2);
+  indent(out, indent_level) << "}\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTriangleFan::apply_first_attribute
+//       Access: Published, Virtual
+//  Description: Sets the first vertex of the triangle (or each
+//               component) to the primitive normal and/or color, if
+//               the primitive is flat-shaded.  This reflects the
+//               DirectX convention of storing flat-shaded properties
+//               on the first vertex, although it is not usually a
+//               convention in Egg.
+//
+//               This may introduce redundant vertices to the vertex
+//               pool.
+////////////////////////////////////////////////////////////////////
+void EggTriangleFan::
+apply_first_attribute() {
+  // In the case of a triangle fan, the first vertex of the fan is the
+  // common vertex, so we consider the second vertex to be the key
+  // vertex of the first triangle, and move from there.
+  for (int i = 0; i < get_num_components(); i++) {
+    EggAttributes *component = get_component(i);
+    do_apply_flat_attribute(i + 1, component);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTriangleFan::get_num_lead_vertices
+//       Access: Protected, Virtual
+//  Description: Returns the number of initial vertices that are not
+//               used in defining any component; the first component
+//               is defined by the (n + 1)th vertex, and then a new
+//               component at each vertex thereafter.
+////////////////////////////////////////////////////////////////////
+int EggTriangleFan::
+get_num_lead_vertices() const {
+  return 2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTriangleFan::triangulate_poly
+//       Access: Protected, Virtual
+//  Description: Fills the container up with EggPolygons that
+//               represent the component triangles of this triangle
+//               fan.
+//
+//               It is assumed that the EggTriangleFan 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).
+////////////////////////////////////////////////////////////////////
+bool EggTriangleFan::
+do_triangulate(EggGroupNode *container) const {
+  if (size() < 3) {
+    return false;
+  }
+  const_iterator vi = begin();
+  EggVertex *v0 = (*vi);
+  ++vi;
+  EggVertex *v1 = (*vi);
+  ++vi;
+
+  for (int i = 0; i < (int)size() - 2; i++) {
+    PT(EggPolygon) poly = new EggPolygon;
+    poly->copy_attributes(*this);
+    const EggAttributes *attrib = get_component(i);
+    if (attrib->has_color()) {
+      poly->set_color(attrib->get_color());
+    }
+    if (attrib->has_normal()) {
+      poly->set_normal(attrib->get_normal());
+    }
+
+    poly->add_vertex(v0);
+    poly->add_vertex(v1);
+    poly->add_vertex(*vi);
+    v1 = *vi;
+    container->add_child(poly);
+    ++vi;
+  }
+
+  return true;
+}

+ 66 - 0
panda/src/egg/eggTriangleFan.h

@@ -0,0 +1,66 @@
+// Filename: eggTriangleFan.h
+// Created by:  drose (23Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 EGGTRIANGLEFAN_H
+#define EGGTRIANGLEFAN_H
+
+#include "pandabase.h"
+
+#include "eggCompositePrimitive.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : EggTriangleFan
+// Description : A connected fan of triangles.  This does not
+//               normally appear in an egg file; it is typically
+//               generated as a result of meshing.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEGG EggTriangleFan : public EggCompositePrimitive {
+PUBLISHED:
+  INLINE EggTriangleFan(const string &name = "");
+  INLINE EggTriangleFan(const EggTriangleFan &copy);
+  INLINE EggTriangleFan &operator = (const EggTriangleFan &copy);
+  virtual ~EggTriangleFan();
+
+  virtual void write(ostream &out, int indent_level) const;
+  virtual void apply_first_attribute();
+
+protected:
+  virtual int get_num_lead_vertices() const;
+  virtual bool do_triangulate(EggGroupNode *container) const;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    EggCompositePrimitive::init_type();
+    register_type(_type_handle, "EggTriangleFan",
+                  EggCompositePrimitive::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 "eggTriangleFan.I"
+
+#endif

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

@@ -19,12 +19,8 @@
 #include "eggTriangleStrip.h"
 #include "eggTriangleStrip.h"
 #include "eggGroupNode.h"
 #include "eggGroupNode.h"
 #include "eggPolygon.h"
 #include "eggPolygon.h"
-#include "plane.h"
-
 #include "indent.h"
 #include "indent.h"
 
 
-#include <algorithm>
-
 TypeHandle EggTriangleStrip::_type_handle;
 TypeHandle EggTriangleStrip::_type_handle;
 
 
 
 

+ 1 - 0
panda/src/egg/egg_composite1.cxx

@@ -18,6 +18,7 @@
 #include "eggMaterialCollection.cxx"
 #include "eggMaterialCollection.cxx"
 #include "eggMesher.cxx"
 #include "eggMesher.cxx"
 #include "eggMesherEdge.cxx"
 #include "eggMesherEdge.cxx"
+#include "eggMesherFanMaker.cxx"
 #include "eggMesherStrip.cxx"
 #include "eggMesherStrip.cxx"
 #include "eggMiscFuncs.cxx"
 #include "eggMiscFuncs.cxx"
 #include "eggMorphList.cxx"
 #include "eggMorphList.cxx"

+ 1 - 0
panda/src/egg/egg_composite2.cxx

@@ -13,6 +13,7 @@
 #include "eggTexture.cxx"
 #include "eggTexture.cxx"
 #include "eggTextureCollection.cxx"
 #include "eggTextureCollection.cxx"
 #include "eggTransform3d.cxx"
 #include "eggTransform3d.cxx"
+#include "eggTriangleFan.cxx"
 #include "eggTriangleStrip.cxx"
 #include "eggTriangleStrip.cxx"
 #include "eggUserData.cxx"
 #include "eggUserData.cxx"
 #include "eggUtilities.cxx"
 #include "eggUtilities.cxx"

+ 22 - 0
panda/src/egg/parser.yxx

@@ -16,6 +16,7 @@
 #include "eggVertexUV.h"
 #include "eggVertexUV.h"
 #include "eggPolygon.h"
 #include "eggPolygon.h"
 #include "eggCompositePrimitive.h"
 #include "eggCompositePrimitive.h"
+#include "eggTriangleFan.h"
 #include "eggTriangleStrip.h"
 #include "eggTriangleStrip.h"
 #include "eggPoint.h"
 #include "eggPoint.h"
 #include "eggLine.h"
 #include "eggLine.h"
@@ -182,6 +183,7 @@ egg_cleanup_parser() {
 %type <_egg> joint
 %type <_egg> joint
 %type <_egg> line
 %type <_egg> line
 %type <_egg> polygon
 %type <_egg> polygon
+%type <_egg> trianglefan
 %type <_egg> trianglestrip
 %type <_egg> trianglestrip
 %type <_egg> point_light
 %type <_egg> point_light
 %type <_egg> nurbs_surface
 %type <_egg> nurbs_surface
@@ -252,6 +254,7 @@ node:
         | joint 
         | joint 
         | instance
         | instance
         | polygon
         | polygon
+        | trianglefan
         | trianglestrip
         | trianglestrip
         | point_light
         | point_light
         | line
         | line
@@ -1596,6 +1599,25 @@ polygon:
 }
 }
         ;
         ;
 
 
+/*
+ * trianglefan
+ *
+ * enter:
+ * exit: returns a new EggTriangleFan.
+ *
+ */
+trianglefan:
+        TRIANGLEFAN optional_name
+{
+  egg_stack.push_back(new EggTriangleFan($2));
+}
+        '{' primitive_body '}'
+{
+  $$ = egg_stack.back();
+  egg_stack.pop_back();
+}
+        ;
+
 /*
 /*
  * trianglestrip
  * trianglestrip
  *
  *

+ 5 - 0
panda/src/egg2pg/eggLoader.cxx

@@ -40,6 +40,7 @@
 #include "qpgeom.h"
 #include "qpgeom.h"
 #include "qpgeomTriangles.h"
 #include "qpgeomTriangles.h"
 #include "qpgeomTristrips.h"
 #include "qpgeomTristrips.h"
+#include "qpgeomTrifans.h"
 #include "qpgeomLines.h"
 #include "qpgeomLines.h"
 #include "qpgeomLinestrips.h"
 #include "qpgeomLinestrips.h"
 #include "qpgeomPoints.h"
 #include "qpgeomPoints.h"
@@ -61,6 +62,7 @@
 #include "eggGroup.h"
 #include "eggGroup.h"
 #include "eggPolygon.h"
 #include "eggPolygon.h"
 #include "eggTriangleStrip.h"
 #include "eggTriangleStrip.h"
+#include "eggTriangleFan.h"
 #include "eggBin.h"
 #include "eggBin.h"
 #include "eggTable.h"
 #include "eggTable.h"
 #include "eggBinner.h"
 #include "eggBinner.h"
@@ -2000,6 +2002,9 @@ make_primitive(const EggRenderState *render_state, EggPrimitive *egg_prim,
   } else if (egg_prim->is_of_type(EggTriangleStrip::get_class_type())) {
   } else if (egg_prim->is_of_type(EggTriangleStrip::get_class_type())) {
     primitive = new qpGeomTristrips(qpGeomUsageHint::UH_static);
     primitive = new qpGeomTristrips(qpGeomUsageHint::UH_static);
 
 
+  } else if (egg_prim->is_of_type(EggTriangleFan::get_class_type())) {
+    primitive = new qpGeomTrifans(qpGeomUsageHint::UH_static);
+
   } else if (egg_prim->is_of_type(EggLine::get_class_type())) {
   } else if (egg_prim->is_of_type(EggLine::get_class_type())) {
     if (egg_prim->size() == 2) {
     if (egg_prim->size() == 2) {
       primitive = new qpGeomLines(qpGeomUsageHint::UH_static);
       primitive = new qpGeomLines(qpGeomUsageHint::UH_static);

+ 2 - 0
panda/src/gobj/qpgeomTrifans.cxx

@@ -125,6 +125,8 @@ decompose_impl() const {
       triangles->add_vertex(v0);
       triangles->add_vertex(v0);
       triangles->add_vertex(v1);
       triangles->add_vertex(v1);
       triangles->add_vertex(vertices[vi]);
       triangles->add_vertex(vertices[vi]);
+      nassertr(vi < (int)vertices.size(), this);
+      v1 = vertices[vi];
       triangles->close_primitive();
       triangles->close_primitive();
       ++vi;
       ++vi;
     }
     }