Jelajahi Sumber

lines and points, antialiasing in qpgeom

David Rose 21 tahun lalu
induk
melakukan
18169d527e
44 mengubah file dengan 1390 tambahan dan 160 penghapusan
  1. 32 0
      panda/src/display/graphicsStateGuardian.cxx
  2. 3 0
      panda/src/display/graphicsStateGuardian.h
  3. 6 1
      panda/src/doc/eggSyntax.txt
  4. 0 11
      panda/src/egg/eggCompositePrimitive.I
  5. 94 7
      panda/src/egg/eggCompositePrimitive.cxx
  6. 5 2
      panda/src/egg/eggCompositePrimitive.h
  7. 29 1
      panda/src/egg/eggGroupNode.cxx
  8. 58 3
      panda/src/egg/eggLine.I
  9. 31 1
      panda/src/egg/eggLine.cxx
  10. 17 5
      panda/src/egg/eggLine.h
  11. 57 2
      panda/src/egg/eggPoint.I
  12. 7 1
      panda/src/egg/eggPoint.cxx
  13. 9 0
      panda/src/egg/eggPoint.h
  14. 5 1
      panda/src/egg/eggPrimitive.cxx
  15. 18 41
      panda/src/egg/eggTriangleStrip.cxx
  16. 2 3
      panda/src/egg/eggTriangleStrip.h
  17. 85 77
      panda/src/egg/parser.cxx.prebuilt
  18. 8 0
      panda/src/egg/parser.yxx
  19. 14 0
      panda/src/egg2pg/eggLoader.cxx
  20. 4 0
      panda/src/egg2pg/eggRenderState.I
  21. 21 0
      panda/src/egg2pg/eggRenderState.cxx
  22. 2 0
      panda/src/egg2pg/eggRenderState.h
  23. 55 3
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  24. 2 0
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  25. 9 0
      panda/src/gobj/Sources.pp
  26. 9 0
      panda/src/gobj/config_gobj.cxx
  27. 3 0
      panda/src/gobj/gobj_composite1.cxx
  28. 22 0
      panda/src/gobj/qpgeom.I
  29. 10 0
      panda/src/gobj/qpgeom.cxx
  30. 2 0
      panda/src/gobj/qpgeom.h
  31. 160 0
      panda/src/gobj/qpgeomLines.cxx
  32. 74 0
      panda/src/gobj/qpgeomLines.h
  33. 196 0
      panda/src/gobj/qpgeomLinestrips.cxx
  34. 73 0
      panda/src/gobj/qpgeomLinestrips.h
  35. 137 0
      panda/src/gobj/qpgeomPoints.cxx
  36. 71 0
      panda/src/gobj/qpgeomPoints.h
  37. 8 0
      panda/src/gobj/qpgeomPrimitive.h
  38. 14 0
      panda/src/gobj/qpgeomTriangles.cxx
  39. 1 0
      panda/src/gobj/qpgeomTriangles.h
  40. 14 0
      panda/src/gobj/qpgeomTrifans.cxx
  41. 1 0
      panda/src/gobj/qpgeomTrifans.h
  42. 15 1
      panda/src/gobj/qpgeomTristrips.cxx
  43. 1 0
      panda/src/gobj/qpgeomTristrips.h
  44. 6 0
      panda/src/gsgbase/graphicsStateGuardianBase.h

+ 32 - 0
panda/src/display/graphicsStateGuardian.cxx

@@ -41,6 +41,7 @@
 #include "pStatTimer.h"
 #include "qpgeomTristrips.h"
 #include "qpgeomTrifans.h"
+#include "qpgeomLinestrips.h"
 
 #include <algorithm>
 
@@ -712,6 +713,37 @@ draw_trifans(const qpGeomTrifans *primitive) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::draw_lines
+//       Access: Public, Virtual
+//  Description: Draws a series of disconnected line segments.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+draw_lines(const qpGeomLines *) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::draw_linestrips
+//       Access: Public, Virtual
+//  Description: Draws a series of line strips.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+draw_linestrips(const qpGeomLinestrips *primitive) {
+  CPT(qpGeomPrimitive) new_prim = primitive->decompose();
+  if (!new_prim->is_of_type(qpGeomLinestrips::get_class_type())) {
+    new_prim->draw(this);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::draw_points
+//       Access: Public, Virtual
+//  Description: Draws a series of disconnected points.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+draw_points(const qpGeomPoints *) {
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::end_draw_primitives()
 //       Access: Public, Virtual

+ 3 - 0
panda/src/display/graphicsStateGuardian.h

@@ -154,6 +154,9 @@ public:
   virtual void draw_triangles(const qpGeomTriangles *primitive);
   virtual void draw_tristrips(const qpGeomTristrips *primitive);
   virtual void draw_trifans(const qpGeomTrifans *primitive);
+  virtual void draw_lines(const qpGeomLines *primitive);
+  virtual void draw_linestrips(const qpGeomLinestrips *primitive);
+  virtual void draw_points(const qpGeomPoints *primitive);
   virtual void end_draw_primitives();
 
   virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex);

+ 6 - 1
panda/src/doc/eggSyntax.txt

@@ -707,6 +707,7 @@ GEOMETRY ENTRIES
         indices 
         <Ref> { pool-name } 
     } 
+    [component attributes]
 }
 
   A Line is a connected set of line segments.  The listed N vertices
@@ -714,7 +715,11 @@ GEOMETRY ENTRIES
   vertex 1, vertex 1 and vertex 2, etc.  The line is not implicitly
   closed; if you wish to represent a loop, you must repeat vertex 0 at
   the end.  As with a PointLight, normals, textures, colors,
-  draw_order, and the "thick" attribute are all valid.
+  draw_order, and the "thick" attribute are all valid.  Also, since a
+  Line (with more than two vertices) is made up of multiple line
+  segments, it may contain a number of <Component> entries, to set a
+  different color and/or normal for each line segment, as in
+  TriangleStrip, below.
 
 
 <TriangleStrip> name { 

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

@@ -35,17 +35,6 @@ INLINE EggCompositePrimitive::
 EggCompositePrimitive(const EggCompositePrimitive &copy) : EggPrimitive(copy) {
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: EggCompositePrimitive::Destructor
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE EggCompositePrimitive::
-~EggCompositePrimitive() {
-  clear();
-  nassertv(_components.empty());
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: EggCompositePrimitive::Copy assignment operator
 //       Access: Published

+ 94 - 7
panda/src/egg/eggCompositePrimitive.cxx

@@ -22,6 +22,18 @@
 TypeHandle EggCompositePrimitive::_type_handle;
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggCompositePrimitive::Destructor
+//       Access: Published, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+EggCompositePrimitive::
+~EggCompositePrimitive() {
+  // Every derived class of EggCompositePrimitive must call clear() in
+  // its destructor.
+  nassertv(_components.empty());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggCompositePrimitive::get_shading
 //       Access: Published, Virtual
@@ -146,7 +158,7 @@ unify_attributes(EggPrimitive::Shading shading) {
   }
 
   // Not having a color is implicitly white.
-  if (!has_color()) {
+  if (!has_color() && shading != S_overall) {
     set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
   }
 
@@ -253,6 +265,57 @@ unify_attributes(EggPrimitive::Shading shading) {
   case S_unknown:
     break;
   }
+
+  if (!has_color() && shading == S_overall) {
+    set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggCompositePrimitive::apply_last_attribute
+//       Access: Published, Virtual
+//  Description: Sets the last vertex of the triangle (or each
+//               component) to the primitive normal and/or color, if
+//               the primitive is flat-shaded.  This reflects the
+//               OpenGL convention of storing flat-shaded properties on
+//               the last vertex, although it is not usually a
+//               convention in Egg.
+//
+//               This may introduce redundant vertices to the vertex
+//               pool.
+////////////////////////////////////////////////////////////////////
+void EggCompositePrimitive::
+apply_last_attribute() {
+  // The first component gets applied to the third vertex, and so on
+  // from there.
+  int num_lead_vertices = get_num_lead_vertices();
+  for (int i = 0; i < get_num_components(); i++) {
+    EggAttributes *component = get_component(i);
+    do_apply_flat_attribute(i + num_lead_vertices, component);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggCompositePrimitive::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 EggCompositePrimitive::
+apply_first_attribute() {
+  // The first component gets applied to the first vertex, and so on
+  // from there.
+  for (int i = 0; i < get_num_components(); i++) {
+    EggAttributes *component = get_component(i);
+    do_apply_flat_attribute(i, component);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -266,9 +329,10 @@ unify_attributes(EggPrimitive::Shading shading) {
 void EggCompositePrimitive::
 post_apply_flat_attribute() {
   if (!empty()) {
+    int num_lead_vertices = get_num_lead_vertices();
     for (int i = 0; i < (int)size(); i++) {
       EggVertex *vertex = get_vertex(i);
-      EggAttributes *component = get_component(max(i - 2, 0));
+      EggAttributes *component = get_component(max(i - num_lead_vertices, 0));
 
       // Use set_normal() instead of copy_normal(), to avoid getting
       // the morphs--we don't want them here, since we're just putting
@@ -300,7 +364,7 @@ post_apply_flat_attribute() {
 ////////////////////////////////////////////////////////////////////
 bool EggCompositePrimitive::
 cleanup() {
-  return size() >= 3;
+  return (int)size() >= get_num_lead_vertices() + 1;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -319,8 +383,9 @@ void EggCompositePrimitive::
 prepare_add_vertex(EggVertex *vertex, int i, int n) {
   EggPrimitive::prepare_add_vertex(vertex, i, n);
 
-  if (n >= 3) {
-    i = max(i - 2, 0);
+  int num_lead_vertices = get_num_lead_vertices();
+  if (n >= num_lead_vertices + 1) {
+    i = max(i - num_lead_vertices, 0);
     nassertv(i <= (int)_components.size());
     _components.insert(_components.begin() + i, new EggAttributes(*this));
   }
@@ -346,14 +411,36 @@ void EggCompositePrimitive::
 prepare_remove_vertex(EggVertex *vertex, int i, int n) {
   EggPrimitive::prepare_remove_vertex(vertex, i, n);
 
-  if (n >= 3) {
-    i = max(i - 2, 0);
+  int num_lead_vertices = get_num_lead_vertices();
+  if (n >= num_lead_vertices + 1) {
+    i = max(i - num_lead_vertices, 0);
     nassertv(i < (int)_components.size());
     delete _components[i];
     _components.erase(_components.begin() + i);
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggCompositePrimitive::triangulate_poly
+//       Access: Protected, Virtual
+//  Description: Fills the container up with EggPolygons that
+//               represent the component triangles of this triangle
+//               strip.
+//
+//               It is assumed that the EggCompositePrimitive 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 EggCompositePrimitive::
+do_triangulate(EggGroupNode *container) const {
+  container->add_child((EggCompositePrimitive *)this);
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggCompositePrimitive::write_body
 //       Access: Protected

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

@@ -35,7 +35,7 @@ PUBLISHED:
   INLINE EggCompositePrimitive(const string &name = "");
   INLINE EggCompositePrimitive(const EggCompositePrimitive &copy);
   INLINE EggCompositePrimitive &operator = (const EggCompositePrimitive &copy);
-  INLINE ~EggCompositePrimitive();
+  virtual ~EggCompositePrimitive();
 
   virtual Shading get_shading() const;
 
@@ -48,14 +48,17 @@ PUBLISHED:
   PT(EggCompositePrimitive) triangulate_in_place();
 
   virtual void unify_attributes(Shading shading);
+  virtual void apply_last_attribute();
+  virtual void apply_first_attribute();
   virtual void post_apply_flat_attribute();
   virtual bool cleanup();
 
 protected:
+  virtual int get_num_lead_vertices() const=0;
   virtual void prepare_add_vertex(EggVertex *vertex, int i, int n);
   virtual void prepare_remove_vertex(EggVertex *vertex, int i, int n);
 
-  virtual bool do_triangulate(EggGroupNode *container) const=0;
+  virtual bool do_triangulate(EggGroupNode *container) const;
 
   void write_body(ostream &out, int indent_level) const;
 

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

@@ -922,7 +922,35 @@ rebuild_vertex_pool(EggVertexPool *vertex_pool, bool recurse) {
   for (ci = _children.begin(); ci != _children.end(); ++ci) {
     EggNode *child = *ci;
 
-    if (child->is_of_type(EggPrimitive::get_class_type())) {
+    if (child->is_of_type(EggCompositePrimitive::get_class_type())) {
+      typedef pvector< PT(EggVertex) > Vertices;
+      typedef pvector<EggAttributes> Attributes;
+      Vertices vertices;
+      Attributes attributes;
+
+      EggCompositePrimitive *prim = DCAST(EggCompositePrimitive, child);
+      EggPrimitive::const_iterator pi;
+      for (pi = prim->begin(); pi != prim->end(); ++pi) {
+        vertices.push_back(*pi);
+      }
+      int i;
+      int num_components = prim->get_num_components();
+      for (i = 0; i < num_components; i++) {
+        attributes.push_back(*prim->get_component(i));
+      }
+
+      prim->clear();
+
+      Vertices::const_iterator vi;
+      for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
+        EggVertex *vertex = (*vi);
+        prim->add_vertex(vertex_pool->create_unique_vertex(*vertex));
+      }
+      for (i = 0; i < num_components; i++) {
+        prim->set_component(i, &attributes[i]);
+      }
+
+    } else if (child->is_of_type(EggPrimitive::get_class_type())) {
       typedef pvector< PT(EggVertex) > Vertices;
       Vertices vertices;
 

+ 58 - 3
panda/src/egg/eggLine.I

@@ -23,7 +23,10 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE EggLine::
-EggLine(const string &name) : EggPrimitive(name) {
+EggLine(const string &name) : 
+  EggCompositePrimitive(name),
+  _has_thick(false)
+{
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -32,7 +35,11 @@ EggLine(const string &name) : EggPrimitive(name) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE EggLine::
-EggLine(const EggLine &copy) : EggPrimitive(copy) {
+EggLine(const EggLine &copy) : 
+  EggCompositePrimitive(copy),
+  _thick(copy._thick),
+  _has_thick(copy._has_thick)
+{
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -42,6 +49,54 @@ EggLine(const EggLine &copy) : EggPrimitive(copy) {
 ////////////////////////////////////////////////////////////////////
 INLINE EggLine &EggLine::
 operator = (const EggLine &copy) {
-  EggPrimitive::operator = (copy);
+  EggCompositePrimitive::operator = (copy);
+  _thick = copy._thick;
+  _has_thick = copy._has_thick;
   return *this;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggLine::has_thick
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool EggLine::
+has_thick() const {
+  return _has_thick;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggLine::get_thick
+//       Access: Published
+//  Description: Returns the thick set on this particular attribute.
+//               If there is no thick set, returns white.
+////////////////////////////////////////////////////////////////////
+INLINE double EggLine::
+get_thick() const {
+  if (has_thick()) {
+    return _thick;
+  } else {
+    return 1.0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggLine::
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggLine::
+set_thick(double thick) {
+  _thick = thick;
+  _has_thick = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggLine::
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggLine::
+clear_thick() {
+  _has_thick = false;
+}

+ 31 - 1
panda/src/egg/eggLine.cxx

@@ -22,6 +22,17 @@
 
 TypeHandle EggLine::_type_handle;
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggLine::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+EggLine::
+~EggLine() {
+  clear();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggLine::write
 //       Access: Public, Virtual
@@ -31,6 +42,25 @@ TypeHandle EggLine::_type_handle;
 void EggLine::
 write(ostream &out, int indent_level) const {
   write_header(out, indent_level, "<Line>");
-  write_body(out, indent_level+2);
+
+  if (has_thick()) {
+    indent(out, indent_level + 2) 
+      << "<Scalar> thick { " << get_thick() << " }\n";
+  }
+
+  write_body(out, indent_level + 2);
   indent(out, indent_level) << "}\n";
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggLine::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 EggLine::
+get_num_lead_vertices() const {
+  return 1;
+}

+ 17 - 5
panda/src/egg/eggLine.h

@@ -21,30 +21,42 @@
 
 #include "pandabase.h"
 
-#include "eggPrimitive.h"
+#include "eggCompositePrimitive.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : EggLine
 // Description : A line segment, or a series of connected line
 //               segments, defined by a <Line> entry.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDAEGG EggLine : public EggPrimitive {
+class EXPCL_PANDAEGG EggLine : public EggCompositePrimitive {
 PUBLISHED:
   INLINE EggLine(const string &name = "");
   INLINE EggLine(const EggLine &copy);
   INLINE EggLine &operator = (const EggLine &copy);
+  virtual ~EggLine();
 
   virtual void write(ostream &out, int indent_level) const;
 
-public:
+  INLINE bool has_thick() const;
+  INLINE double get_thick() const;
+  INLINE void set_thick(const double thick);
+  INLINE void clear_thick();
+
+protected:
+  virtual int get_num_lead_vertices() const;
 
+private:
+  double _thick;
+  bool _has_thick;
+
+public:
   static TypeHandle get_class_type() {
     return _type_handle;
   }
   static void init_type() {
-    EggPrimitive::init_type();
+    EggCompositePrimitive::init_type();
     register_type(_type_handle, "EggLine",
-                  EggPrimitive::get_class_type());
+                  EggCompositePrimitive::get_class_type());
   }
   virtual TypeHandle get_type() const {
     return get_class_type();

+ 57 - 2
panda/src/egg/eggPoint.I

@@ -23,7 +23,10 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE EggPoint::
-EggPoint(const string &name) : EggPrimitive(name) {
+EggPoint(const string &name) : 
+  EggPrimitive(name),
+  _has_thick(false)
+{
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -32,7 +35,11 @@ EggPoint(const string &name) : EggPrimitive(name) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE EggPoint::
-EggPoint(const EggPoint &copy) : EggPrimitive(copy) {
+EggPoint(const EggPoint &copy) : 
+  EggPrimitive(copy),
+  _thick(copy._thick),
+  _has_thick(copy._has_thick)
+{
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -43,5 +50,53 @@ EggPoint(const EggPoint &copy) : EggPrimitive(copy) {
 INLINE EggPoint &EggPoint::
 operator = (const EggPoint &copy) {
   EggPrimitive::operator = (copy);
+  _thick = copy._thick;
+  _has_thick = copy._has_thick;
   return *this;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggPoint::has_thick
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool EggPoint::
+has_thick() const {
+  return _has_thick;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggPoint::get_thick
+//       Access: Published
+//  Description: Returns the thick set on this particular attribute.
+//               If there is no thick set, returns white.
+////////////////////////////////////////////////////////////////////
+INLINE double EggPoint::
+get_thick() const {
+  if (has_thick()) {
+    return _thick;
+  } else {
+    return 1.0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggPoint::
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggPoint::
+set_thick(double thick) {
+  _thick = thick;
+  _has_thick = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggPoint::
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggPoint::
+clear_thick() {
+  _has_thick = false;
+}

+ 7 - 1
panda/src/egg/eggPoint.cxx

@@ -47,6 +47,12 @@ cleanup() {
 void EggPoint::
 write(ostream &out, int indent_level) const {
   write_header(out, indent_level, "<PointLight>");
-  write_body(out, indent_level+2);
+
+  if (has_thick()) {
+    indent(out, indent_level + 2) 
+      << "<Scalar> thick { " << get_thick() << " }\n";
+  }
+
+  write_body(out, indent_level + 2);
   indent(out, indent_level) << "}\n";
 }

+ 9 - 0
panda/src/egg/eggPoint.h

@@ -34,10 +34,19 @@ PUBLISHED:
   INLINE EggPoint(const EggPoint &copy);
   INLINE EggPoint &operator = (const EggPoint &copy);
 
+  INLINE bool has_thick() const;
+  INLINE double get_thick() const;
+  INLINE void set_thick(const double thick);
+  INLINE void clear_thick();
+
   virtual bool cleanup();
 
   virtual void write(ostream &out, int indent_level) const;
 
+private:
+  double _thick;
+  bool _has_thick;
+
 public:
 
   static TypeHandle get_class_type() {

+ 5 - 1
panda/src/egg/eggPrimitive.cxx

@@ -353,7 +353,7 @@ unify_attributes(EggPrimitive::Shading shading) {
   }
 
   // Not having a color is implicitly white.
-  if (!has_color()) {
+  if (!has_color() && shading != S_overall) {
     set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
   }
 
@@ -408,6 +408,10 @@ unify_attributes(EggPrimitive::Shading shading) {
   case S_unknown:
     break;
   }
+
+  if (!has_color() && shading == S_overall) {
+    set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 18 - 41
panda/src/egg/eggTriangleStrip.cxx

@@ -29,49 +29,13 @@ TypeHandle EggTriangleStrip::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTriangleStrip::apply_last_attribute
+//     Function: EggTriangleStrip::Destructor
 //       Access: Published, Virtual
-//  Description: Sets the last vertex of the triangle (or each
-//               component) to the primitive normal and/or color, if
-//               the primitive is flat-shaded.  This reflects the
-//               OpenGL convention of storing flat-shaded properties on
-//               the last vertex, although it is not usually a
-//               convention in Egg.
-//
-//               This may introduce redundant vertices to the vertex
-//               pool.
-////////////////////////////////////////////////////////////////////
-void EggTriangleStrip::
-apply_last_attribute() {
-  // The first component gets applied to the third vertex, and so on
-  // from there.
-  for (int i = 0; i < get_num_components(); i++) {
-    EggAttributes *component = get_component(i);
-    do_apply_flat_attribute(i + 2, component);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTriangleStrip::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.
+//  Description: 
 ////////////////////////////////////////////////////////////////////
-void EggTriangleStrip::
-apply_first_attribute() {
-  // The first component gets applied to the first vertex, and so on
-  // from there.
-  for (int i = 0; i < get_num_components(); i++) {
-    EggAttributes *component = get_component(i);
-    do_apply_flat_attribute(i, component);
-  }
+EggTriangleStrip::
+~EggTriangleStrip() {
+  clear();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -87,6 +51,19 @@ write(ostream &out, int indent_level) const {
   indent(out, indent_level) << "}\n";
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggTriangleStrip::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 EggTriangleStrip::
+get_num_lead_vertices() const {
+  return 2;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggTriangleStrip::triangulate_poly
 //       Access: Protected, Virtual

+ 2 - 3
panda/src/egg/eggTriangleStrip.h

@@ -34,13 +34,12 @@ PUBLISHED:
   INLINE EggTriangleStrip(const string &name = "");
   INLINE EggTriangleStrip(const EggTriangleStrip &copy);
   INLINE EggTriangleStrip &operator = (const EggTriangleStrip &copy);
-
-  virtual void apply_last_attribute();
-  virtual void apply_first_attribute();
+  virtual ~EggTriangleStrip();
 
   virtual void write(ostream &out, int indent_level) const;
 
 protected:
+  virtual int get_num_lead_vertices() const;
   virtual bool do_triangulate(EggGroupNode *container) const;
 
 public:

+ 85 - 77
panda/src/egg/parser.cxx.prebuilt

@@ -451,17 +451,17 @@ static const short yyrline[] =
     1468,  1471,  1473,  1491,  1524,  1529,  1553,  1565,  1571,  1587,
     1587,  1606,  1606,  1625,  1625,  1644,  1644,  1663,  1663,  1682,
     1682,  1702,  1704,  1705,  1715,  1717,  1717,  1738,  1739,  1740,
-    1741,  1742,  1743,  1744,  1745,  1803,  1805,  1806,  1807,  1808,
-    1809,  1810,  1811,  1812,  1813,  1814,  1815,  1821,  1822,  1885,
-    1887,  1888,  1889,  1890,  1891,  1892,  1893,  1894,  1895,  1896,
-    1964,  1981,  2021,  2038,  2043,  2051,  2068,  2073,  2081,  2098,
-    2114,  2145,  2163,  2183,  2203,  2209,  2219,  2226,  2244,  2260,
-    2281,  2281,  2303,  2303,  2325,  2327,  2331,  2335,  2339,  2343,
-    2357,  2357,  2378,  2380,  2392,  2405,  2405,  2426,  2428,  2445,
-    2458,  2458,  2479,  2481,  2496,  2510,  2515,  2528,  2533,  2546,
-    2567,  2588,  2612,  2618,  2629,  2641,  2647,  2657,  2662,  2675,
-    2680,  2684,  2696,  2701,  2716,  2721,  2734,  2736,  2750,  2757,
-    2763,  2779,  2788,  2794
+    1741,  1742,  1743,  1744,  1745,  1811,  1813,  1814,  1815,  1816,
+    1817,  1818,  1819,  1820,  1821,  1822,  1823,  1829,  1830,  1893,
+    1895,  1896,  1897,  1898,  1899,  1900,  1901,  1902,  1903,  1904,
+    1972,  1989,  2029,  2046,  2051,  2059,  2076,  2081,  2089,  2106,
+    2122,  2153,  2171,  2191,  2211,  2217,  2227,  2234,  2252,  2268,
+    2289,  2289,  2311,  2311,  2333,  2335,  2339,  2343,  2347,  2351,
+    2365,  2365,  2386,  2388,  2400,  2413,  2413,  2434,  2436,  2453,
+    2466,  2466,  2487,  2489,  2504,  2518,  2523,  2536,  2541,  2554,
+    2575,  2596,  2620,  2626,  2637,  2649,  2655,  2665,  2670,  2683,
+    2688,  2692,  2704,  2709,  2724,  2729,  2742,  2744,  2758,  2765,
+    2771,  2787,  2796,  2802
 };
 #endif
 
@@ -3016,13 +3016,21 @@ case 154:
     primitive->set_draw_order((int)value);
   } else if (cmp_nocase_uh(name, "bin") == 0) {
     primitive->set_bin(strval);
+  } else if (cmp_nocase_uh(name, "thick") == 0) {
+    if (primitive->is_of_type(EggLine::get_class_type())) {
+      DCAST(EggLine, primitive)->set_thick(value);
+    } else if (primitive->is_of_type(EggPoint::get_class_type())) {
+      DCAST(EggPoint, primitive)->set_thick(value);
+    } else {
+      eggyywarning("scalar thick is only meaningful for points and lines.");
+    }
   } else {
     eggyywarning("Unknown scalar " + name);
   }
 }
     break;
 case 166:
-#line 1816 "parser.yxx"
+#line 1824 "parser.yxx"
 {
   EggNurbsCurve *curve = DCAST(EggNurbsCurve, yyvsp[0]._egg);
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
@@ -3030,7 +3038,7 @@ case 166:
 }
     break;
 case 168:
-#line 1823 "parser.yxx"
+#line 1831 "parser.yxx"
 {
   EggNurbsSurface *primitive = DCAST(EggNurbsSurface, egg_stack.back());
   string name = yyvsp[-3]._string;
@@ -3085,7 +3093,7 @@ case 168:
 }
     break;
 case 179:
-#line 1897 "parser.yxx"
+#line 1905 "parser.yxx"
 {
   EggNurbsCurve *primitive = DCAST(EggNurbsCurve, egg_stack.back());
   string name = yyvsp[-3]._string;
@@ -3146,7 +3154,7 @@ case 179:
 }
     break;
 case 180:
-#line 1966 "parser.yxx"
+#line 1974 "parser.yxx"
 {
   if (yyvsp[0]._egg != (EggTexture *)NULL) {
     EggTexture *texture = DCAST(EggTexture, yyvsp[0]._egg);
@@ -3155,7 +3163,7 @@ case 180:
 }
     break;
 case 181:
-#line 1983 "parser.yxx"
+#line 1991 "parser.yxx"
 {
   EggTexture *texture = NULL;
 
@@ -3187,7 +3195,7 @@ case 181:
 }
     break;
 case 182:
-#line 2023 "parser.yxx"
+#line 2031 "parser.yxx"
 {
   if (yyvsp[0]._egg != (EggMaterial *)NULL) {
     EggMaterial *material = DCAST(EggMaterial, yyvsp[0]._egg);
@@ -3196,13 +3204,13 @@ case 182:
 }
     break;
 case 183:
-#line 2040 "parser.yxx"
+#line 2048 "parser.yxx"
 {
   DCAST(EggPrimitive, egg_stack.back())->set_normal(Normald(yyvsp[-2]._number, yyvsp[-1]._number, yyvsp[0]._number));
 }
     break;
 case 184:
-#line 2044 "parser.yxx"
+#line 2052 "parser.yxx"
 {
   bool inserted = DCAST(EggPrimitive, egg_stack.back())->_dnormals.
     insert(EggMorphNormal(yyvsp[-5]._string, LVector3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number))).second;
@@ -3212,7 +3220,7 @@ case 184:
 }
     break;
 case 185:
-#line 2052 "parser.yxx"
+#line 2060 "parser.yxx"
 {
   bool inserted = DCAST(EggPrimitive, egg_stack.back())->_dnormals.
     insert(EggMorphNormal(yyvsp[-4]._string, LVector3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number))).second;
@@ -3222,13 +3230,13 @@ case 185:
 }
     break;
 case 186:
-#line 2070 "parser.yxx"
+#line 2078 "parser.yxx"
 {
   DCAST(EggPrimitive, egg_stack.back())->set_color(Colorf(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number, yyvsp[0]._number));
 }
     break;
 case 187:
-#line 2074 "parser.yxx"
+#line 2082 "parser.yxx"
 {
   bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas.
     insert(EggMorphColor(yyvsp[-6]._string, LVector4f(yyvsp[-4]._number, yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number))).second;
@@ -3238,7 +3246,7 @@ case 187:
 }
     break;
 case 188:
-#line 2082 "parser.yxx"
+#line 2090 "parser.yxx"
 {
   bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas.
     insert(EggMorphColor(yyvsp[-5]._string, LVector4f(yyvsp[-4]._number, yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number))).second;
@@ -3248,7 +3256,7 @@ case 188:
 }
     break;
 case 189:
-#line 2100 "parser.yxx"
+#line 2108 "parser.yxx"
 {
   EggPrimitive *primitive = DCAST(EggPrimitive, egg_stack.back());
   int value = (int)yyvsp[0]._number;
@@ -3256,7 +3264,7 @@ case 189:
 }
     break;
 case 190:
-#line 2116 "parser.yxx"
+#line 2124 "parser.yxx"
 {
   if (yyvsp[-2]._egg != (EggVertexPool *)NULL) {
     EggVertexPool *pool = DCAST(EggVertexPool, yyvsp[-2]._egg);
@@ -3279,7 +3287,7 @@ case 190:
 }
     break;
 case 191:
-#line 2147 "parser.yxx"
+#line 2155 "parser.yxx"
 {
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   int u_order = (int)yyvsp[-1]._number;
@@ -3289,7 +3297,7 @@ case 191:
 }
     break;
 case 192:
-#line 2165 "parser.yxx"
+#line 2173 "parser.yxx"
 {
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   PTA_double nums = yyvsp[0]._number_list;
@@ -3301,7 +3309,7 @@ case 192:
 }
     break;
 case 193:
-#line 2185 "parser.yxx"
+#line 2193 "parser.yxx"
 {
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   PTA_double nums = yyvsp[0]._number_list;
@@ -3313,14 +3321,14 @@ case 193:
 }
     break;
 case 194:
-#line 2205 "parser.yxx"
+#line 2213 "parser.yxx"
 {
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   nurbs->_trims.push_back(EggNurbsSurface::Trim());
 }
     break;
 case 196:
-#line 2221 "parser.yxx"
+#line 2229 "parser.yxx"
 {
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   nassertr(!nurbs->_trims.empty(), 0);
@@ -3328,7 +3336,7 @@ case 196:
 }
     break;
 case 197:
-#line 2227 "parser.yxx"
+#line 2235 "parser.yxx"
 {
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   nassertr(!nurbs->_trims.empty(), 0);
@@ -3338,7 +3346,7 @@ case 197:
 }
     break;
 case 198:
-#line 2246 "parser.yxx"
+#line 2254 "parser.yxx"
 {
   EggNurbsCurve *nurbs = DCAST(EggNurbsCurve, egg_stack.back());
   int order = (int)yyvsp[0]._number;
@@ -3346,7 +3354,7 @@ case 198:
 }
     break;
 case 199:
-#line 2262 "parser.yxx"
+#line 2270 "parser.yxx"
 {
   EggNurbsCurve *nurbs = DCAST(EggNurbsCurve, egg_stack.back());
   PTA_double nums = yyvsp[0]._number_list;
@@ -3358,7 +3366,7 @@ case 199:
 }
     break;
 case 200:
-#line 2283 "parser.yxx"
+#line 2291 "parser.yxx"
 {
   EggTable *table = new EggTable(yyvsp[0]._string);
   table->set_table_type(EggTable::TT_table);
@@ -3366,14 +3374,14 @@ case 200:
 }
     break;
 case 201:
-#line 2289 "parser.yxx"
+#line 2297 "parser.yxx"
 {
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
 }
     break;
 case 202:
-#line 2305 "parser.yxx"
+#line 2313 "parser.yxx"
 {
   EggTable *table = new EggTable(yyvsp[0]._string);
   table->set_table_type(EggTable::TT_bundle);
@@ -3381,58 +3389,58 @@ case 202:
 }
     break;
 case 203:
-#line 2311 "parser.yxx"
+#line 2319 "parser.yxx"
 {
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
 }
     break;
 case 205:
-#line 2328 "parser.yxx"
+#line 2336 "parser.yxx"
 {
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
 }
     break;
 case 206:
-#line 2332 "parser.yxx"
+#line 2340 "parser.yxx"
 {
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
 }
     break;
 case 207:
-#line 2336 "parser.yxx"
+#line 2344 "parser.yxx"
 {
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
 }
     break;
 case 208:
-#line 2340 "parser.yxx"
+#line 2348 "parser.yxx"
 {
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
 }
     break;
 case 209:
-#line 2344 "parser.yxx"
+#line 2352 "parser.yxx"
 {
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
 }
     break;
 case 210:
-#line 2359 "parser.yxx"
+#line 2367 "parser.yxx"
 {
   EggSAnimData *anim_data = new EggSAnimData(yyvsp[0]._string);
   egg_stack.push_back(anim_data);
 }
     break;
 case 211:
-#line 2364 "parser.yxx"
+#line 2372 "parser.yxx"
 {
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
 }
     break;
 case 213:
-#line 2381 "parser.yxx"
+#line 2389 "parser.yxx"
 {
   EggSAnimData *anim_data = DCAST(EggSAnimData, egg_stack.back());
   string name = yyvsp[-3]._string;
@@ -3446,27 +3454,27 @@ case 213:
 }
     break;
 case 214:
-#line 2393 "parser.yxx"
+#line 2401 "parser.yxx"
 {
   DCAST(EggSAnimData, egg_stack.back())->set_data(yyvsp[-1]._number_list);
 }
     break;
 case 215:
-#line 2407 "parser.yxx"
+#line 2415 "parser.yxx"
 {
   EggXfmAnimData *anim_data = new EggXfmAnimData(yyvsp[0]._string);
   egg_stack.push_back(anim_data);
 }
     break;
 case 216:
-#line 2412 "parser.yxx"
+#line 2420 "parser.yxx"
 {
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
 }
     break;
 case 218:
-#line 2429 "parser.yxx"
+#line 2437 "parser.yxx"
 {
   EggXfmAnimData *anim_data = DCAST(EggXfmAnimData, egg_stack.back());
   string name = yyvsp[-3]._string;
@@ -3485,27 +3493,27 @@ case 218:
 }
     break;
 case 219:
-#line 2446 "parser.yxx"
+#line 2454 "parser.yxx"
 {
   DCAST(EggXfmAnimData, egg_stack.back())->set_data(yyvsp[-1]._number_list);
 }
     break;
 case 220:
-#line 2460 "parser.yxx"
+#line 2468 "parser.yxx"
 {
   EggXfmSAnim *anim_group = new EggXfmSAnim(yyvsp[0]._string);
   egg_stack.push_back(anim_group);
 }
     break;
 case 221:
-#line 2465 "parser.yxx"
+#line 2473 "parser.yxx"
 {
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
 }
     break;
 case 223:
-#line 2482 "parser.yxx"
+#line 2490 "parser.yxx"
 {
   EggXfmSAnim *anim_group = DCAST(EggXfmSAnim, egg_stack.back());
   string name = yyvsp[-3]._string;
@@ -3522,37 +3530,37 @@ case 223:
 }
     break;
 case 224:
-#line 2497 "parser.yxx"
+#line 2505 "parser.yxx"
 {
   DCAST(EggXfmSAnim, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
 }
     break;
 case 225:
-#line 2512 "parser.yxx"
+#line 2520 "parser.yxx"
 {
   yyval._number_list = PTA_double::empty_array(0);
 }
     break;
 case 226:
-#line 2516 "parser.yxx"
+#line 2524 "parser.yxx"
 {
   yyval._number_list.push_back((double)yyvsp[0]._number);
 }
     break;
 case 227:
-#line 2530 "parser.yxx"
+#line 2538 "parser.yxx"
 {
   yyval._number_list = PTA_double::empty_array(0);
 }
     break;
 case 228:
-#line 2534 "parser.yxx"
+#line 2542 "parser.yxx"
 {
   yyval._number_list.push_back(yyvsp[0]._number);
 }
     break;
 case 229:
-#line 2548 "parser.yxx"
+#line 2556 "parser.yxx"
 {
   string name = yyvsp[0]._string;
   Textures::iterator vpi = textures.find(name);
@@ -3565,7 +3573,7 @@ case 229:
 }
     break;
 case 230:
-#line 2569 "parser.yxx"
+#line 2577 "parser.yxx"
 {
   string name = yyvsp[0]._string;
   Materials::iterator vpi = materials.find(name);
@@ -3578,7 +3586,7 @@ case 230:
 }
     break;
 case 231:
-#line 2590 "parser.yxx"
+#line 2598 "parser.yxx"
 {
   string name = yyvsp[0]._string;
   VertexPools::iterator vpi = vertex_pools.find(name);
@@ -3593,69 +3601,69 @@ case 231:
 }
     break;
 case 232:
-#line 2614 "parser.yxx"
+#line 2622 "parser.yxx"
 {
   eggyyerror("Name required.");
   yyval._string = "";
 }
     break;
 case 235:
-#line 2643 "parser.yxx"
+#line 2651 "parser.yxx"
 {
   eggyyerror("String required.");
   yyval._string = "";
 }
     break;
 case 237:
-#line 2659 "parser.yxx"
+#line 2667 "parser.yxx"
 {
   yyval._string = "";
 }
     break;
 case 239:
-#line 2677 "parser.yxx"
+#line 2685 "parser.yxx"
 {
   yyval._string = yyvsp[0]._string;
 }
     break;
 case 240:
-#line 2681 "parser.yxx"
+#line 2689 "parser.yxx"
 {
   yyval._string = yyvsp[0]._string;
 }
     break;
 case 242:
-#line 2698 "parser.yxx"
+#line 2706 "parser.yxx"
 {
   yyval._string = "";
 }
     break;
 case 243:
-#line 2702 "parser.yxx"
+#line 2710 "parser.yxx"
 {
   yyval._string = yyvsp[0]._string;
 }
     break;
 case 244:
-#line 2718 "parser.yxx"
+#line 2726 "parser.yxx"
 {
   yyval._string = yyvsp[0]._string;
 }
     break;
 case 245:
-#line 2722 "parser.yxx"
+#line 2730 "parser.yxx"
 {
   yyval._string = yyvsp[-1]._string + "\n" + yyvsp[0]._string;
 }
     break;
 case 247:
-#line 2737 "parser.yxx"
+#line 2745 "parser.yxx"
 {
   yyval._number = yyvsp[0]._ulong;
 }
     break;
 case 248:
-#line 2752 "parser.yxx"
+#line 2760 "parser.yxx"
 {
   yyval._number = yyvsp[0]._number;
   yyval._ulong = (unsigned long)yyvsp[0]._number;
@@ -3663,7 +3671,7 @@ case 248:
 }
     break;
 case 249:
-#line 2758 "parser.yxx"
+#line 2766 "parser.yxx"
 {
   yyval._number = yyvsp[0]._ulong;
   yyval._ulong = yyvsp[0]._ulong;
@@ -3671,7 +3679,7 @@ case 249:
 }
     break;
 case 250:
-#line 2764 "parser.yxx"
+#line 2772 "parser.yxx"
 {
   yyval._number = 0.0;
   yyval._ulong = 0;
@@ -3679,7 +3687,7 @@ case 250:
 }
     break;
 case 251:
-#line 2781 "parser.yxx"
+#line 2789 "parser.yxx"
 {
   int i = (int)yyvsp[0]._number;
   if ((double)i != yyvsp[0]._number) {
@@ -3689,7 +3697,7 @@ case 251:
 }
     break;
 case 252:
-#line 2789 "parser.yxx"
+#line 2797 "parser.yxx"
 {
   yyval._number = yyvsp[0]._ulong;
 }
@@ -3927,4 +3935,4 @@ yyreturn:
 #endif
   return yyresult;
 }
-#line 2796 "parser.yxx"
+#line 2804 "parser.yxx"

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

@@ -1787,6 +1787,14 @@ primitive_body:
     primitive->set_draw_order((int)value);
   } else if (cmp_nocase_uh(name, "bin") == 0) {
     primitive->set_bin(strval);
+  } else if (cmp_nocase_uh(name, "thick") == 0) {
+    if (primitive->is_of_type(EggLine::get_class_type())) {
+      DCAST(EggLine, primitive)->set_thick(value);
+    } else if (primitive->is_of_type(EggPoint::get_class_type())) {
+      DCAST(EggPoint, primitive)->set_thick(value);
+    } else {
+      eggyywarning("scalar thick is only meaningful for points and lines.");
+    }
   } else {
     eggyywarning("Unknown scalar " + name);
   }

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

@@ -40,6 +40,9 @@
 #include "qpgeom.h"
 #include "qpgeomTriangles.h"
 #include "qpgeomTristrips.h"
+#include "qpgeomLines.h"
+#include "qpgeomLinestrips.h"
+#include "qpgeomPoints.h"
 #include "sequenceNode.h"
 #include "switchNode.h"
 #include "portalNode.h"
@@ -1993,8 +1996,19 @@ make_primitive(const EggRenderState *render_state, EggPrimitive *egg_prim,
     if (egg_prim->size() == 3) {
       primitive = new qpGeomTriangles(qpGeomUsageHint::UH_static);
     }
+
   } else if (egg_prim->is_of_type(EggTriangleStrip::get_class_type())) {
     primitive = new qpGeomTristrips(qpGeomUsageHint::UH_static);
+
+  } else if (egg_prim->is_of_type(EggLine::get_class_type())) {
+    if (egg_prim->size() == 2) {
+      primitive = new qpGeomLines(qpGeomUsageHint::UH_static);
+    } else {
+      primitive = new qpGeomLinestrips(qpGeomUsageHint::UH_static);
+    }
+
+  } else if (egg_prim->is_of_type(EggPoint::get_class_type())) {
+    primitive = new qpGeomPoints(qpGeomUsageHint::UH_static);
   }
 
   if (primitive == (qpGeomPrimitive *)NULL) {

+ 4 - 0
panda/src/egg2pg/eggRenderState.I

@@ -27,6 +27,7 @@ EggRenderState(EggLoader &loader) :
   _state(RenderState::make_empty()),
   _hidden(false),
   _flat_shaded(false),
+  _primitive_type(qpGeomPrimitive::PT_none),
   _loader(loader)
 {
 }
@@ -60,5 +61,8 @@ compare_to(const EggRenderState &other) const {
   if (_flat_shaded != other._flat_shaded) {
     return (int)_flat_shaded - (int)other._flat_shaded;
   }
+  if (_primitive_type != other._primitive_type) {
+    return (int)_primitive_type - (int)other._primitive_type;
+  }
   return 0;
 }

+ 21 - 0
panda/src/egg2pg/eggRenderState.cxx

@@ -18,6 +18,8 @@
 
 #include "eggRenderState.h"
 #include "eggRenderMode.h"
+#include "eggLine.h"
+#include "eggPoint.h"
 #include "textureAttrib.h"
 #include "renderAttrib.h"
 #include "eggTexture.h"
@@ -32,6 +34,7 @@
 #include "depthWriteAttrib.h"
 #include "depthTestAttrib.h"
 #include "texMatrixAttrib.h"
+#include "renderModeAttrib.h"
 #include "material.h"
 #include "materialAttrib.h"
 #include "materialPool.h"
@@ -349,6 +352,24 @@ fill_state(EggPrimitive *egg_prim) {
     }
   }
 
+  if (egg_prim->is_of_type(EggLine::get_class_type())) {
+    _primitive_type = qpGeomPrimitive::PT_lines;
+    EggLine *egg_line = DCAST(EggLine, egg_prim);
+    if (egg_line->get_thick() != 1.0) {
+      add_attrib(RenderModeAttrib::make(RenderModeAttrib::M_unchanged, 
+                                        egg_line->get_thick()));
+    }
+  } else if (egg_prim->is_of_type(EggPoint::get_class_type())) {
+    _primitive_type = qpGeomPrimitive::PT_points;
+    EggPoint *egg_point = DCAST(EggPoint, egg_prim);
+    if (egg_point->get_thick() != 1.0) {
+      add_attrib(RenderModeAttrib::make(RenderModeAttrib::M_unchanged, 
+                                        egg_point->get_thick()));
+    }
+  } else {
+    _primitive_type = qpGeomPrimitive::PT_polygons;
+  }
+
   if (has_bin) {
     add_attrib(CullBinAttrib::make(bin, draw_order));
 

+ 2 - 0
panda/src/egg2pg/eggRenderState.h

@@ -26,6 +26,7 @@
 #include "renderState.h"
 #include "renderAttrib.h"
 #include "internalName.h"
+#include "qpgeomPrimitive.h"
 #include "luse.h"
 #include "pointerTo.h"
 #include "pvector.h"
@@ -64,6 +65,7 @@ public:
   CPT(RenderState) _state;
   bool _hidden;
   bool _flat_shaded;
+  qpGeomPrimitive::PrimitiveType _primitive_type;
 
   typedef EggLoader::BakeInUVs BakeInUVs;
   typedef EggLoader::TextureDef TextureDef;

+ 55 - 3
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -25,6 +25,9 @@
 #include "qpgeomTriangles.h"
 #include "qpgeomTristrips.h"
 #include "qpgeomTrifans.h"
+#include "qpgeomLines.h"
+#include "qpgeomLinestrips.h"
+#include "qpgeomPoints.h"
 #include "graphicsWindow.h"
 #include "lens.h"
 #include "perspectiveLens.h"
@@ -2065,6 +2068,20 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
 
   _geom_display_list = 0;
 
+  if (_auto_antialias_mode) {
+    switch (geom->get_primitive_type()) {
+    case qpGeomPrimitive::PT_polygons:
+      setup_antialias_polygon();
+      break;
+    case qpGeomPrimitive::PT_points:
+      setup_antialias_point();
+      break;
+    case qpGeomPrimitive::PT_lines:
+      setup_antialias_line();
+      break;
+    }
+  }
+
   if (geom->get_usage_hint() == qpGeomUsageHint::UH_static && 
       _vertex_data->get_usage_hint() == qpGeomUsageHint::UH_static &&
       display_lists) {
@@ -2209,7 +2226,6 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 draw_triangles(const qpGeomTriangles *primitive) {
-  //  setup_antialias_polygon();
   _vertices_tri_pcollector.add_level(primitive->get_num_vertices());
   const unsigned short *client_pointer = setup_primitive(primitive);
 
@@ -2229,8 +2245,6 @@ draw_triangles(const qpGeomTriangles *primitive) {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 draw_tristrips(const qpGeomTristrips *primitive) {
-  //  setup_antialias_polygon();
-
   _vertices_tristrip_pcollector.add_level(primitive->get_num_vertices());
   const unsigned short *client_pointer = setup_primitive(primitive);
 
@@ -2250,6 +2264,44 @@ draw_tristrips(const qpGeomTristrips *primitive) {
   report_my_gl_errors();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::draw_lines
+//       Access: Public, Virtual
+//  Description: Draws a series of disconnected line segments.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+draw_lines(const qpGeomLines *primitive) {
+  _vertices_tri_pcollector.add_level(primitive->get_num_vertices());
+  const unsigned short *client_pointer = setup_primitive(primitive);
+
+  _glDrawRangeElements(GL_LINES, 
+                       primitive->get_min_vertex(),
+                       primitive->get_max_vertex(),
+                       primitive->get_num_vertices(),
+                       GL_UNSIGNED_SHORT, client_pointer);
+
+  report_my_gl_errors();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::draw_points
+//       Access: Public, Virtual
+//  Description: Draws a series of disconnected points.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+draw_points(const qpGeomPoints *primitive) {
+  _vertices_tri_pcollector.add_level(primitive->get_num_vertices());
+  const unsigned short *client_pointer = setup_primitive(primitive);
+
+  _glDrawRangeElements(GL_POINTS, 
+                       primitive->get_min_vertex(),
+                       primitive->get_max_vertex(),
+                       primitive->get_num_vertices(),
+                       GL_UNSIGNED_SHORT, client_pointer);
+
+  report_my_gl_errors();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::end_draw_primitives()
 //       Access: Public, Virtual

+ 2 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -98,6 +98,8 @@ public:
                                      const qpGeomVertexData *vertex_data);
   virtual void draw_triangles(const qpGeomTriangles *primitive);
   virtual void draw_tristrips(const qpGeomTristrips *primitive);
+  virtual void draw_lines(const qpGeomLines *primitive);
+  virtual void draw_points(const qpGeomPoints *primitive);
   virtual void end_draw_primitives();
 
   INLINE bool draw_display_list(GeomContext *gc);

+ 9 - 0
panda/src/gobj/Sources.pp

@@ -24,6 +24,9 @@
     qpgeomTriangles.h \
     qpgeomTristrips.h \
     qpgeomTrifans.h \
+    qpgeomLines.h \
+    qpgeomLinestrips.h \
+    qpgeomPoints.h \
     qpgeomUsageHint.h \
     qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
     qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
@@ -62,6 +65,9 @@
     qpgeomTriangles.cxx \
     qpgeomTristrips.cxx \
     qpgeomTrifans.cxx \
+    qpgeomLines.cxx \
+    qpgeomLinestrips.cxx \
+    qpgeomPoints.cxx \
     qpgeomVertexArrayData.cxx \
     qpgeomVertexArrayFormat.cxx \
     qpgeomCacheEntry.cxx \
@@ -96,6 +102,9 @@
     qpgeomTriangles.h \
     qpgeomTristrips.h \
     qpgeomTrifans.h \
+    qpgeomLines.h \
+    qpgeomLinestrips.h \
+    qpgeomPoints.h \
     qpgeomUsageHint.h \
     qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
     qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \

+ 9 - 0
panda/src/gobj/config_gobj.cxx

@@ -28,6 +28,9 @@
 #include "qpgeomTriangles.h"
 #include "qpgeomTristrips.h"
 #include "qpgeomTrifans.h"
+#include "qpgeomLines.h"
+#include "qpgeomLinestrips.h"
+#include "qpgeomPoints.h"
 #include "qpgeomVertexArrayData.h"
 #include "qpgeomVertexArrayFormat.h"
 #include "qpgeomVertexData.h"
@@ -189,6 +192,9 @@ ConfigureFn(config_gobj) {
   qpGeomTriangles::init_type();
   qpGeomTristrips::init_type();
   qpGeomTrifans::init_type();
+  qpGeomLines::init_type();
+  qpGeomLinestrips::init_type();
+  qpGeomPoints::init_type();
   qpGeomVertexArrayData::init_type();
   qpGeomVertexArrayFormat::init_type();
   qpGeomVertexData::init_type();
@@ -223,6 +229,9 @@ ConfigureFn(config_gobj) {
   qpGeomTriangles::register_with_read_factory();
   qpGeomTristrips::register_with_read_factory();
   qpGeomTrifans::register_with_read_factory();
+  qpGeomLines::register_with_read_factory();
+  qpGeomLinestrips::register_with_read_factory();
+  qpGeomPoints::register_with_read_factory();
   qpGeomVertexArrayData::register_with_read_factory();
   qpGeomVertexArrayFormat::register_with_read_factory();
   qpGeomVertexData::register_with_read_factory();

+ 3 - 0
panda/src/gobj/gobj_composite1.cxx

@@ -17,6 +17,9 @@
 #include "qpgeomTriangles.cxx"
 #include "qpgeomTristrips.cxx"
 #include "qpgeomTrifans.cxx"
+#include "qpgeomLines.cxx"
+#include "qpgeomLinestrips.cxx"
+#include "qpgeomPoints.cxx"
 #include "qpgeomVertexArrayData.cxx"
 #include "qpgeomVertexArrayFormat.cxx"
 #include "qpgeomCacheEntry.cxx"

+ 22 - 0
panda/src/gobj/qpgeom.I

@@ -17,6 +17,20 @@
 ////////////////////////////////////////////////////////////////////
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::get_primitive_type
+//       Access: Published
+//  Description: Returns the primitive type that is common to all
+//               GeomPrimitives added within the Geom.  All nested
+//               primitives within a particular Geom must be the same
+//               type.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomPrimitive::PrimitiveType qpGeom::
+get_primitive_type() const {
+  CDReader cdata(_cycler);
+  return cdata->_primitive_type;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeom::get_usage_hint
 //       Access: Published
@@ -104,6 +118,11 @@ set_primitive(int i, const qpGeomPrimitive *primitive) {
   clear_cache();
   CDWriter cdata(_cycler);
   nassertv(i >= 0 && i < (int)cdata->_primitives.size());
+
+  // All primitives within a particular Geom must have the same
+  // primitive type.
+  nassertv(cdata->_primitive_type == qpGeomPrimitive::PT_none ||
+           cdata->_primitive_type == primitive->get_primitive_type());
   if (cdata->_got_usage_hint &&
       cdata->_primitives[i]->get_usage_hint() != primitive->get_usage_hint()) {
     if (cdata->_primitives[i]->get_usage_hint() < primitive->get_usage_hint()) {
@@ -118,6 +137,7 @@ set_primitive(int i, const qpGeomPrimitive *primitive) {
     }
   }
   cdata->_primitives[i] = (qpGeomPrimitive *)primitive;
+  cdata->_primitive_type = primitive->get_primitive_type();
   cdata->_modified = qpGeom::get_next_modified();
 }
 
@@ -169,6 +189,7 @@ operator < (const CacheEntry &other) const {
 ////////////////////////////////////////////////////////////////////
 INLINE qpGeom::CData::
 CData() :
+  _primitive_type(qpGeomPrimitive::PT_none),
   _usage_hint(qpGeomUsageHint::UH_static),
   _got_usage_hint(false)
 {
@@ -183,6 +204,7 @@ INLINE qpGeom::CData::
 CData(const qpGeom::CData &copy) :
   _data(copy._data),
   _primitives(copy._primitives),
+  _primitive_type(copy._primitive_type),
   _usage_hint(copy._usage_hint),
   _got_usage_hint(copy._got_usage_hint),
   _modified(copy._modified)

+ 10 - 0
panda/src/gobj/qpgeom.cxx

@@ -149,7 +149,13 @@ void qpGeom::
 add_primitive(const qpGeomPrimitive *primitive) {
   clear_cache();
   CDWriter cdata(_cycler);
+  // All primitives within a particular Geom must have the same
+  // primitive type.
+  nassertv(cdata->_primitive_type == qpGeomPrimitive::PT_none ||
+           cdata->_primitive_type == primitive->get_primitive_type());
+
   cdata->_primitives.push_back((qpGeomPrimitive *)primitive);
+  cdata->_primitive_type = primitive->get_primitive_type();
 
   if (cdata->_got_usage_hint) {
     cdata->_usage_hint = min(cdata->_usage_hint, primitive->get_usage_hint());
@@ -174,6 +180,9 @@ remove_primitive(int i) {
     cdata->_got_usage_hint = false;
   }
   cdata->_primitives.erase(cdata->_primitives.begin() + i);
+  if (cdata->_primitives.empty()) {
+    cdata->_primitive_type = qpGeomPrimitive::PT_none;
+  }
   cdata->_modified = qpGeom::get_next_modified();
 }
 
@@ -190,6 +199,7 @@ clear_primitives() {
   clear_cache();
   CDWriter cdata(_cycler);
   cdata->_primitives.clear();
+  cdata->_primitive_type = qpGeomPrimitive::PT_none;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 0
panda/src/gobj/qpgeom.h

@@ -66,6 +66,7 @@ PUBLISHED:
   // Temporary.
   virtual Geom *make_copy() const;
 
+  INLINE qpGeomPrimitive::PrimitiveType get_primitive_type() const;
   INLINE qpGeomUsageHint::UsageHint get_usage_hint() const;
 
   INLINE CPT(qpGeomVertexData) get_vertex_data() const;
@@ -137,6 +138,7 @@ private:
 
     PT(qpGeomVertexData) _data;
     Primitives _primitives;
+    qpGeomPrimitive::PrimitiveType _primitive_type;
     qpGeomUsageHint::UsageHint _usage_hint;
     bool _got_usage_hint;
     UpdateSeq _modified;

+ 160 - 0
panda/src/gobj/qpgeomLines.cxx

@@ -0,0 +1,160 @@
+// Filename: qpgeomLines.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 "qpgeomLines.h"
+#include "pStatTimer.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+
+TypeHandle qpGeomLines::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLines::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomLines::
+qpGeomLines(qpGeomUsageHint::UsageHint usage_hint) :
+  qpGeomPrimitive(usage_hint)
+{
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLines::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomLines::
+qpGeomLines(const qpGeomLines &copy) :
+  qpGeomPrimitive(copy)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLines::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomLines::
+~qpGeomLines() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLines::make_copy
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PT(qpGeomPrimitive) qpGeomLines::
+make_copy() const {
+  return new qpGeomLines(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLines::get_primitive_type
+//       Access: Published, Virtual
+//  Description: Returns the fundamental rendering type of this
+//               primitive: whether it is points, lines, or polygons.
+//               This is used primarily to set up the appropriate
+//               antialiasing settings when AntialiasAttrib::M_auto is
+//               in effect.
+////////////////////////////////////////////////////////////////////
+qpGeomPrimitive::PrimitiveType qpGeomLines::
+get_primitive_type() const {
+  return PT_lines;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLines::get_num_vertices_per_primitive
+//       Access: Published, Virtual
+//  Description: If the primitive type is a simple type in which all
+//               primitives have the same number of vertices, like
+//               lines, returns the number of vertices per
+//               primitive.  If the primitive type is a more complex
+//               type in which different primitives might have
+//               different numbers of vertices, for instance a
+//               line strip, returns 0.
+////////////////////////////////////////////////////////////////////
+int qpGeomLines::
+get_num_vertices_per_primitive() const {
+  return 2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLines::draw
+//       Access: Public, Virtual
+//  Description: Calls the appropriate method on the GSG to draw the
+//               primitive.
+////////////////////////////////////////////////////////////////////
+void qpGeomLines::
+draw(GraphicsStateGuardianBase *gsg) const {
+  gsg->draw_lines(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLines::rotate_impl
+//       Access: Protected, Virtual
+//  Description: The virtual implementation of do_rotate().
+////////////////////////////////////////////////////////////////////
+CPTA_ushort qpGeomLines::
+rotate_impl() const {
+  // To rotate lines, we just move reverse the pairs of vertices.
+  CPTA_ushort vertices = get_vertices();
+  ShadeModel shade_model = get_shade_model();
+
+  PTA_ushort new_vertices;
+  new_vertices.reserve(vertices.size());
+
+  for (int begin = 0; begin < (int)vertices.size(); begin += 2) {
+    new_vertices.push_back(vertices[begin + 1]);
+    new_vertices.push_back(vertices[begin]);
+  }
+  
+  nassertr(new_vertices.size() == vertices.size(), vertices);
+  return new_vertices;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLines::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               qpGeom.
+////////////////////////////////////////////////////////////////////
+void qpGeomLines::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLines::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type qpGeom is encountered
+//               in the Bam file.  It should create the qpGeom
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *qpGeomLines::
+make_from_bam(const FactoryParams &params) {
+  qpGeomLines *object = new qpGeomLines(qpGeomUsageHint::UH_client);
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  object->fillin(scan, manager);
+
+  return object;
+}

+ 74 - 0
panda/src/gobj/qpgeomLines.h

@@ -0,0 +1,74 @@
+// Filename: qpgeomLines.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 qpGEOMLINES_H
+#define qpGEOMLINES_H
+
+#include "pandabase.h"
+#include "qpgeomPrimitive.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomLines
+// Description : Defines a series of disconnected line segments.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomLines : public qpGeomPrimitive {
+PUBLISHED:
+  qpGeomLines(qpGeomUsageHint::UsageHint usage_hint);
+  qpGeomLines(const qpGeomLines &copy);
+  virtual ~qpGeomLines();
+
+  virtual PT(qpGeomPrimitive) make_copy() const;
+  virtual PrimitiveType get_primitive_type() const;
+
+  virtual int get_num_vertices_per_primitive() const;
+
+public:
+  virtual void draw(GraphicsStateGuardianBase *gsg) const;
+
+protected:
+  virtual CPTA_ushort rotate_impl() const;
+
+public:
+  static void register_with_read_factory();
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    qpGeomPrimitive::init_type();
+    register_type(_type_handle, "qpGeomLines",
+                  qpGeomPrimitive::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;
+
+  friend class qpGeom;
+};
+
+#endif

+ 196 - 0
panda/src/gobj/qpgeomLinestrips.cxx

@@ -0,0 +1,196 @@
+// Filename: qpgeomLinestrips.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 "qpgeomLinestrips.h"
+#include "qpgeomLines.h"
+#include "pStatTimer.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+
+TypeHandle qpGeomLinestrips::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLinestrips::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomLinestrips::
+qpGeomLinestrips(qpGeomUsageHint::UsageHint usage_hint) :
+  qpGeomPrimitive(usage_hint)
+{
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLinestrips::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomLinestrips::
+qpGeomLinestrips(const qpGeomLinestrips &copy) :
+  qpGeomPrimitive(copy)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLinestrips::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomLinestrips::
+~qpGeomLinestrips() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLinestrips::make_copy
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PT(qpGeomPrimitive) qpGeomLinestrips::
+make_copy() const {
+  return new qpGeomLinestrips(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLinestrips::get_primitive_type
+//       Access: Published, Virtual
+//  Description: Returns the fundamental rendering type of this
+//               primitive: whether it is points, lines, or polygons.
+//               This is used primarily to set up the appropriate
+//               antialiasing settings when AntialiasAttrib::M_auto is
+//               in effect.
+////////////////////////////////////////////////////////////////////
+qpGeomPrimitive::PrimitiveType qpGeomLinestrips::
+get_primitive_type() const {
+  return PT_lines;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLinestrips::draw
+//       Access: Public, Virtual
+//  Description: Calls the appropriate method on the GSG to draw the
+//               primitive.
+////////////////////////////////////////////////////////////////////
+void qpGeomLinestrips::
+draw(GraphicsStateGuardianBase *gsg) const {
+  gsg->draw_linestrips(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLinestrips::decompose_impl
+//       Access: Protected, Virtual
+//  Description: Decomposes a complex primitive type into a simpler
+//               primitive type, for instance line strips to
+//               lines, and returns a pointer to the new primitive
+//               definition.  If the decomposition cannot be
+//               performed, this might return the original object.
+//
+//               This method is useful for application code that wants
+//               to iterate through the set of lines on the
+//               primitive without having to write handlers for each
+//               possible kind of primitive type.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomPrimitive) qpGeomLinestrips::
+decompose_impl() const {
+  PT(qpGeomLines) lines = new qpGeomLines(get_usage_hint());
+  lines->set_shade_model(get_shade_model());
+  CPTA_ushort vertices = get_vertices();
+  CPTA_int ends = get_ends();
+
+  int vi = 0;
+  int li = 0;
+  while (li < (int)ends.size()) {
+    int end = ends[li];
+    nassertr(vi + 1 <= end, lines.p());
+    nassertr(vi < (int)vertices.size(), this);
+    int v0 = vertices[vi];
+    ++vi;
+    while (vi < end) {
+      lines->add_vertex(v0);
+      lines->add_vertex(vertices[vi]);
+      nassertr(vi < (int)vertices.size(), this);
+      v0 = vertices[vi];
+      lines->close_primitive();
+      ++vi;
+    }
+    ++li;
+  }
+  nassertr(vi == (int)vertices.size(), lines.p());
+
+  return lines.p();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLinestrips::rotate_impl
+//       Access: Protected, Virtual
+//  Description: The virtual implementation of do_rotate().
+////////////////////////////////////////////////////////////////////
+CPTA_ushort qpGeomLinestrips::
+rotate_impl() const {
+  // To rotate a line strip, we just reverse the vertices.
+  CPTA_ushort vertices = get_vertices();
+  CPTA_int ends = get_ends();
+  PTA_ushort new_vertices;
+  new_vertices.reserve(vertices.size());
+
+  int begin = 0;
+  CPTA_int::const_iterator ei;
+  for (ei = ends.begin(); ei != ends.end(); ++ei) {
+    int end = (*ei);
+    int num_vertices = end - begin;
+
+    for (int vi = end - 1; vi >= begin; --vi) {
+      new_vertices.push_back(vertices[vi]);
+    }
+
+    begin = end;
+  }
+  nassertr(new_vertices.size() == vertices.size(), vertices);
+
+  return new_vertices;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLinestrips::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               qpGeom.
+////////////////////////////////////////////////////////////////////
+void qpGeomLinestrips::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLinestrips::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type qpGeom is encountered
+//               in the Bam file.  It should create the qpGeom
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *qpGeomLinestrips::
+make_from_bam(const FactoryParams &params) {
+  qpGeomLinestrips *object = new qpGeomLinestrips(qpGeomUsageHint::UH_client);
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  object->fillin(scan, manager);
+
+  return object;
+}

+ 73 - 0
panda/src/gobj/qpgeomLinestrips.h

@@ -0,0 +1,73 @@
+// Filename: qpgeomLinestrips.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 qpGEOMLINESTRIPS_H
+#define qpGEOMLINESTRIPS_H
+
+#include "pandabase.h"
+#include "qpgeomPrimitive.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomLinestrips
+// Description : Defines a series of line strips.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomLinestrips : public qpGeomPrimitive {
+PUBLISHED:
+  qpGeomLinestrips(qpGeomUsageHint::UsageHint usage_hint);
+  qpGeomLinestrips(const qpGeomLinestrips &copy);
+  virtual ~qpGeomLinestrips();
+
+  virtual PT(qpGeomPrimitive) make_copy() const;
+  virtual PrimitiveType get_primitive_type() const;
+
+public:
+  virtual void draw(GraphicsStateGuardianBase *gsg) const;
+
+protected:
+  virtual CPT(qpGeomPrimitive) decompose_impl() const;
+  virtual CPTA_ushort rotate_impl() const;
+
+public:
+  static void register_with_read_factory();
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    qpGeomPrimitive::init_type();
+    register_type(_type_handle, "qpGeomLinestrips",
+                  qpGeomPrimitive::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;
+
+  friend class qpGeom;
+};
+
+#endif

+ 137 - 0
panda/src/gobj/qpgeomPoints.cxx

@@ -0,0 +1,137 @@
+// Filename: qpgeomPoints.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 "qpgeomPoints.h"
+#include "pStatTimer.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+
+TypeHandle qpGeomPoints::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPoints::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomPoints::
+qpGeomPoints(qpGeomUsageHint::UsageHint usage_hint) :
+  qpGeomPrimitive(usage_hint)
+{
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPoints::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomPoints::
+qpGeomPoints(const qpGeomPoints &copy) :
+  qpGeomPrimitive(copy)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPoints::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomPoints::
+~qpGeomPoints() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPoints::make_copy
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PT(qpGeomPrimitive) qpGeomPoints::
+make_copy() const {
+  return new qpGeomPoints(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPoints::get_primitive_type
+//       Access: Published, Virtual
+//  Description: Returns the fundamental rendering type of this
+//               primitive: whether it is points, lines, or polygons.
+//               This is used primarily to set up the appropriate
+//               antialiasing settings when AntialiasAttrib::M_auto is
+//               in effect.
+////////////////////////////////////////////////////////////////////
+qpGeomPrimitive::PrimitiveType qpGeomPoints::
+get_primitive_type() const {
+  return PT_points;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPoints::get_num_vertices_per_primitive
+//       Access: Published, Virtual
+//  Description: If the primitive type is a simple type in which all
+//               primitives have the same number of vertices, like
+//               points, returns the number of vertices per
+//               primitive.  If the primitive type is a more complex
+//               type in which different primitives might have
+//               different numbers of vertices, for instance a
+//               point strip, returns 0.
+////////////////////////////////////////////////////////////////////
+int qpGeomPoints::
+get_num_vertices_per_primitive() const {
+  return 1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPoints::draw
+//       Access: Public, Virtual
+//  Description: Calls the appropriate method on the GSG to draw the
+//               primitive.
+////////////////////////////////////////////////////////////////////
+void qpGeomPoints::
+draw(GraphicsStateGuardianBase *gsg) const {
+  gsg->draw_points(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPoints::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               qpGeom.
+////////////////////////////////////////////////////////////////////
+void qpGeomPoints::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPoints::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type qpGeom is encountered
+//               in the Bam file.  It should create the qpGeom
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *qpGeomPoints::
+make_from_bam(const FactoryParams &params) {
+  qpGeomPoints *object = new qpGeomPoints(qpGeomUsageHint::UH_client);
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  object->fillin(scan, manager);
+
+  return object;
+}

+ 71 - 0
panda/src/gobj/qpgeomPoints.h

@@ -0,0 +1,71 @@
+// Filename: qpgeomPoints.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 qpGEOMPOINTS_H
+#define qpGEOMPOINTS_H
+
+#include "pandabase.h"
+#include "qpgeomPrimitive.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomPoints
+// Description : Defines a series of disconnected points.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomPoints : public qpGeomPrimitive {
+PUBLISHED:
+  qpGeomPoints(qpGeomUsageHint::UsageHint usage_hint);
+  qpGeomPoints(const qpGeomPoints &copy);
+  virtual ~qpGeomPoints();
+
+  virtual PT(qpGeomPrimitive) make_copy() const;
+  virtual PrimitiveType get_primitive_type() const;
+
+  virtual int get_num_vertices_per_primitive() const;
+
+public:
+  virtual void draw(GraphicsStateGuardianBase *gsg) const;
+
+public:
+  static void register_with_read_factory();
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    qpGeomPrimitive::init_type();
+    register_type(_type_handle, "qpGeomPoints",
+                  qpGeomPrimitive::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;
+
+  friend class qpGeom;
+};
+
+#endif

+ 8 - 0
panda/src/gobj/qpgeomPrimitive.h

@@ -92,6 +92,14 @@ PUBLISHED:
     SM_flat_last_vertex,
   };
 
+  enum PrimitiveType {
+    PT_none,
+    PT_polygons,
+    PT_lines,
+    PT_points
+  };
+
+  virtual PrimitiveType get_primitive_type() const=0;
   INLINE qpGeomUsageHint::UsageHint get_usage_hint() const;
 
   INLINE ShadeModel get_shade_model() const;

+ 14 - 0
panda/src/gobj/qpgeomTriangles.cxx

@@ -64,6 +64,20 @@ make_copy() const {
   return new qpGeomTriangles(*this);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTriangles::get_primitive_type
+//       Access: Published, Virtual
+//  Description: Returns the fundamental rendering type of this
+//               primitive: whether it is points, lines, or polygons.
+//               This is used primarily to set up the appropriate
+//               antialiasing settings when AntialiasAttrib::M_auto is
+//               in effect.
+////////////////////////////////////////////////////////////////////
+qpGeomPrimitive::PrimitiveType qpGeomTriangles::
+get_primitive_type() const {
+  return PT_polygons;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomTriangles::get_num_vertices_per_primitive
 //       Access: Published, Virtual

+ 1 - 0
panda/src/gobj/qpgeomTriangles.h

@@ -35,6 +35,7 @@ PUBLISHED:
   virtual ~qpGeomTriangles();
 
   virtual PT(qpGeomPrimitive) make_copy() const;
+  virtual PrimitiveType get_primitive_type() const;
 
   virtual int get_num_vertices_per_primitive() const;
 

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

@@ -64,6 +64,20 @@ make_copy() const {
   return new qpGeomTrifans(*this);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTrifans::get_primitive_type
+//       Access: Published, Virtual
+//  Description: Returns the fundamental rendering type of this
+//               primitive: whether it is points, lines, or polygons.
+//               This is used primarily to set up the appropriate
+//               antialiasing settings when AntialiasAttrib::M_auto is
+//               in effect.
+////////////////////////////////////////////////////////////////////
+qpGeomPrimitive::PrimitiveType qpGeomTrifans::
+get_primitive_type() const {
+  return PT_polygons;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomTrifans::draw
 //       Access: Public, Virtual

+ 1 - 0
panda/src/gobj/qpgeomTrifans.h

@@ -35,6 +35,7 @@ PUBLISHED:
   virtual ~qpGeomTrifans();
 
   virtual PT(qpGeomPrimitive) make_copy() const;
+  virtual PrimitiveType get_primitive_type() const;
 
 public:
   virtual void draw(GraphicsStateGuardianBase *gsg) const;

+ 15 - 1
panda/src/gobj/qpgeomTristrips.cxx

@@ -65,6 +65,20 @@ make_copy() const {
   return new qpGeomTristrips(*this);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTristrips::get_primitive_type
+//       Access: Published, Virtual
+//  Description: Returns the fundamental rendering type of this
+//               primitive: whether it is points, lines, or polygons.
+//               This is used primarily to set up the appropriate
+//               antialiasing settings when AntialiasAttrib::M_auto is
+//               in effect.
+////////////////////////////////////////////////////////////////////
+qpGeomPrimitive::PrimitiveType qpGeomTristrips::
+get_primitive_type() const {
+  return PT_polygons;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomTristrips::draw
 //       Access: Public, Virtual
@@ -99,7 +113,7 @@ decompose_impl() const {
 
   // We need a slightly different algorithm for SM_flat_first_vertex
   // than for SM_flat_last_vertex, to preserve the key vertex in the
-  // right place.  The remaining shade models can either either
+  // right place.  The remaining shade models can use either
   // algorithm.
   if (get_shade_model() == SM_flat_first_vertex) {
     // Preserve the first vertex of each component triangle as the

+ 1 - 0
panda/src/gobj/qpgeomTristrips.h

@@ -35,6 +35,7 @@ PUBLISHED:
   virtual ~qpGeomTristrips();
 
   virtual PT(qpGeomPrimitive) make_copy() const;
+  virtual PrimitiveType get_primitive_type() const;
 
 public:
   virtual void draw(GraphicsStateGuardianBase *gsg) const;

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

@@ -52,6 +52,9 @@ class qpGeomPrimitive;
 class qpGeomTriangles;
 class qpGeomTristrips;
 class qpGeomTrifans;
+class qpGeomLines;
+class qpGeomLinestrips;
+class qpGeomPoints;
 class qpGeomMunger;
 
 class PreparedGraphicsObjects;
@@ -190,6 +193,9 @@ public:
   virtual void draw_triangles(const qpGeomTriangles *primitive)=0;
   virtual void draw_tristrips(const qpGeomTristrips *primitive)=0;
   virtual void draw_trifans(const qpGeomTrifans *primitive)=0;
+  virtual void draw_lines(const qpGeomLines *primitive)=0;
+  virtual void draw_linestrips(const qpGeomLinestrips *primitive)=0;
+  virtual void draw_points(const qpGeomPoints *primitive)=0;
   virtual void end_draw_primitives()=0;
 
   virtual void framebuffer_copy_to_texture