Browse Source

qpgeom particles

David Rose 21 years ago
parent
commit
8dd9c1419c
31 changed files with 1211 additions and 287 deletions
  1. 9 0
      panda/src/display/graphicsStateGuardian.cxx
  2. 1 0
      panda/src/display/graphicsStateGuardian.h
  3. 11 0
      panda/src/glstuff/glGraphicsStateGuardian_src.I
  4. 266 14
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  5. 25 3
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  6. 3 0
      panda/src/gobj/Sources.pp
  7. 3 0
      panda/src/gobj/config_gobj.cxx
  8. 1 0
      panda/src/gobj/gobj_composite1.cxx
  9. 39 0
      panda/src/gobj/internalName.I
  10. 3 0
      panda/src/gobj/internalName.cxx
  11. 6 0
      panda/src/gobj/internalName.h
  12. 5 1
      panda/src/gobj/qpgeomPrimitive.cxx
  13. 148 0
      panda/src/gobj/qpgeomSprites.cxx
  14. 90 0
      panda/src/gobj/qpgeomSprites.h
  15. 8 2
      panda/src/gobj/qpgeomVertexWriter.I
  16. 6 2
      panda/src/gobj/qpgeomVertexWriter.cxx
  17. 2 0
      panda/src/gsgbase/graphicsStateGuardianBase.h
  18. 2 2
      panda/src/particlesystem/baseParticleRenderer.h
  19. 62 32
      panda/src/particlesystem/lineParticleRenderer.cxx
  20. 5 2
      panda/src/particlesystem/lineParticleRenderer.h
  21. 58 32
      panda/src/particlesystem/pointParticleRenderer.cxx
  22. 5 2
      panda/src/particlesystem/pointParticleRenderer.h
  23. 113 52
      panda/src/particlesystem/sparkleParticleRenderer.cxx
  24. 5 2
      panda/src/particlesystem/sparkleParticleRenderer.h
  25. 32 33
      panda/src/particlesystem/spriteParticleRenderer.I
  26. 227 88
      panda/src/particlesystem/spriteParticleRenderer.cxx
  27. 19 8
      panda/src/particlesystem/spriteParticleRenderer.h
  28. 25 4
      panda/src/pgraph/renderModeAttrib.I
  29. 25 5
      panda/src/pgraph/renderModeAttrib.cxx
  30. 5 2
      panda/src/pgraph/renderModeAttrib.h
  31. 2 1
      panda/src/putil/bam.h

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

@@ -748,6 +748,15 @@ void GraphicsStateGuardian::
 draw_points(const qpGeomPoints *) {
 draw_points(const qpGeomPoints *) {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::draw_sprites
+//       Access: Public, Virtual
+//  Description: Draws a series of rectangular sprite polygons.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+draw_sprites(const qpGeomSprites *) {
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::end_draw_primitives()
 //     Function: GraphicsStateGuardian::end_draw_primitives()
 //       Access: Public, Virtual
 //       Access: Public, Virtual

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

@@ -160,6 +160,7 @@ public:
   virtual void draw_lines(const qpGeomLines *primitive);
   virtual void draw_lines(const qpGeomLines *primitive);
   virtual void draw_linestrips(const qpGeomLinestrips *primitive);
   virtual void draw_linestrips(const qpGeomLinestrips *primitive);
   virtual void draw_points(const qpGeomPoints *primitive);
   virtual void draw_points(const qpGeomPoints *primitive);
+  virtual void draw_sprites(const qpGeomSprites *primitive);
   virtual void end_draw_primitives();
   virtual void end_draw_primitives();
 
 
   virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex);
   virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex);

+ 11 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.I

@@ -526,3 +526,14 @@ issue_flat_shading(Geom *geom) {
     // Otherwise, it's a uniform-colored primitive; we can take either one.
     // Otherwise, it's a uniform-colored primitive; we can take either one.
   }
   }
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::SpriteData::Ordering
+//       Access: Public
+//  Description: Orders the sprites from back-to-front for correct
+//               transparency sorting in draw_sprites().
+////////////////////////////////////////////////////////////////////
+INLINE bool CLP(GraphicsStateGuardian)::SpriteData::
+operator < (const SpriteData &other) const {
+  return _eye[2] < other._eye[2];
+}

+ 266 - 14
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -28,6 +28,8 @@
 #include "qpgeomLines.h"
 #include "qpgeomLines.h"
 #include "qpgeomLinestrips.h"
 #include "qpgeomLinestrips.h"
 #include "qpgeomPoints.h"
 #include "qpgeomPoints.h"
+#include "qpgeomSprites.h"
+#include "qpgeomVertexReader.h"
 #include "graphicsWindow.h"
 #include "graphicsWindow.h"
 #include "lens.h"
 #include "lens.h"
 #include "perspectiveLens.h"
 #include "perspectiveLens.h"
@@ -62,6 +64,7 @@
 #include "pnmImage.h"
 #include "pnmImage.h"
 #include "config_gobj.h"
 #include "config_gobj.h"
 #include "mutexHolder.h"
 #include "mutexHolder.h"
+#include "indirectLess.h"
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS
 #include "pStatTimer.h"
 #include "pStatTimer.h"
 #endif
 #endif
@@ -138,6 +141,10 @@ issue_scaled_color_gl(const Geom *geom, Geom::ColorIterator &citerator,
 // defined by the GL, just so it will always be safe to call the
 // defined by the GL, just so it will always be safe to call the
 // extension functions.
 // extension functions.
 
 
+static void APIENTRY
+null_glPointParameterfv(GLenum, const GLfloat *) {
+}
+
 static void APIENTRY
 static void APIENTRY
 null_glDrawRangeElements(GLenum mode, GLuint start, GLuint end, 
 null_glDrawRangeElements(GLenum mode, GLuint start, GLuint end, 
                          GLsizei count, GLenum type, const GLvoid *indices) {
                          GLsizei count, GLenum type, const GLvoid *indices) {
@@ -364,6 +371,31 @@ reset() {
   get_extra_extensions();
   get_extra_extensions();
   report_extensions();
   report_extensions();
 
 
+  _supports_point_parameters = false;
+
+  if (is_at_least_version(1, 4)) {
+    _supports_point_parameters = true;
+    _glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)
+      get_extension_func(GLPREFIX_QUOTED, "PointParameterfv");
+
+  } else if (has_extension("GL_ARB_point_parameters")) {
+    _supports_point_parameters = true;
+    _glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)
+      get_extension_func(GLPREFIX_QUOTED, "PointParameterfvARB");
+  }
+  if (_supports_point_parameters) {
+    if (_glPointParameterfv == NULL) {
+      GLCAT.warning()
+        << "glPointParameterfv advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
+      _supports_point_parameters = false;
+    }
+  }
+  if (!_supports_point_parameters) {
+    _glPointParameterfv = null_glPointParameterfv;
+  }
+
+  _supports_point_sprite = false;
+
   _supports_vertex_blend = has_extension("GL_ARB_vertex_blend");
   _supports_vertex_blend = has_extension("GL_ARB_vertex_blend");
 
 
   if (_supports_vertex_blend) {
   if (_supports_vertex_blend) {
@@ -764,8 +796,7 @@ reset() {
       << "max clip planes = " << _max_clip_planes << "\n";
       << "max clip planes = " << _max_clip_planes << "\n";
   }
   }
 
 
-  _current_projection_mat = LMatrix4f::ident_mat();
-  _projection_mat_stack_count = 0;
+  _projection_mat = LMatrix4f::ident_mat();
 
 
   if (_supports_multitexture) {
   if (_supports_multitexture) {
     GLint max_texture_stages;
     GLint max_texture_stages;
@@ -786,6 +817,8 @@ reset() {
   _last_max_stage_index = 0;
   _last_max_stage_index = 0;
   _auto_antialias_mode = false;
   _auto_antialias_mode = false;
   _render_mode = RenderModeAttrib::M_filled;
   _render_mode = RenderModeAttrib::M_filled;
+  _point_size = 1.0f;
+  _point_perspective = false;
 
 
   _transform_stale = false;
   _transform_stale = false;
   _vertex_blending_enabled = false;
   _vertex_blending_enabled = false;
@@ -915,6 +948,8 @@ prepare_display_region() {
     GLCAT.error()
     GLCAT.error()
       << "Invalid NULL display region in prepare_display_region()\n";
       << "Invalid NULL display region in prepare_display_region()\n";
     enable_scissor(false);
     enable_scissor(false);
+    _viewport_width = 1;
+    _viewport_height = 1;
 
 
   } else if (_current_display_region != _actual_display_region) {
   } else if (_current_display_region != _actual_display_region) {
     _actual_display_region = _current_display_region;
     _actual_display_region = _current_display_region;
@@ -926,11 +961,15 @@ prepare_display_region() {
     GLsizei width = GLsizei(w);
     GLsizei width = GLsizei(w);
     GLsizei height = GLsizei(h);
     GLsizei height = GLsizei(h);
 
 
-    enable_scissor( true );
-    GLP(Scissor)( x, y, width, height );
-    GLP(Viewport)( x, y, width, height );
+    enable_scissor(true);
+    GLP(Scissor)(x, y, width, height);
+    GLP(Viewport)(x, y, width, height);
+    _viewport_width = width;
+    _viewport_height = height;
   }
   }
   report_my_gl_errors();
   report_my_gl_errors();
+
+  do_point_size();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -955,7 +994,7 @@ prepare_lens() {
     return false;
     return false;
   }
   }
 
 
-  const LMatrix4f &projection_mat = _current_lens->get_projection_mat();
+  const LMatrix4f &lens_mat = _current_lens->get_projection_mat();
 
 
   // The projection matrix must always be right-handed Y-up, even if
   // The projection matrix must always be right-handed Y-up, even if
   // our coordinate system of choice is otherwise, because certain GL
   // our coordinate system of choice is otherwise, because certain GL
@@ -964,25 +1003,27 @@ prepare_lens() {
   // other arbitrary) coordinate system, we'll use a Y-up projection
   // other arbitrary) coordinate system, we'll use a Y-up projection
   // matrix, and store the conversion to our coordinate system of
   // matrix, and store the conversion to our coordinate system of
   // choice in the modelview matrix.
   // choice in the modelview matrix.
-  LMatrix4f new_projection_mat =
+  _projection_mat =
     LMatrix4f::convert_mat(CS_yup_right, _current_lens->get_coordinate_system()) *
     LMatrix4f::convert_mat(CS_yup_right, _current_lens->get_coordinate_system()) *
-    projection_mat;
+    lens_mat;
 
 
   if (_scene_setup->get_inverted()) {
   if (_scene_setup->get_inverted()) {
     // If the scene is supposed to be inverted, then invert the
     // If the scene is supposed to be inverted, then invert the
     // projection matrix.
     // projection matrix.
     static LMatrix4f invert_mat = LMatrix4f::scale_mat(1.0f, -1.0f, 1.0f);
     static LMatrix4f invert_mat = LMatrix4f::scale_mat(1.0f, -1.0f, 1.0f);
-    new_projection_mat *= invert_mat;
+    _projection_mat *= invert_mat;
   }
   }
 
 
 #ifdef GSG_VERBOSE
 #ifdef GSG_VERBOSE
   GLCAT.spam()
   GLCAT.spam()
-    << "glMatrixMode(GL_PROJECTION): " << new_projection_mat << endl;
+    << "glMatrixMode(GL_PROJECTION): " << _projection_mat << endl;
 #endif
 #endif
   GLP(MatrixMode)(GL_PROJECTION);
   GLP(MatrixMode)(GL_PROJECTION);
-  GLP(LoadMatrixf)(new_projection_mat.get_data());
+  GLP(LoadMatrixf)(_projection_mat.get_data());
   report_my_gl_errors();
   report_my_gl_errors();
 
 
+  do_point_size();
+
   return true;
   return true;
 }
 }
 
 
@@ -2513,6 +2554,169 @@ draw_points(const qpGeomPoints *primitive) {
   report_my_gl_errors();
   report_my_gl_errors();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::draw_sprites
+//       Access: Public, Virtual
+//  Description: Draws a series of rectangular sprite polygons.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+draw_sprites(const qpGeomSprites *primitive) {
+  bool has_rotate = _vertex_data->has_column(InternalName::get_rotate());
+  bool has_scale_x = _vertex_data->has_column(InternalName::get_scale_x());
+  bool has_scale_y = _vertex_data->has_column(InternalName::get_scale_y());
+  if (!_supports_point_sprite || 
+      has_rotate || has_scale_x || has_scale_y) {
+    // In this case, we have to draw the sprites as a series of
+    // polygons, because either the GL doesn't support the
+    // point_sprite extension, or the vertex data requires some
+    // nonstandard adjustments not covered by point_sprite.
+
+    // This is kind of a shame because we have already prepared the
+    // vertex buffer, and it turns out we're not going to use it.  Oh
+    // well, too bad.
+
+    // Now clear the projection and modelview matrices, since we'll do
+    // the transformation to camera space ourselves.
+    GLP(MatrixMode)(GL_PROJECTION);
+    GLP(PushMatrix)();
+    GLP(LoadIdentity)();
+    GLP(MatrixMode)(GL_MODELVIEW);
+    GLP(PushMatrix)();
+    GLP(LoadIdentity)();
+
+    bool has_color = _vertex_data->has_column(InternalName::get_color());
+
+    // First, get all of the points in eye space.
+    const LMatrix4f &modelview = _transform->get_mat();
+    qpGeomVertexReader vertex(_vertex_data, InternalName::get_vertex());
+    qpGeomVertexReader color(_vertex_data, InternalName::get_color());
+    qpGeomVertexReader rotate(_vertex_data, InternalName::get_rotate());
+    qpGeomVertexReader scale_x(_vertex_data, InternalName::get_scale_x());
+    qpGeomVertexReader scale_y(_vertex_data, InternalName::get_scale_y());
+
+    int num_sprites = primitive->get_num_vertices();
+    SpriteData *sprites = (SpriteData *)alloca(num_sprites * sizeof(SpriteData));
+    SpriteData **sprite_pointers = (SpriteData **)alloca(num_sprites * sizeof(SpriteData *));
+
+    SpriteData *sd = sprites;
+    SpriteData *sd_end = sprites + num_sprites;
+    SpriteData **sdp = sprite_pointers;
+    SpriteData **sdp_end = sprite_pointers + num_sprites;
+
+    for (int i = 0; i < num_sprites; ++i) {
+      int vi = primitive->get_vertex(i);
+
+      nassertv(sd < sd_end && sdp < sdp_end);
+      if (has_color) {
+        color.set_vertex(vi);
+        sd->_color = color.get_data4f();
+      }
+      if (has_rotate) {
+        rotate.set_vertex(vi);
+        sd->_rotate = rotate.get_data1f();
+      }
+      if (has_scale_x) {
+        scale_x.set_vertex(vi);
+        sd->_scale_x = scale_x.get_data1f();
+      } else {
+        sd->_scale_x = 1.0f;
+      }
+      if (has_scale_y) {
+        scale_y.set_vertex(vi);
+        sd->_scale_y = scale_y.get_data1f();
+      } else {
+        sd->_scale_y = 1.0f;
+      }
+
+      // The point in eye-space coordinates.
+      vertex.set_vertex(vi);
+      sd->_eye = modelview.xform_point(vertex.get_data3f());
+      (*sdp) = sd;
+      ++sd;
+      ++sdp;
+    }
+
+    // Now sort the sprites in order from back-to-front so they will
+    // render properly with transparency, at least with each other.
+    ::sort(sprite_pointers, sprite_pointers + num_sprites,
+           IndirectLess<SpriteData>());
+
+    // Point radius, converted from pixels into camera space.
+    float rx = _gl_point_size / _viewport_width;
+    float ry = _gl_point_size / _viewport_height;
+
+    // Go through the sprites, now in sorted order, and render a quad
+    // for each one.
+    GLP(Begin)(GL_QUADS);
+    for (sdp = sprite_pointers; sdp < sdp_end; ++sdp) {
+      sd = (*sdp);
+      if (has_color) {
+        GLP(Color4fv)(sd->_color.get_data());
+      }
+      // The point in eye-space coordinates.
+      const LPoint3f &eye = sd->_eye;
+
+      // The point in camera-space coordinates.
+      LPoint4f p4 = LPoint4f(eye[0], eye[1], eye[2], 1.0f) * _projection_mat;
+      LPoint3f c(p4[0] / p4[3], p4[1] / p4[3], p4[2] / p4[3]);
+
+      // Define the first two corners based on the scales in X and Y.
+      LPoint2f c0(sd->_scale_x, sd->_scale_y);
+      LPoint2f c1(-sd->_scale_x, sd->_scale_y);
+
+      if (has_rotate) {
+        // If we have a rotate factor, apply it to those two corners.
+        LMatrix3f mat = LMatrix3f::rotate_mat(sd->_rotate);
+        c0 = c0 * mat;
+        c1 = c1 * mat;
+      }
+
+      // Now scale the corners to compensate for the aspect ratio of
+      // the viewport (as well as applying the current
+      // RenderModeAttrib's thickness, i.e. point size).
+      c0.set(c0[0] * rx, c0[1] * ry);
+      c1.set(c1[0] * rx, c1[1] * ry);
+
+      if (_point_perspective) {
+        // If _point_perspective is in effect, we should divide the
+        // radius by the distance from the camera plane (which is
+        // -eye[2]), to emulate the glPointParameters() behavior.
+        float scale = (-1.0f / eye[2]);
+        c0 *= scale;
+        c1 *= scale;
+      }
+
+      GLP(TexCoord2f)(1.0f, 0.0f);
+      GLP(Vertex3f)(c[0] + c0[0], c[1] + c0[1], c[2]);
+      GLP(TexCoord2f)(0.0f, 0.0f);
+      GLP(Vertex3f)(c[0] + c1[0], c[1] + c1[1], c[2]);
+      GLP(TexCoord2f)(0.0f, 1.0f);
+      GLP(Vertex3f)(c[0] - c0[0], c[1] - c0[1], c[2]);
+      GLP(TexCoord2f)(1.0f, 1.0f);
+      GLP(Vertex3f)(c[0] - c1[0], c[1] - c1[1], c[2]);
+    }
+    GLP(End)();
+
+    GLP(MatrixMode)(GL_PROJECTION);
+    GLP(PopMatrix)();
+    GLP(MatrixMode)(GL_MODELVIEW);
+    GLP(PopMatrix)();
+
+  } else {
+    // In this case, the sprites are simple squares, so we can take
+    // advantage of the point_sprite extension to draw them quickly.
+    _vertices_other_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()
 //     Function: CLP(GraphicsStateGuardian)::end_draw_primitives()
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -3421,6 +3625,8 @@ issue_material(const MaterialAttrib *attrib) {
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 issue_render_mode(const RenderModeAttrib *attrib) {
 issue_render_mode(const RenderModeAttrib *attrib) {
   _render_mode = attrib->get_mode();
   _render_mode = attrib->get_mode();
+  _point_size = attrib->get_thickness();
+  _point_perspective = attrib->get_perspective();
 
 
   switch (_render_mode) {
   switch (_render_mode) {
   case RenderModeAttrib::M_unchanged:
   case RenderModeAttrib::M_unchanged:
@@ -3442,10 +3648,10 @@ issue_render_mode(const RenderModeAttrib *attrib) {
   }
   }
 
 
   // The thickness affects both the line width and the point size.
   // The thickness affects both the line width and the point size.
-  GLP(LineWidth)(attrib->get_thickness());
-  GLP(PointSize)(attrib->get_thickness());
-
+  GLP(LineWidth)(_point_size);
   report_my_gl_errors();
   report_my_gl_errors();
+
+  do_point_size();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -6058,6 +6264,52 @@ do_issue_texture() {
   report_my_gl_errors();
   report_my_gl_errors();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::do_point_size
+//       Access: Protected
+//  Description: Internally sets the point size parameters after any
+//               of the properties have changed that might affect
+//               this.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+do_point_size() {
+  if (!_point_perspective) {
+    // Normal, constant-sized points.  Here _point_size is a width in
+    // pixels.
+    GLP(PointSize)(_point_size);
+    _gl_point_size = _point_size;
+    static LVecBase3f constant(1.0f, 0.0f, 0.0f);
+    _glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, constant.get_data());
+
+  } else {
+    // Perspective-sized points.  Here _point_size is a width in 3-d
+    // units.  To arrange that, we need to figure out the appropriate
+    // scaling factor based on the current viewport and projection
+    // matrix.
+    LVector3f width(_point_size, 0.0f, 1.0f);
+    width = width * _projection_mat;
+    _gl_point_size = width[0] * _viewport_width;
+
+    if (!_supports_point_parameters) {
+      // Actually, this OpenGL driver doesn't support the
+      // glPointParameter() extension.  That means we can't get
+      // perspective correct points anyway.  Maybe we should render
+      // them as sprites?  As a stopgap, we'll just ask for 1-pixel
+      // points.
+      GLP(PointSize)(1.0f);
+
+    } else {
+      // This driver does support the extension, so get the
+      // appropriate width.
+      GLP(PointSize)(width[0] * _viewport_width);
+      static LVecBase3f square(0.0f, 0.0f, 1.0f);
+      _glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, square.get_data());
+    }
+  }
+
+  report_my_gl_errors();
+}
+
 #ifndef NDEBUG
 #ifndef NDEBUG
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::build_phony_mipmaps
 //     Function: CLP(GraphicsStateGuardian)::build_phony_mipmaps

+ 25 - 3
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -51,6 +51,7 @@ class Light;
 // system GL version matches or exceeds the GL version in which these
 // system GL version matches or exceeds the GL version in which these
 // functions are defined, and the system gl.h sometimes doesn't
 // functions are defined, and the system gl.h sometimes doesn't
 // declare these typedefs.
 // declare these typedefs.
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);
 typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
 typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
 typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
 typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
 typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
 typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
@@ -100,6 +101,7 @@ public:
   virtual void draw_tristrips(const qpGeomTristrips *primitive);
   virtual void draw_tristrips(const qpGeomTristrips *primitive);
   virtual void draw_lines(const qpGeomLines *primitive);
   virtual void draw_lines(const qpGeomLines *primitive);
   virtual void draw_points(const qpGeomPoints *primitive);
   virtual void draw_points(const qpGeomPoints *primitive);
+  virtual void draw_sprites(const qpGeomSprites *primitive);
   virtual void end_draw_primitives();
   virtual void end_draw_primitives();
 
 
   INLINE bool draw_display_list(GeomContext *gc);
   INLINE bool draw_display_list(GeomContext *gc);
@@ -263,6 +265,7 @@ protected:
 
 
   void do_auto_rescale_normal();
   void do_auto_rescale_normal();
   void do_issue_texture();
   void do_issue_texture();
+  void do_point_size();
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
   void build_phony_mipmaps(Texture *tex);
   void build_phony_mipmaps(Texture *tex);
@@ -302,9 +305,9 @@ protected:
   int _max_lights;
   int _max_lights;
   int _max_clip_planes;
   int _max_clip_planes;
 
 
-  LMatrix4f _current_projection_mat;
-  int _projection_mat_stack_count;
-  
+  LMatrix4f _projection_mat;
+  int _viewport_width;
+  int _viewport_height;
   CPT(TextureAttrib) _current_texture;
   CPT(TextureAttrib) _current_texture;
   CPT(TexMatrixAttrib) _current_tex_mat;
   CPT(TexMatrixAttrib) _current_tex_mat;
   bool _needs_tex_mat;
   bool _needs_tex_mat;
@@ -313,6 +316,9 @@ protected:
   bool _tex_gen_modifies_mat;
   bool _tex_gen_modifies_mat;
   bool _auto_antialias_mode;
   bool _auto_antialias_mode;
   RenderModeAttrib::Mode _render_mode;
   RenderModeAttrib::Mode _render_mode;
+  float _point_size;
+  float _gl_point_size;
+  bool _point_perspective;
 
 
   bool _transform_stale;
   bool _transform_stale;
   bool _vertex_blending_enabled;
   bool _vertex_blending_enabled;
@@ -335,6 +341,11 @@ protected:
   pset<string> _extensions;
   pset<string> _extensions;
 
 
 public:
 public:
+  bool _supports_point_parameters;
+  PFNGLPOINTPARAMETERFVPROC _glPointParameterfv;
+
+  bool _supports_point_sprite;
+
   bool _supports_vertex_blend;
   bool _supports_vertex_blend;
   PFNGLWEIGHTPOINTERARBPROC _glWeightPointerARB;
   PFNGLWEIGHTPOINTERARBPROC _glWeightPointerARB;
   PFNGLVERTEXBLENDARBPROC _glVertexBlendARB;
   PFNGLVERTEXBLENDARBPROC _glVertexBlendARB;
@@ -381,6 +392,17 @@ public:
   typedef pvector<GLuint> DeletedDisplayLists;
   typedef pvector<GLuint> DeletedDisplayLists;
   DeletedDisplayLists _deleted_display_lists;
   DeletedDisplayLists _deleted_display_lists;
 
 
+  // This class is used internally by draw_sprites().
+  class SpriteData {
+  public:
+    INLINE bool operator < (const SpriteData &other) const;
+    Vertexf _eye;
+    Colorf _color;
+    float _rotate;
+    float _scale_x;
+    float _scale_y;
+  };
+
 public:
 public:
   static GraphicsStateGuardian *
   static GraphicsStateGuardian *
   make_GlGraphicsStateGuardian(const FactoryParams &params);
   make_GlGraphicsStateGuardian(const FactoryParams &params);

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

@@ -27,6 +27,7 @@
     qpgeomLines.h \
     qpgeomLines.h \
     qpgeomLinestrips.h \
     qpgeomLinestrips.h \
     qpgeomPoints.h \
     qpgeomPoints.h \
+    qpgeomSprites.h \
     qpgeomUsageHint.h \
     qpgeomUsageHint.h \
     qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
     qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
     qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
     qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
@@ -79,6 +80,7 @@
     qpgeomLines.cxx \
     qpgeomLines.cxx \
     qpgeomLinestrips.cxx \
     qpgeomLinestrips.cxx \
     qpgeomPoints.cxx \
     qpgeomPoints.cxx \
+    qpgeomSprites.cxx \
     qpgeomVertexArrayData.cxx \
     qpgeomVertexArrayData.cxx \
     qpgeomVertexArrayFormat.cxx \
     qpgeomVertexArrayFormat.cxx \
     qpgeomCacheEntry.cxx \
     qpgeomCacheEntry.cxx \
@@ -128,6 +130,7 @@
     qpgeomLines.h \
     qpgeomLines.h \
     qpgeomLinestrips.h \
     qpgeomLinestrips.h \
     qpgeomPoints.h \
     qpgeomPoints.h \
+    qpgeomSprites.h \
     qpgeomUsageHint.h \
     qpgeomUsageHint.h \
     qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
     qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
     qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
     qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \

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

@@ -31,6 +31,7 @@
 #include "qpgeomLines.h"
 #include "qpgeomLines.h"
 #include "qpgeomLinestrips.h"
 #include "qpgeomLinestrips.h"
 #include "qpgeomPoints.h"
 #include "qpgeomPoints.h"
+#include "qpgeomSprites.h"
 #include "qpgeomVertexArrayData.h"
 #include "qpgeomVertexArrayData.h"
 #include "qpgeomVertexArrayFormat.h"
 #include "qpgeomVertexArrayFormat.h"
 #include "qpgeomVertexData.h"
 #include "qpgeomVertexData.h"
@@ -256,6 +257,7 @@ ConfigureFn(config_gobj) {
   qpGeomLines::init_type();
   qpGeomLines::init_type();
   qpGeomLinestrips::init_type();
   qpGeomLinestrips::init_type();
   qpGeomPoints::init_type();
   qpGeomPoints::init_type();
+  qpGeomSprites::init_type();
   qpGeomVertexArrayData::init_type();
   qpGeomVertexArrayData::init_type();
   qpGeomVertexArrayFormat::init_type();
   qpGeomVertexArrayFormat::init_type();
   qpGeomVertexData::init_type();
   qpGeomVertexData::init_type();
@@ -300,6 +302,7 @@ ConfigureFn(config_gobj) {
   qpGeomLines::register_with_read_factory();
   qpGeomLines::register_with_read_factory();
   qpGeomLinestrips::register_with_read_factory();
   qpGeomLinestrips::register_with_read_factory();
   qpGeomPoints::register_with_read_factory();
   qpGeomPoints::register_with_read_factory();
+  qpGeomSprites::register_with_read_factory();
   qpGeomVertexArrayData::register_with_read_factory();
   qpGeomVertexArrayData::register_with_read_factory();
   qpGeomVertexArrayFormat::register_with_read_factory();
   qpGeomVertexArrayFormat::register_with_read_factory();
   qpGeomVertexData::register_with_read_factory();
   qpGeomVertexData::register_with_read_factory();

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

@@ -20,6 +20,7 @@
 #include "qpgeomLines.cxx"
 #include "qpgeomLines.cxx"
 #include "qpgeomLinestrips.cxx"
 #include "qpgeomLinestrips.cxx"
 #include "qpgeomPoints.cxx"
 #include "qpgeomPoints.cxx"
+#include "qpgeomSprites.cxx"
 #include "qpgeomVertexArrayData.cxx"
 #include "qpgeomVertexArrayData.cxx"
 #include "qpgeomVertexArrayFormat.cxx"
 #include "qpgeomVertexArrayFormat.cxx"
 #include "qpgeomCacheEntry.cxx"
 #include "qpgeomCacheEntry.cxx"

+ 39 - 0
panda/src/gobj/internalName.I

@@ -178,6 +178,45 @@ get_color() {
   return _color;
   return _color;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_rotate
+//       Access: Published, Static
+//  Description: Returns the standard InternalName "rotate".
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+get_rotate() {
+  if (_rotate == (InternalName *)NULL) {
+    _rotate = InternalName::make("rotate");
+  }
+  return _rotate;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_scale_x
+//       Access: Published, Static
+//  Description: Returns the standard InternalName "scale_x".
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+get_scale_x() {
+  if (_scale_x == (InternalName *)NULL) {
+    _scale_x = InternalName::make("scale_x");
+  }
+  return _scale_x;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_scale_y
+//       Access: Published, Static
+//  Description: Returns the standard InternalName "scale_y".
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+get_scale_y() {
+  if (_scale_y == (InternalName *)NULL) {
+    _scale_y = InternalName::make("scale_y");
+  }
+  return _scale_y;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: InternalName::get_transform_blend
 //     Function: InternalName::get_transform_blend
 //       Access: Published, Static
 //       Access: Published, Static

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

@@ -32,6 +32,9 @@ PT(InternalName) InternalName::_tangent;
 PT(InternalName) InternalName::_binormal;
 PT(InternalName) InternalName::_binormal;
 PT(InternalName) InternalName::_texcoord;
 PT(InternalName) InternalName::_texcoord;
 PT(InternalName) InternalName::_color;
 PT(InternalName) InternalName::_color;
+PT(InternalName) InternalName::_rotate;
+PT(InternalName) InternalName::_scale_x;
+PT(InternalName) InternalName::_scale_y;
 PT(InternalName) InternalName::_transform_blend;
 PT(InternalName) InternalName::_transform_blend;
 PT(InternalName) InternalName::_transform_weight;
 PT(InternalName) InternalName::_transform_weight;
 PT(InternalName) InternalName::_transform_index;
 PT(InternalName) InternalName::_transform_index;

+ 6 - 0
panda/src/gobj/internalName.h

@@ -71,6 +71,9 @@ PUBLISHED:
   INLINE static PT(InternalName) get_texcoord();
   INLINE static PT(InternalName) get_texcoord();
   INLINE static PT(InternalName) get_texcoord_name(const string &name);
   INLINE static PT(InternalName) get_texcoord_name(const string &name);
   INLINE static PT(InternalName) get_color();
   INLINE static PT(InternalName) get_color();
+  INLINE static PT(InternalName) get_rotate();
+  INLINE static PT(InternalName) get_scale_x();
+  INLINE static PT(InternalName) get_scale_y();
   INLINE static PT(InternalName) get_transform_blend();
   INLINE static PT(InternalName) get_transform_blend();
   INLINE static PT(InternalName) get_transform_weight();
   INLINE static PT(InternalName) get_transform_weight();
   INLINE static PT(InternalName) get_transform_index();
   INLINE static PT(InternalName) get_transform_index();
@@ -92,6 +95,9 @@ private:
   static PT(InternalName) _binormal;
   static PT(InternalName) _binormal;
   static PT(InternalName) _texcoord;
   static PT(InternalName) _texcoord;
   static PT(InternalName) _color;
   static PT(InternalName) _color;
+  static PT(InternalName) _rotate;
+  static PT(InternalName) _scale_x;
+  static PT(InternalName) _scale_y;
   static PT(InternalName) _transform_blend;
   static PT(InternalName) _transform_blend;
   static PT(InternalName) _transform_weight;
   static PT(InternalName) _transform_weight;
   static PT(InternalName) _transform_index;
   static PT(InternalName) _transform_index;

+ 5 - 1
panda/src/gobj/qpgeomPrimitive.cxx

@@ -138,6 +138,9 @@ add_vertex(int vertex) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void qpGeomPrimitive::
 void qpGeomPrimitive::
 add_consecutive_vertices(int start, int num_vertices) {
 add_consecutive_vertices(int start, int num_vertices) {
+  if (num_vertices == 0) {
+    return;
+  }
   clear_cache();
   clear_cache();
   int end = (start + num_vertices) - 1;
   int end = (start + num_vertices) - 1;
   unsigned short short_start = start;
   unsigned short short_start = start;
@@ -472,7 +475,8 @@ get_num_bytes() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool qpGeomPrimitive::
 bool qpGeomPrimitive::
 check_valid(const qpGeomVertexData *vertex_data) const {
 check_valid(const qpGeomVertexData *vertex_data) const {
-  return get_max_vertex() < vertex_data->get_num_vertices();
+  return get_num_vertices() == 0 ||
+    get_max_vertex() < vertex_data->get_num_vertices();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 148 - 0
panda/src/gobj/qpgeomSprites.cxx

@@ -0,0 +1,148 @@
+// Filename: qpgeomSprites.cxx
+// Created by:  drose (05Apr05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "qpgeomSprites.h"
+#include "pStatTimer.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+
+TypeHandle qpGeomSprites::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomSprites::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomSprites::
+qpGeomSprites(qpGeomUsageHint::UsageHint usage_hint) :
+  qpGeomPrimitive(usage_hint)
+{
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomSprites::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomSprites::
+qpGeomSprites(const qpGeomSprites &copy) :
+  qpGeomPrimitive(copy)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomSprites::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomSprites::
+~qpGeomSprites() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomSprites::make_copy
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PT(qpGeomPrimitive) qpGeomSprites::
+make_copy() const {
+  return new qpGeomSprites(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomSprites::get_primitive_type
+//       Access: Public, Virtual
+//  Description: Returns the fundamental rendering type of this
+//               primitive: whether it is sprites, lines, or polygons.
+//               This is used primarily to set up the appropriate
+//               antialiasing settings when AntialiasAttrib::M_auto is
+//               in effect.
+////////////////////////////////////////////////////////////////////
+qpGeomPrimitive::PrimitiveType qpGeomSprites::
+get_primitive_type() const {
+  return PT_polygons;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomSprites::get_num_vertices_per_primitive
+//       Access: Public, Virtual
+//  Description: If the primitive type is a simple type in which all
+//               primitives have the same number of vertices, like
+//               sprites, 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
+//               sprite strip, returns 0.
+////////////////////////////////////////////////////////////////////
+int qpGeomSprites::
+get_num_vertices_per_primitive() const {
+  return 1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomSprites::get_min_num_vertices_per_primitive
+//       Access: Public, Virtual
+//  Description: Returns the minimum number of vertices that must be
+//               added before close_primitive() may legally be called.
+////////////////////////////////////////////////////////////////////
+int qpGeomSprites::
+get_min_num_vertices_per_primitive() const {
+  return 1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomSprites::draw
+//       Access: Public, Virtual
+//  Description: Calls the appropriate method on the GSG to draw the
+//               primitive.
+////////////////////////////////////////////////////////////////////
+void qpGeomSprites::
+draw(GraphicsStateGuardianBase *gsg) const {
+  gsg->draw_sprites(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomSprites::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               qpGeom.
+////////////////////////////////////////////////////////////////////
+void qpGeomSprites::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomSprites::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 *qpGeomSprites::
+make_from_bam(const FactoryParams &params) {
+  qpGeomSprites *object = new qpGeomSprites(qpGeomUsageHint::UH_client);
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  object->fillin(scan, manager);
+
+  return object;
+}

+ 90 - 0
panda/src/gobj/qpgeomSprites.h

@@ -0,0 +1,90 @@
+// Filename: qpgeomSprites.h
+// Created by:  drose (05Apr05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 qpGEOMSPRITES_H
+#define qpGEOMSPRITES_H
+
+#include "pandabase.h"
+#include "qpgeomPrimitive.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomSprites
+// Description : Defines a collection of rectangular polygons with the
+//               same texture applied to all of them.  This is most
+//               useful for particle systems.
+//
+//               Each sprite is defined by a single vertex, at the
+//               center of the polygon.  Each polygon may optionally
+//               be rotated by a certain angle, and/or scaled in x and
+//               y; if needed, these parameters are specified
+//               per-vertex with the optional "rotate", "scale_x", and
+//               "scale_y" vertex data column names.
+//
+//               The overall scale of the sprites is controlled by the
+//               current RenderModeAttrib::get_thickness() and
+//               get_perspective() parameters.  If present, scale_x
+//               and scale_y apply an additional per-sprite scale.
+//               The UV range is always (0, 0) in the upper left
+//               corner to (1, 1) in the lower right; use a
+//               TexMatrixAttrib to adjust this.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomSprites : public qpGeomPrimitive {
+PUBLISHED:
+  qpGeomSprites(qpGeomUsageHint::UsageHint usage_hint);
+  qpGeomSprites(const qpGeomSprites &copy);
+  virtual ~qpGeomSprites();
+
+public:
+  virtual PT(qpGeomPrimitive) make_copy() const;
+  virtual PrimitiveType get_primitive_type() const;
+
+  virtual int get_num_vertices_per_primitive() const;
+  virtual int get_min_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, "qpGeomSprites",
+                  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 - 2
panda/src/gobj/qpgeomVertexWriter.I

@@ -117,8 +117,11 @@ get_vertex_data() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool qpGeomVertexWriter::
 INLINE bool qpGeomVertexWriter::
 set_column(int column) {
 set_column(int column) {
+  if (_vertex_data == (qpGeomVertexData *)NULL) {
+    return false;
+  }
   return set_column(_vertex_data->get_format()->get_array_with(column),
   return set_column(_vertex_data->get_format()->get_array_with(column),
-                       _vertex_data->get_format()->get_column(column));
+                    _vertex_data->get_format()->get_column(column));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -154,8 +157,11 @@ set_column(const string &name) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool qpGeomVertexWriter::
 INLINE bool qpGeomVertexWriter::
 set_column(const InternalName *name) {
 set_column(const InternalName *name) {
+  if (_vertex_data == (qpGeomVertexData *)NULL) {
+    return false;
+  }
   return set_column(_vertex_data->get_format()->get_array_with(name),
   return set_column(_vertex_data->get_format()->get_array_with(name),
-                       _vertex_data->get_format()->get_column(name));
+                    _vertex_data->get_format()->get_column(name));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 6 - 2
panda/src/gobj/qpgeomVertexWriter.cxx

@@ -41,6 +41,10 @@ unsigned char qpGeomVertexWriter::empty_buffer[100] = { 0 };
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool qpGeomVertexWriter::
 bool qpGeomVertexWriter::
 set_column(int array, const qpGeomVertexColumn *column) {
 set_column(int array, const qpGeomVertexColumn *column) {
+  if (_vertex_data == (qpGeomVertexData *)NULL) {
+    return false;
+  }
+
   // Delete the old writer, if we've got one.
   // Delete the old writer, if we've got one.
   if (_writer != (Writer *)NULL) {
   if (_writer != (Writer *)NULL) {
     delete _writer;
     delete _writer;
@@ -55,9 +59,9 @@ set_column(int array, const qpGeomVertexColumn *column) {
     _stride = 0;
     _stride = 0;
     _write_vertex = _start_vertex;
     _write_vertex = _start_vertex;
     _num_vertices = 0;
     _num_vertices = 0;
-
+    
     return false;
     return false;
-
+    
   } else {
   } else {
     _array = array;
     _array = array;
     _column = column;
     _column = column;

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

@@ -55,6 +55,7 @@ class qpGeomTrifans;
 class qpGeomLines;
 class qpGeomLines;
 class qpGeomLinestrips;
 class qpGeomLinestrips;
 class qpGeomPoints;
 class qpGeomPoints;
+class qpGeomSprites;
 class qpGeomMunger;
 class qpGeomMunger;
 
 
 class PreparedGraphicsObjects;
 class PreparedGraphicsObjects;
@@ -196,6 +197,7 @@ public:
   virtual void draw_lines(const qpGeomLines *primitive)=0;
   virtual void draw_lines(const qpGeomLines *primitive)=0;
   virtual void draw_linestrips(const qpGeomLinestrips *primitive)=0;
   virtual void draw_linestrips(const qpGeomLinestrips *primitive)=0;
   virtual void draw_points(const qpGeomPoints *primitive)=0;
   virtual void draw_points(const qpGeomPoints *primitive)=0;
+  virtual void draw_sprites(const qpGeomSprites *primitive)=0;
   virtual void end_draw_primitives()=0;
   virtual void end_draw_primitives()=0;
 
 
   virtual void framebuffer_copy_to_texture
   virtual void framebuffer_copy_to_texture

+ 2 - 2
panda/src/particlesystem/baseParticleRenderer.h

@@ -67,8 +67,6 @@ PUBLISHED:
 public:
 public:
   virtual BaseParticleRenderer *make_copy() = 0;
   virtual BaseParticleRenderer *make_copy() = 0;
 
 
-  friend class ParticleSystem;
-
 protected:
 protected:
   ParticleRendererAlphaMode _alpha_mode;
   ParticleRendererAlphaMode _alpha_mode;
 
 
@@ -105,6 +103,8 @@ private:
   virtual void init_geoms() = 0;
   virtual void init_geoms() = 0;
   virtual void render(pvector< PT(PhysicsObject) >& po_vector,
   virtual void render(pvector< PT(PhysicsObject) >& po_vector,
                       int ttl_particles) = 0;
                       int ttl_particles) = 0;
+
+  friend class ParticleSystem;
 };
 };
 
 
 #include "baseParticleRenderer.I"
 #include "baseParticleRenderer.I"

+ 62 - 32
panda/src/particlesystem/lineParticleRenderer.cxx

@@ -17,8 +17,11 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "lineParticleRenderer.h"
 #include "lineParticleRenderer.h"
-
 #include "boundingSphere.h"
 #include "boundingSphere.h"
+#include "geomNode.h"
+#include "qpgeom.h"
+#include "qpgeomVertexWriter.h"
+#include "geomLine.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //    Function : LineParticleRenderer
 //    Function : LineParticleRenderer
@@ -30,8 +33,8 @@ LineParticleRenderer::
 LineParticleRenderer() :
 LineParticleRenderer() :
   _head_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f)),
   _head_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f)),
   _tail_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f)) {
   _tail_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f)) {
-  _line_primitive = new GeomLine;
-  init_geoms();
+
+  resize_pool(0);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -47,8 +50,7 @@ LineParticleRenderer(const Colorf& head,
   BaseParticleRenderer(alpha_mode),
   BaseParticleRenderer(alpha_mode),
   _head_color(head), _tail_color(tail)
   _head_color(head), _tail_color(tail)
 {
 {
-  _line_primitive = new GeomLine;
-  init_geoms();
+  resize_pool(0);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -63,8 +65,7 @@ LineParticleRenderer(const LineParticleRenderer& copy) :
   _head_color = copy._head_color;
   _head_color = copy._head_color;
   _tail_color = copy._tail_color;
   _tail_color = copy._tail_color;
 
 
-  _line_primitive = new GeomLine;
-  init_geoms();
+  resize_pool(0);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -117,11 +118,10 @@ kill_particle(int) {
 
 
 void LineParticleRenderer::
 void LineParticleRenderer::
 resize_pool(int new_size) {
 resize_pool(int new_size) {
-  _vertex_array = PTA_Vertexf::empty_array(new_size * 2);
-  _color_array = PTA_Colorf::empty_array(new_size * 2);
-
-  _line_primitive->set_coords(_vertex_array);
-  _line_primitive->set_colors(_color_array, G_PER_VERTEX);
+  if (!use_qpgeom) {
+    _vertex_array = PTA_Vertexf::empty_array(new_size * 2);
+    _color_array = PTA_Colorf::empty_array(new_size * 2);
+  }
 
 
   _max_pool_size = new_size;
   _max_pool_size = new_size;
 
 
@@ -136,7 +136,21 @@ resize_pool(int new_size) {
 
 
 void LineParticleRenderer::
 void LineParticleRenderer::
 init_geoms() {
 init_geoms() {
-  _line_primitive->set_num_prims(0);
+  if (use_qpgeom) {
+    PT(qpGeom) qpgeom = new qpGeom; 
+    _line_primitive = qpgeom;
+    _vdata = new qpGeomVertexData
+      ("particles", qpGeomVertexFormat::get_v3cp(),
+       qpGeomUsageHint::UH_dynamic);
+    qpgeom->set_vertex_data(_vdata);
+    _lines = new qpGeomLines(qpGeomUsageHint::UH_dynamic);
+    qpgeom->add_primitive(_lines);
+
+  } else {
+    _line_primitive = new GeomLine;
+    _line_primitive->set_coords(_vertex_array);
+    _line_primitive->set_colors(_color_array, G_PER_VERTEX);
+  }
 
 
   GeomNode *render_node = get_render_node();
   GeomNode *render_node = get_render_node();
   render_node->remove_all_geoms();
   render_node->remove_all_geoms();
@@ -162,6 +176,11 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
 
 
   Vertexf *cur_vert = &_vertex_array[0];
   Vertexf *cur_vert = &_vertex_array[0];
   Colorf *cur_color = &_color_array[0];
   Colorf *cur_color = &_color_array[0];
+  qpGeomVertexWriter vertex(_vdata, InternalName::get_vertex());
+  qpGeomVertexWriter color(_vdata, InternalName::get_color());
+  if (use_qpgeom) {
+    _lines->clear_vertices();
+  }
 
 
   // init the aabb
   // init the aabb
 
 
@@ -176,24 +195,24 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
     if (cur_particle->get_alive() == false)
     if (cur_particle->get_alive() == false)
       continue;
       continue;
 
 
-    LPoint3f pos = cur_particle->get_position();
+    LPoint3f position = cur_particle->get_position();
 
 
     // adjust the aabb
     // adjust the aabb
 
 
-    if (pos.get_x() > _aabb_max.get_x())
-      _aabb_max[0] = pos.get_x();
-    if (pos.get_x() < _aabb_min.get_x())
-      _aabb_min[0] = pos.get_x();
+    if (position[0] > _aabb_max[0])
+      _aabb_max[0] = position[0];
+    if (position[0] < _aabb_min[0])
+      _aabb_min[0] = position[0];
 
 
-    if (pos.get_y() > _aabb_max.get_y())
-      _aabb_max[1] = pos.get_y();
-    if (pos.get_y() < _aabb_min.get_y())
-      _aabb_min[1] = pos.get_y();
+    if (position[1] > _aabb_max[1])
+      _aabb_max[1] = position[1];
+    if (position[1] < _aabb_min[1])
+      _aabb_min[1] = position[1];
 
 
-    if (pos.get_z() > _aabb_max.get_z())
-      _aabb_max[2] = pos.get_z();
-    if (pos.get_z() < _aabb_min.get_z())
-      _aabb_min[2] = pos.get_z();
+    if (position[2] > _aabb_max[2])
+      _aabb_max[2] = position[2];
+    if (position[2] < _aabb_min[2])
+      _aabb_min[2] = position[2];
 
 
     // draw the particle.
     // draw the particle.
 
 
@@ -222,18 +241,29 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
 
 
     // one line from current position to last position
     // one line from current position to last position
 
 
-    *cur_vert++ = pos;
-    *cur_vert++ = cur_particle->get_last_position();
-
-    *cur_color++ = head_color;
-    *cur_color++ = tail_color;
+    if (use_qpgeom) {
+      vertex.add_data3f(position);
+      vertex.add_data3f(cur_particle->get_last_position());
+      color.add_data4f(head_color);
+      color.add_data4f(tail_color);
+      _lines->add_next_vertices(2);
+      _lines->close_primitive();
+    } else {
+      *cur_vert++ = position;
+      *cur_vert++ = cur_particle->get_last_position();
+
+      *cur_color++ = head_color;
+      *cur_color++ = tail_color;
+    }
 
 
     remaining_particles--;
     remaining_particles--;
     if (remaining_particles == 0)
     if (remaining_particles == 0)
       break;
       break;
   }
   }
 
 
-  _line_primitive->set_num_prims(ttl_particles);
+  if (!use_qpgeom) {
+    _line_primitive->set_num_prims(ttl_particles);
+  }
 
 
   // done filling geomline node, now do the bb stuff
   // done filling geomline node, now do the bb stuff
 
 

+ 5 - 2
panda/src/particlesystem/lineParticleRenderer.h

@@ -25,7 +25,8 @@
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "pointerToArray.h"
 #include "pointerToArray.h"
 #include "geom.h"
 #include "geom.h"
-#include "geomLine.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomLines.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : LineParticleRenderer
 //       Class : LineParticleRenderer
@@ -58,10 +59,12 @@ private:
   Colorf _head_color;
   Colorf _head_color;
   Colorf _tail_color;
   Colorf _tail_color;
 
 
-  PT(GeomLine) _line_primitive;
+  PT(Geom) _line_primitive;
+  PT(qpGeomLines) _lines;
 
 
   PTA_Vertexf _vertex_array;
   PTA_Vertexf _vertex_array;
   PTA_Colorf _color_array;
   PTA_Colorf _color_array;
+  PT(qpGeomVertexData) _vdata;
 
 
   int _max_pool_size;
   int _max_pool_size;
 
 

+ 58 - 32
panda/src/particlesystem/pointParticleRenderer.cxx

@@ -19,6 +19,9 @@
 #include "pointParticleRenderer.h"
 #include "pointParticleRenderer.h"
 #include "boundingSphere.h"
 #include "boundingSphere.h"
 #include "geomNode.h"
 #include "geomNode.h"
+#include "geomPoint.h"
+#include "qpgeom.h"
+#include "qpgeomVertexWriter.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //    Function : PointParticleRenderer
 //    Function : PointParticleRenderer
@@ -36,9 +39,8 @@ PointParticleRenderer(ParticleRendererAlphaMode am,
   _start_color(sc), _end_color(ec),
   _start_color(sc), _end_color(ec),
   _blend_type(bt), _blend_method(bm)
   _blend_type(bt), _blend_method(bm)
 {
 {
-  _point_primitive = new GeomPoint;
   set_point_size(point_size);
   set_point_size(point_size);
-  init_geoms();
+  resize_pool(0);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -49,8 +51,7 @@ PointParticleRenderer(ParticleRendererAlphaMode am,
 
 
 PointParticleRenderer::
 PointParticleRenderer::
 PointParticleRenderer(const PointParticleRenderer& copy) :
 PointParticleRenderer(const PointParticleRenderer& copy) :
-  BaseParticleRenderer(copy),
-  _max_pool_size(0)
+  BaseParticleRenderer(copy)
 {
 {
   _blend_type = copy._blend_type;
   _blend_type = copy._blend_type;
   _blend_method = copy._blend_method;
   _blend_method = copy._blend_method;
@@ -58,8 +59,7 @@ PointParticleRenderer(const PointParticleRenderer& copy) :
   _end_color = copy._end_color;
   _end_color = copy._end_color;
   _point_size = copy._point_size;
   _point_size = copy._point_size;
   _thick = copy._thick;
   _thick = copy._thick;
-  _point_primitive = new GeomPoint;
-  init_geoms();
+  resize_pool(0);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -69,7 +69,7 @@ PointParticleRenderer(const PointParticleRenderer& copy) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 PointParticleRenderer::
 PointParticleRenderer::
-~PointParticleRenderer(void) {
+~PointParticleRenderer() {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -79,7 +79,7 @@ PointParticleRenderer::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 BaseParticleRenderer *PointParticleRenderer::
 BaseParticleRenderer *PointParticleRenderer::
-make_copy(void) {
+make_copy() {
   return new PointParticleRenderer(*this);
   return new PointParticleRenderer(*this);
 }
 }
 
 
@@ -97,11 +97,10 @@ resize_pool(int new_size) {
 
 
   _max_pool_size = new_size;
   _max_pool_size = new_size;
 
 
-  _vertex_array = PTA_Vertexf::empty_array(new_size);
-  _color_array = PTA_Colorf::empty_array(new_size);
-
-  _point_primitive->set_coords(_vertex_array);
-  _point_primitive->set_colors(_color_array, G_PER_VERTEX);
+  if (!use_qpgeom) {
+    _vertex_array = PTA_Vertexf::empty_array(new_size);
+    _color_array = PTA_Colorf::empty_array(new_size);
+  }
 
 
   init_geoms();
   init_geoms();
 }
 }
@@ -113,9 +112,22 @@ resize_pool(int new_size) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 void PointParticleRenderer::
 void PointParticleRenderer::
-init_geoms(void) {
-
-  _point_primitive->set_num_prims(0);
+init_geoms() {
+  if (use_qpgeom) {
+    PT(qpGeom) qpgeom = new qpGeom; 
+    _point_primitive = qpgeom;
+    _vdata = new qpGeomVertexData
+      ("particles", qpGeomVertexFormat::get_v3cp(),
+       qpGeomUsageHint::UH_dynamic);
+    qpgeom->set_vertex_data(_vdata);
+    _points = new qpGeomPoints(qpGeomUsageHint::UH_dynamic);
+    qpgeom->add_primitive(_points);
+
+  } else {
+    _point_primitive = new GeomPoint;
+    _point_primitive->set_coords(_vertex_array);
+    _point_primitive->set_colors(_color_array, G_PER_VERTEX);
+  }
   
   
   GeomNode *render_node = get_render_node();
   GeomNode *render_node = get_render_node();
   render_node->remove_all_geoms();
   render_node->remove_all_geoms();
@@ -228,6 +240,8 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
 
 
   Vertexf *cur_vert = &_vertex_array[0];
   Vertexf *cur_vert = &_vertex_array[0];
   Colorf *cur_color = &_color_array[0];
   Colorf *cur_color = &_color_array[0];
+  qpGeomVertexWriter vertex(_vdata, InternalName::get_vertex());
+  qpGeomVertexWriter color(_vdata, InternalName::get_color());
 
 
   // init the aabb
   // init the aabb
 
 
@@ -239,34 +253,41 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
   for (i = 0; i < (int)po_vector.size(); i++) {
   for (i = 0; i < (int)po_vector.size(); i++) {
     cur_particle = (BaseParticle *) po_vector[i].p();
     cur_particle = (BaseParticle *) po_vector[i].p();
 
 
-    if (cur_particle->get_alive() == false)
+    if (!cur_particle->get_alive())
       continue;
       continue;
 
 
+    LPoint3f position = cur_particle->get_position();
+
     // x aabb adjust
     // x aabb adjust
 
 
-    if (cur_particle->get_position().get_x() > _aabb_max.get_x())
-      _aabb_max[0] = cur_particle->get_position().get_x();
-    else if (cur_particle->get_position().get_x() < _aabb_min.get_x())
-      _aabb_min[0] = cur_particle->get_position().get_x();
+    if (position[0] > _aabb_max[0])
+      _aabb_max[0] = position[0];
+    else if (position[0] < _aabb_min[0])
+      _aabb_min[0] = position[0];
 
 
     // y aabb adjust
     // y aabb adjust
 
 
-    if (cur_particle->get_position().get_y() > _aabb_max.get_y())
-      _aabb_max[1] = cur_particle->get_position().get_y();
-    else if (cur_particle->get_position().get_y() < _aabb_min.get_y())
-      _aabb_min[1] = cur_particle->get_position().get_y();
+    if (position[1] > _aabb_max[1])
+      _aabb_max[1] = position[1];
+    else if (position[1] < _aabb_min[1])
+      _aabb_min[1] = position[1];
 
 
     // z aabb adjust
     // z aabb adjust
 
 
-    if (cur_particle->get_position().get_z() > _aabb_max.get_z())
-      _aabb_max[2] = cur_particle->get_position().get_z();
-    else if (cur_particle->get_position().get_z() < _aabb_min.get_z())
-      _aabb_min[2] = cur_particle->get_position().get_z();
+    if (position[2] > _aabb_max[2])
+      _aabb_max[2] = position[2];
+    else if (position[2] < _aabb_min[2])
+      _aabb_min[2] = position[2];
 
 
     // stuff it into the arrays
     // stuff it into the arrays
 
 
-    *cur_vert++ = cur_particle->get_position();
-    *cur_color++ = create_color(cur_particle);
+    if (use_qpgeom) {
+      vertex.add_data3f(position);
+      color.add_data4f(create_color(cur_particle));
+    } else {
+      *cur_vert++ = position;
+      *cur_color++ = create_color(cur_particle);
+    }
 
 
     // maybe jump out early?
     // maybe jump out early?
 
 
@@ -275,7 +296,12 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
       break;
       break;
   }
   }
 
 
-  _point_primitive->set_num_prims(ttl_particles);
+  if (use_qpgeom) {
+    _points->clear_vertices();
+    _points->add_next_vertices(ttl_particles);
+  } else {
+    _point_primitive->set_num_prims(ttl_particles);
+  }
 
 
   // done filling geompoint node, now do the bb stuff
   // done filling geompoint node, now do the bb stuff
 
 

+ 5 - 2
panda/src/particlesystem/pointParticleRenderer.h

@@ -26,7 +26,8 @@
 #include "pointerToArray.h"
 #include "pointerToArray.h"
 #include "luse.h"
 #include "luse.h"
 #include "geom.h"
 #include "geom.h"
-#include "geomPoint.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomPoints.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : PointParticleRenderer
 //       Class : PointParticleRenderer
@@ -76,10 +77,12 @@ private:
   float _point_size;
   float _point_size;
   CPT(RenderAttrib) _thick;
   CPT(RenderAttrib) _thick;
 
 
-  PT(GeomPoint) _point_primitive;
+  PT(Geom) _point_primitive;
+  PT(qpGeomPoints) _points;
 
 
   PTA_Vertexf _vertex_array;
   PTA_Vertexf _vertex_array;
   PTA_Colorf _color_array;
   PTA_Colorf _color_array;
+  PT(qpGeomVertexData) _vdata;
 
 
   int _max_pool_size;
   int _max_pool_size;
 
 

+ 113 - 52
panda/src/particlesystem/sparkleParticleRenderer.cxx

@@ -17,9 +17,11 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "sparkleParticleRenderer.h"
 #include "sparkleParticleRenderer.h"
-
 #include "boundingSphere.h"
 #include "boundingSphere.h"
 #include "geomNode.h"
 #include "geomNode.h"
+#include "qpgeom.h"
+#include "qpgeomVertexWriter.h"
+#include "geomLine.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //    Function : SparkleParticleRenderer
 //    Function : SparkleParticleRenderer
@@ -33,8 +35,7 @@ SparkleParticleRenderer() :
   _edge_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f)),
   _edge_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f)),
   _birth_radius(0.1f), _death_radius(0.1f)
   _birth_radius(0.1f), _death_radius(0.1f)
 {
 {
-  _line_primitive = new GeomLine;
-  init_geoms();
+  resize_pool(0);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -51,8 +52,7 @@ SparkleParticleRenderer(const Colorf& center, const Colorf& edge,
   _center_color(center), _edge_color(edge), _birth_radius(birth_radius),
   _center_color(center), _edge_color(edge), _birth_radius(birth_radius),
   _death_radius(death_radius), _life_scale(life_scale)
   _death_radius(death_radius), _life_scale(life_scale)
 {
 {
-  _line_primitive = new GeomLine;
-  init_geoms();
+  resize_pool(0);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -69,8 +69,7 @@ SparkleParticleRenderer(const SparkleParticleRenderer& copy) :
   _death_radius = copy._death_radius;
   _death_radius = copy._death_radius;
   _life_scale = copy._life_scale;
   _life_scale = copy._life_scale;
 
 
-  _line_primitive = new GeomLine;
-  init_geoms();
+  resize_pool(0);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -118,11 +117,10 @@ kill_particle(int) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void SparkleParticleRenderer::
 void SparkleParticleRenderer::
 resize_pool(int new_size) {
 resize_pool(int new_size) {
-  _vertex_array = PTA_Vertexf::empty_array(new_size * 12);
-  _color_array = PTA_Colorf::empty_array(new_size * 12);
-
-  _line_primitive->set_coords(_vertex_array);
-  _line_primitive->set_colors(_color_array, G_PER_VERTEX);
+  if (!use_qpgeom) {
+    _vertex_array = PTA_Vertexf::empty_array(new_size * 12);
+    _color_array = PTA_Colorf::empty_array(new_size * 12);
+  }
 
 
   _max_pool_size = new_size;
   _max_pool_size = new_size;
 
 
@@ -136,7 +134,21 @@ resize_pool(int new_size) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void SparkleParticleRenderer::
 void SparkleParticleRenderer::
 init_geoms() {
 init_geoms() {
-  _line_primitive->set_num_prims(0);
+  if (use_qpgeom) {
+    PT(qpGeom) qpgeom = new qpGeom; 
+    _line_primitive = qpgeom;
+    _vdata = new qpGeomVertexData
+      ("particles", qpGeomVertexFormat::get_v3cp(),
+       qpGeomUsageHint::UH_dynamic);
+    qpgeom->set_vertex_data(_vdata);
+    _lines = new qpGeomLines(qpGeomUsageHint::UH_dynamic);
+    qpgeom->add_primitive(_lines);
+
+  } else {
+    _line_primitive = new GeomLine;
+    _line_primitive->set_coords(_vertex_array);
+    _line_primitive->set_colors(_color_array, G_PER_VERTEX);
+  }
 
 
   GeomNode *render_node = get_render_node();
   GeomNode *render_node = get_render_node();
   render_node->remove_all_geoms();
   render_node->remove_all_geoms();
@@ -161,6 +173,11 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
 
 
   Vertexf *cur_vert = &_vertex_array[0];
   Vertexf *cur_vert = &_vertex_array[0];
   Colorf *cur_color = &_color_array[0];
   Colorf *cur_color = &_color_array[0];
+  qpGeomVertexWriter vertex(_vdata, InternalName::get_vertex());
+  qpGeomVertexWriter color(_vdata, InternalName::get_color());
+  if (use_qpgeom) {
+    _lines->clear_vertices();
+  }
 
 
   // init the aabb
   // init the aabb
 
 
@@ -175,22 +192,24 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
     if (cur_particle->get_alive() == false)
     if (cur_particle->get_alive() == false)
       continue;
       continue;
 
 
+    LPoint3f position = cur_particle->get_position();
+
     // adjust the aabb
     // adjust the aabb
 
 
-    if (cur_particle->get_position().get_x() > _aabb_max.get_x())
-      _aabb_max[0] = cur_particle->get_position().get_x();
-    else if (cur_particle->get_position().get_x() < _aabb_min.get_x())
-      _aabb_min[0] = cur_particle->get_position().get_x();
+    if (position[0] > _aabb_max[0])
+      _aabb_max[0] = position[0];
+    else if (position[0] < _aabb_min[0])
+      _aabb_min[0] = position[0];
 
 
-    if (cur_particle->get_position().get_y() > _aabb_max.get_y())
-      _aabb_max[1] = cur_particle->get_position().get_y();
-    else if (cur_particle->get_position().get_y() < _aabb_min.get_y())
-      _aabb_min[1] = cur_particle->get_position().get_y();
+    if (position[1] > _aabb_max[1])
+      _aabb_max[1] = position[1];
+    else if (position[1] < _aabb_min[1])
+      _aabb_min[1] = position[1];
 
 
-    if (cur_particle->get_position().get_z() > _aabb_max.get_z())
-      _aabb_max[2] = cur_particle->get_position().get_z();
-    else if (cur_particle->get_position().get_z() < _aabb_min.get_z())
-      _aabb_min[2] = cur_particle->get_position().get_z();
+    if (position[2] > _aabb_max[2])
+      _aabb_max[2] = position[2];
+    else if (position[2] < _aabb_min[2])
+      _aabb_min[2] = position[2];
 
 
     // draw the particle.
     // draw the particle.
 
 
@@ -198,7 +217,6 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
     float neg_radius = -radius;
     float neg_radius = -radius;
     float alpha;
     float alpha;
 
 
-    LPoint3f pos = cur_particle->get_position();
     Colorf center_color = _center_color;
     Colorf center_color = _center_color;
     Colorf edge_color = _edge_color;
     Colorf edge_color = _edge_color;
 
 
@@ -223,38 +241,81 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
 
 
     // 6 lines coming from the center point.
     // 6 lines coming from the center point.
 
 
-    *cur_vert++ = pos;
-    *cur_vert++ = pos + Vertexf(radius, 0.0f, 0.0f);
-    *cur_vert++ = pos;
-    *cur_vert++ = pos + Vertexf(neg_radius, 0.0f, 0.0f);
-    *cur_vert++ = pos;
-    *cur_vert++ = pos + Vertexf(0.0f, radius, 0.0f);
-    *cur_vert++ = pos;
-    *cur_vert++ = pos + Vertexf(0.0f, neg_radius, 0.0f);
-    *cur_vert++ = pos;
-    *cur_vert++ = pos + Vertexf(0.0f, 0.0f, radius);
-    *cur_vert++ = pos;
-    *cur_vert++ = pos + Vertexf(0.0f, 0.0f, neg_radius);
-
-    *cur_color++ = center_color;
-    *cur_color++ = edge_color;
-    *cur_color++ = center_color;
-    *cur_color++ = edge_color;
-    *cur_color++ = center_color;
-    *cur_color++ = edge_color;
-    *cur_color++ = center_color;
-    *cur_color++ = edge_color;
-    *cur_color++ = center_color;
-    *cur_color++ = edge_color;
-    *cur_color++ = center_color;
-    *cur_color++ = edge_color;
+    if (use_qpgeom) {
+      vertex.add_data3f(position);
+      vertex.add_data3f(position + Vertexf(radius, 0.0f, 0.0f));
+      vertex.add_data3f(position);
+      vertex.add_data3f(position + Vertexf(neg_radius, 0.0f, 0.0f));
+      vertex.add_data3f(position);
+      vertex.add_data3f(position + Vertexf(0.0f, radius, 0.0f));
+      vertex.add_data3f(position);
+      vertex.add_data3f(position + Vertexf(0.0f, neg_radius, 0.0f));
+      vertex.add_data3f(position);
+      vertex.add_data3f(position + Vertexf(0.0f, 0.0f, radius));
+      vertex.add_data3f(position);
+      vertex.add_data3f(position + Vertexf(0.0f, 0.0f, neg_radius));
+
+      color.add_data4f(center_color);
+      color.add_data4f(edge_color);
+      color.add_data4f(center_color);
+      color.add_data4f(edge_color);
+      color.add_data4f(center_color);
+      color.add_data4f(edge_color);
+      color.add_data4f(center_color);
+      color.add_data4f(edge_color);
+      color.add_data4f(center_color);
+      color.add_data4f(edge_color);
+      color.add_data4f(center_color);
+      color.add_data4f(edge_color);
+
+      _lines->add_next_vertices(2);
+      _lines->close_primitive();
+      _lines->add_next_vertices(2);
+      _lines->close_primitive();
+      _lines->add_next_vertices(2);
+      _lines->close_primitive();
+      _lines->add_next_vertices(2);
+      _lines->close_primitive();
+      _lines->add_next_vertices(2);
+      _lines->close_primitive();
+      _lines->add_next_vertices(2);
+      _lines->close_primitive();
+    } else {
+      *cur_vert++ = position;
+      *cur_vert++ = position + Vertexf(radius, 0.0f, 0.0f);
+      *cur_vert++ = position;
+      *cur_vert++ = position + Vertexf(neg_radius, 0.0f, 0.0f);
+      *cur_vert++ = position;
+      *cur_vert++ = position + Vertexf(0.0f, radius, 0.0f);
+      *cur_vert++ = position;
+      *cur_vert++ = position + Vertexf(0.0f, neg_radius, 0.0f);
+      *cur_vert++ = position;
+      *cur_vert++ = position + Vertexf(0.0f, 0.0f, radius);
+      *cur_vert++ = position;
+      *cur_vert++ = position + Vertexf(0.0f, 0.0f, neg_radius);
+
+      *cur_color++ = center_color;
+      *cur_color++ = edge_color;
+      *cur_color++ = center_color;
+      *cur_color++ = edge_color;
+      *cur_color++ = center_color;
+      *cur_color++ = edge_color;
+      *cur_color++ = center_color;
+      *cur_color++ = edge_color;
+      *cur_color++ = center_color;
+      *cur_color++ = edge_color;
+      *cur_color++ = center_color;
+      *cur_color++ = edge_color;
+    }
 
 
     remaining_particles--;
     remaining_particles--;
     if (remaining_particles == 0)
     if (remaining_particles == 0)
       break;
       break;
   }
   }
 
 
-  _line_primitive->set_num_prims(6 * ttl_particles);
+  if (!use_qpgeom) {
+    _line_primitive->set_num_prims(6 * ttl_particles);
+  }
 
 
   // done filling geomline node, now do the bb stuff
   // done filling geomline node, now do the bb stuff
 
 

+ 5 - 2
panda/src/particlesystem/sparkleParticleRenderer.h

@@ -25,7 +25,8 @@
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "pointerToArray.h"
 #include "pointerToArray.h"
 #include "geom.h"
 #include "geom.h"
-#include "geomLine.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomLines.h"
 
 
 enum SparkleParticleLifeScale {
 enum SparkleParticleLifeScale {
   SP_NO_SCALE,
   SP_NO_SCALE,
@@ -78,10 +79,12 @@ private:
   float _birth_radius;
   float _birth_radius;
   float _death_radius;
   float _death_radius;
 
 
-  PT(GeomLine) _line_primitive;
+  PT(Geom) _line_primitive;
+  PT(qpGeomLines) _lines;
 
 
   PTA_Vertexf _vertex_array;
   PTA_Vertexf _vertex_array;
   PTA_Colorf _color_array;
   PTA_Colorf _color_array;
+  PT(qpGeomVertexData) _vdata;
 
 
   int _max_pool_size;
   int _max_pool_size;
 
 

+ 32 - 33
panda/src/particlesystem/spriteParticleRenderer.I

@@ -34,10 +34,12 @@ get_source_type() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void SpriteParticleRenderer::
 INLINE void SpriteParticleRenderer::
 set_texture(Texture *tex) {
 set_texture(Texture *tex) {
-  _sprite_primitive->set_texture(tex);
-  _sprite_primitive->set_ll_uv(TexCoordf(0.0f, 0.0f));
-  _sprite_primitive->set_ur_uv(TexCoordf(1.0f, 1.0f));
+  _texture = tex;
+  set_ll_uv(TexCoordf(0.0f, 0.0f));
+  set_ur_uv(TexCoordf(1.0f, 1.0f));
   _source_type = ST_texture;
   _source_type = ST_texture;
+
+  init_geoms();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -50,7 +52,7 @@ set_texture(Texture *tex) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void SpriteParticleRenderer::
 INLINE void SpriteParticleRenderer::
 set_ll_uv(const TexCoordf &ll_uv) {
 set_ll_uv(const TexCoordf &ll_uv) {
-  _sprite_primitive->set_ll_uv(ll_uv);
+  _ll_uv = ll_uv;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -63,7 +65,7 @@ set_ll_uv(const TexCoordf &ll_uv) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void SpriteParticleRenderer::
 INLINE void SpriteParticleRenderer::
 set_ur_uv(const TexCoordf &ur_uv) {
 set_ur_uv(const TexCoordf &ur_uv) {
-  _sprite_primitive->set_ur_uv(ur_uv);
+  _ur_uv = ur_uv;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -81,16 +83,14 @@ set_color(const Colorf &color) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void SpriteParticleRenderer::
 INLINE void SpriteParticleRenderer::
 set_x_scale_flag(bool animate_x_ratio) {
 set_x_scale_flag(bool animate_x_ratio) {
-  if (animate_x_ratio == true && _animate_x_ratio == false) {
+  if (animate_x_ratio && !_animate_x_ratio) {
     _x_texel_array = PTA_float::empty_array(_pool_size);
     _x_texel_array = PTA_float::empty_array(_pool_size);
-    _sprite_primitive->set_x_texel_ratio(_x_texel_array, G_PER_PRIM);
-  }
-  else if (animate_x_ratio == false && _animate_x_ratio == true) {
+  } else if (!animate_x_ratio && _animate_x_ratio) {
     _x_texel_array = PTA_float::empty_array(1);
     _x_texel_array = PTA_float::empty_array(1);
-    _sprite_primitive->set_x_texel_ratio(_x_texel_array, G_OVERALL);
   }
   }
 
 
   _animate_x_ratio = animate_x_ratio;
   _animate_x_ratio = animate_x_ratio;
+  init_geoms();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -99,16 +99,14 @@ set_x_scale_flag(bool animate_x_ratio) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void SpriteParticleRenderer::
 INLINE void SpriteParticleRenderer::
 set_y_scale_flag(bool animate_y_ratio) {
 set_y_scale_flag(bool animate_y_ratio) {
-  if (animate_y_ratio == true && _animate_y_ratio == false) {
+  if (animate_y_ratio && !_animate_y_ratio) {
     _y_texel_array = PTA_float::empty_array(_pool_size);
     _y_texel_array = PTA_float::empty_array(_pool_size);
-    _sprite_primitive->set_y_texel_ratio(_y_texel_array, G_PER_PRIM);
-  }
-  else if (animate_y_ratio == false && _animate_y_ratio == true) {
+  } else if (!animate_y_ratio && _animate_y_ratio) {
     _y_texel_array = PTA_float::empty_array(1);
     _y_texel_array = PTA_float::empty_array(1);
-    _sprite_primitive->set_y_texel_ratio(_y_texel_array, G_OVERALL);
   }
   }
 
 
   _animate_y_ratio = animate_y_ratio;
   _animate_y_ratio = animate_y_ratio;
+  init_geoms();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -117,16 +115,14 @@ set_y_scale_flag(bool animate_y_ratio) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void SpriteParticleRenderer::
 INLINE void SpriteParticleRenderer::
 set_anim_angle_flag(bool animate_theta) {
 set_anim_angle_flag(bool animate_theta) {
-  if (animate_theta == true && _animate_theta == false) {
+  if (animate_theta && !_animate_theta) {
     _theta_array = PTA_float::empty_array(_pool_size);
     _theta_array = PTA_float::empty_array(_pool_size);
-    _sprite_primitive->set_thetas(_theta_array, G_PER_PRIM);
-  }
-  else if (animate_theta == false && _animate_theta == true) {
+  } else if (!animate_theta && _animate_theta) {
     _theta_array = PTA_float::empty_array(_pool_size);
     _theta_array = PTA_float::empty_array(_pool_size);
-    _sprite_primitive->set_thetas(_theta_array, G_OVERALL);
   }
   }
 
 
   _animate_theta = animate_theta;
   _animate_theta = animate_theta;
+  init_geoms();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -135,7 +131,8 @@ set_anim_angle_flag(bool animate_theta) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void SpriteParticleRenderer::
 INLINE void SpriteParticleRenderer::
 set_initial_x_scale(float initial_x_scale) {
 set_initial_x_scale(float initial_x_scale) {
-  _initial_x_texel_ratio = initial_x_scale;
+  _initial_x_scale = initial_x_scale;
+  init_geoms();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -144,7 +141,7 @@ set_initial_x_scale(float initial_x_scale) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void SpriteParticleRenderer::
 INLINE void SpriteParticleRenderer::
 set_final_x_scale(float final_x_scale) {
 set_final_x_scale(float final_x_scale) {
-  _final_x_texel_ratio = final_x_scale;
+  _final_x_scale = final_x_scale;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -153,7 +150,8 @@ set_final_x_scale(float final_x_scale) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void SpriteParticleRenderer::
 INLINE void SpriteParticleRenderer::
 set_initial_y_scale(float initial_y_scale) {
 set_initial_y_scale(float initial_y_scale) {
-  _initial_y_texel_ratio = initial_y_scale;
+  _initial_y_scale = initial_y_scale;
+  init_geoms();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -162,7 +160,7 @@ set_initial_y_scale(float initial_y_scale) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void SpriteParticleRenderer::
 INLINE void SpriteParticleRenderer::
 set_final_y_scale(float final_y_scale) {
 set_final_y_scale(float final_y_scale) {
-  _final_y_texel_ratio = final_y_scale;
+  _final_y_scale = final_y_scale;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -172,6 +170,7 @@ set_final_y_scale(float final_y_scale) {
 INLINE void SpriteParticleRenderer::
 INLINE void SpriteParticleRenderer::
 set_nonanimated_theta(float theta) {
 set_nonanimated_theta(float theta) {
   _theta = theta;
   _theta = theta;
+  init_geoms();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -189,7 +188,7 @@ set_alpha_blend_method(ParticleRendererBlendMethod bm) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void SpriteParticleRenderer::
 INLINE void SpriteParticleRenderer::
 set_alpha_disable(bool ad) {
 set_alpha_disable(bool ad) {
-  _sprite_primitive->set_alpha_disable(ad);
+  _alpha_disable = ad;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -198,7 +197,7 @@ set_alpha_disable(bool ad) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *SpriteParticleRenderer::
 INLINE Texture *SpriteParticleRenderer::
 get_texture() const {
 get_texture() const {
-  return _sprite_primitive->get_texture();
+  return _texture;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -209,7 +208,7 @@ get_texture() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE const TexCoordf &SpriteParticleRenderer::
 INLINE const TexCoordf &SpriteParticleRenderer::
 get_ll_uv() const {
 get_ll_uv() const {
-  return _sprite_primitive->get_ll_uv();
+  return _ll_uv;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -220,7 +219,7 @@ get_ll_uv() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE const TexCoordf &SpriteParticleRenderer::
 INLINE const TexCoordf &SpriteParticleRenderer::
 get_ur_uv() const {
 get_ur_uv() const {
-  return _sprite_primitive->get_ur_uv();
+  return _ur_uv;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -265,7 +264,7 @@ get_anim_angle_flag() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE float SpriteParticleRenderer::
 INLINE float SpriteParticleRenderer::
 get_initial_x_scale() const {
 get_initial_x_scale() const {
-  return _initial_x_texel_ratio;
+  return _initial_x_scale;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -274,7 +273,7 @@ get_initial_x_scale() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE float SpriteParticleRenderer::
 INLINE float SpriteParticleRenderer::
 get_final_x_scale() const {
 get_final_x_scale() const {
-  return _final_x_texel_ratio;
+  return _final_x_scale;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -283,7 +282,7 @@ get_final_x_scale() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE float SpriteParticleRenderer::
 INLINE float SpriteParticleRenderer::
 get_initial_y_scale() const {
 get_initial_y_scale() const {
-  return _initial_y_texel_ratio;
+  return _initial_y_scale;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -292,7 +291,7 @@ get_initial_y_scale() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE float SpriteParticleRenderer::
 INLINE float SpriteParticleRenderer::
 get_final_y_scale() const {
 get_final_y_scale() const {
-  return _final_y_texel_ratio;
+  return _final_y_scale;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -319,5 +318,5 @@ get_alpha_blend_method() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool SpriteParticleRenderer::
 INLINE bool SpriteParticleRenderer::
 get_alpha_disable() const {
 get_alpha_disable() const {
-  return _sprite_primitive->get_alpha_disable();
+  return _alpha_disable;
 }
 }

+ 227 - 88
panda/src/particlesystem/spriteParticleRenderer.cxx

@@ -17,11 +17,16 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "spriteParticleRenderer.h"
 #include "spriteParticleRenderer.h"
-
 #include "boundingSphere.h"
 #include "boundingSphere.h"
-#include "geom.h"
+#include "geomNode.h"
 #include "nodePath.h"
 #include "nodePath.h"
 #include "dcast.h"
 #include "dcast.h"
+#include "geomSprite.h"
+#include "qpgeom.h"
+#include "qpgeomVertexWriter.h"
+#include "renderModeAttrib.h"
+#include "texMatrixAttrib.h"
+#include "textureAttrib.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //    Function : SpriteParticleRenderer::SpriteParticleRenderer
 //    Function : SpriteParticleRenderer::SpriteParticleRenderer
@@ -32,19 +37,21 @@ SpriteParticleRenderer::
 SpriteParticleRenderer(Texture *tex) :
 SpriteParticleRenderer(Texture *tex) :
   BaseParticleRenderer(PR_ALPHA_NONE),
   BaseParticleRenderer(PR_ALPHA_NONE),
   _color(Colorf(1.0f, 1.0f, 1.0f, 1.0f)),
   _color(Colorf(1.0f, 1.0f, 1.0f, 1.0f)),
-  _initial_x_texel_ratio(0.02f),
-  _final_x_texel_ratio(0.02f),
-  _initial_y_texel_ratio(0.02f),
-  _final_y_texel_ratio(0.02f),
+  _ll_uv(0.0f, 0.0f),
+  _ur_uv(1.0f, 1.0f),
+  _initial_x_scale(0.02f),
+  _final_x_scale(0.02f),
+  _initial_y_scale(0.02f),
+  _final_y_scale(0.02f),
   _theta(0.0f),
   _theta(0.0f),
   _animate_x_ratio(false),
   _animate_x_ratio(false),
   _animate_y_ratio(false),
   _animate_y_ratio(false),
   _animate_theta(false),
   _animate_theta(false),
+  _alpha_disable(false),
   _blend_method(PP_BLEND_LINEAR),
   _blend_method(PP_BLEND_LINEAR),
   _pool_size(0),
   _pool_size(0),
   _source_type(ST_texture)
   _source_type(ST_texture)
 {
 {
-  _sprite_primitive = new GeomSprite(tex);
   init_geoms();
   init_geoms();
 }
 }
 
 
@@ -56,17 +63,20 @@ SpriteParticleRenderer(Texture *tex) :
 SpriteParticleRenderer::
 SpriteParticleRenderer::
 SpriteParticleRenderer(const SpriteParticleRenderer& copy) :
 SpriteParticleRenderer(const SpriteParticleRenderer& copy) :
   BaseParticleRenderer(copy), _pool_size(0) {
   BaseParticleRenderer(copy), _pool_size(0) {
+  _texture = copy._texture;
   _animate_x_ratio = copy._animate_x_ratio;
   _animate_x_ratio = copy._animate_x_ratio;
   _animate_y_ratio = copy._animate_y_ratio;
   _animate_y_ratio = copy._animate_y_ratio;
   _animate_theta = copy._animate_theta;
   _animate_theta = copy._animate_theta;
+  _alpha_disable = copy._alpha_disable;
   _blend_method = copy._blend_method;
   _blend_method = copy._blend_method;
-  _initial_x_texel_ratio = copy._initial_x_texel_ratio;
-  _final_x_texel_ratio = copy._final_x_texel_ratio;
-  _initial_y_texel_ratio = copy._initial_y_texel_ratio;
-  _final_y_texel_ratio = copy._final_y_texel_ratio;
+  _ll_uv = copy._ll_uv;
+  _ur_uv = copy._ur_uv;
+  _initial_x_scale = copy._initial_x_scale;
+  _final_x_scale = copy._final_x_scale;
+  _initial_y_scale = copy._initial_y_scale;
+  _final_y_scale = copy._final_y_scale;
   _theta = copy._theta;
   _theta = copy._theta;
   _color = copy._color;
   _color = copy._color;
-  _sprite_primitive = new GeomSprite(copy.get_texture());
   init_geoms();
   init_geoms();
 }
 }
 
 
@@ -76,7 +86,7 @@ SpriteParticleRenderer(const SpriteParticleRenderer& copy) :
 // Description : destructor
 // Description : destructor
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 SpriteParticleRenderer::
 SpriteParticleRenderer::
-~SpriteParticleRenderer(void) {
+~SpriteParticleRenderer() {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -85,7 +95,7 @@ SpriteParticleRenderer::
 // Description : child dynamic copy
 // Description : child dynamic copy
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 BaseParticleRenderer *SpriteParticleRenderer::
 BaseParticleRenderer *SpriteParticleRenderer::
-make_copy(void) {
+make_copy() {
   return new SpriteParticleRenderer(*this);
   return new SpriteParticleRenderer(*this);
 }
 }
 
 
@@ -166,6 +176,8 @@ set_from_node(const NodePath &node_path) {
   set_ll_uv(min_uv);
   set_ll_uv(min_uv);
   set_ur_uv(max_uv);
   set_ur_uv(max_uv);
   _source_type = ST_from_node;
   _source_type = ST_from_node;
+
+  init_geoms();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -180,34 +192,29 @@ resize_pool(int new_size) {
 
 
   _pool_size = new_size;
   _pool_size = new_size;
 
 
-  GeomBindType _x_bind, _y_bind, _theta_bind;
-
   // handle the x texel ratio
   // handle the x texel ratio
-  if (_animate_x_ratio == true) {
+  if (_animate_x_ratio) {
     _x_texel_array = PTA_float::empty_array(new_size);
     _x_texel_array = PTA_float::empty_array(new_size);
     _x_bind = G_PER_PRIM;
     _x_bind = G_PER_PRIM;
-  }
-  else {
+  } else {
     _x_texel_array = PTA_float::empty_array(1);
     _x_texel_array = PTA_float::empty_array(1);
     _x_bind = G_OVERALL;
     _x_bind = G_OVERALL;
   }
   }
 
 
   // handle the y texel ratio
   // handle the y texel ratio
-  if (_animate_y_ratio == true) {
+  if (_animate_y_ratio) {
     _y_texel_array = PTA_float::empty_array(new_size);
     _y_texel_array = PTA_float::empty_array(new_size);
     _y_bind = G_PER_PRIM;
     _y_bind = G_PER_PRIM;
-  }
-  else {
+  } else {
     _y_texel_array = PTA_float::empty_array(1);
     _y_texel_array = PTA_float::empty_array(1);
     _y_bind = G_OVERALL;
     _y_bind = G_OVERALL;
   }
   }
 
 
   // handle the theta vector
   // handle the theta vector
-  if (_animate_theta == true) {
+  if (_animate_theta) {
     _theta_array = PTA_float::empty_array(new_size);
     _theta_array = PTA_float::empty_array(new_size);
     _theta_bind = G_PER_PRIM;
     _theta_bind = G_PER_PRIM;
-  }
-  else {
+  } else {
     _theta_array = PTA_float::empty_array(1);
     _theta_array = PTA_float::empty_array(1);
     _theta_bind = G_OVERALL;
     _theta_bind = G_OVERALL;
   }
   }
@@ -215,12 +222,6 @@ resize_pool(int new_size) {
   _vertex_array = PTA_Vertexf::empty_array(new_size);
   _vertex_array = PTA_Vertexf::empty_array(new_size);
   _color_array = PTA_Colorf::empty_array(new_size);
   _color_array = PTA_Colorf::empty_array(new_size);
 
 
-  _sprite_primitive->set_coords(_vertex_array);
-  _sprite_primitive->set_colors(_color_array, G_PER_PRIM);
-  _sprite_primitive->set_x_texel_ratio(_x_texel_array, _x_bind);
-  _sprite_primitive->set_y_texel_ratio(_y_texel_array, _y_bind);
-  _sprite_primitive->set_thetas(_theta_array, _theta_bind);
-
   init_geoms();
   init_geoms();
 }
 }
 
 
@@ -232,12 +233,97 @@ resize_pool(int new_size) {
 //               modifications
 //               modifications
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void SpriteParticleRenderer::
 void SpriteParticleRenderer::
-init_geoms(void) {
-  _sprite_primitive->set_num_prims(0);
+init_geoms() {
+  CPT(RenderState) state = _render_state;
+
+  if (use_qpgeom) {
+    PT(qpGeom) qpgeom = new qpGeom; 
+    _sprite_primitive = qpgeom;
+
+    PT(qpGeomVertexArrayFormat) array_format = new qpGeomVertexArrayFormat
+      (InternalName::get_vertex(), 3, qpGeomVertexColumn::NT_float32,
+       qpGeomVertexColumn::C_point,
+       InternalName::get_color(), 1, qpGeomVertexColumn::NT_packed_dabc,
+       qpGeomVertexColumn::C_color);
+
+    if (_animate_theta || _theta != 0.0f) {
+      array_format->add_column
+        (InternalName::get_rotate(), 1, qpGeomVertexColumn::NT_float32,
+         qpGeomVertexColumn::C_other);
+    }
+
+    _base_x_scale = _initial_x_scale;
+    _base_y_scale = _base_x_scale;
+
+    // We also scale the particle size by the number of texels used,
+    // by established convention.
+    float texel_scale = 1.0f;
+    if (_texture != (Texture *)NULL) {
+      float x_texels = _texture->get_x_size() * fabs(_ur_uv[0] - _ll_uv[0]);
+      float y_texels = _texture->get_y_size() * fabs(_ur_uv[1] - _ll_uv[1]);
+      texel_scale = x_texels;
+      _base_y_scale = _base_x_scale / y_texels * x_texels;
+    }
+
+    if (_animate_x_ratio) {
+      _base_x_scale = max(_initial_x_scale, _final_x_scale);
+      array_format->add_column
+        (InternalName::get_scale_x(), 1, qpGeomVertexColumn::NT_float32,
+         qpGeomVertexColumn::C_other);
+    }
+
+    if (_animate_y_ratio || _initial_y_scale != _base_y_scale) {
+      array_format->add_column
+        (InternalName::get_scale_y(), 1, qpGeomVertexColumn::NT_float32,
+         qpGeomVertexColumn::C_other);
+    }
+
+    CPT(qpGeomVertexFormat) format = qpGeomVertexFormat::register_format
+      (new qpGeomVertexFormat(array_format));
+
+    _vdata = new qpGeomVertexData
+      ("particles", format, qpGeomUsageHint::UH_dynamic);
+    qpgeom->set_vertex_data(_vdata);
+    _sprites = new qpGeomSprites(qpGeomUsageHint::UH_dynamic);
+    qpgeom->add_primitive(_sprites);
+
+    state = state->add_attrib(RenderModeAttrib::make(RenderModeAttrib::M_unchanged, _base_x_scale * texel_scale, true));
+
+    if (_texture != (Texture *)NULL) {
+      state = state->add_attrib(TextureAttrib::make(_texture));
+    }
+
+    // Build a matrix to convert the texture coordinates to the ll, ur
+    // space.
+    LPoint2f ul(_ll_uv[0], _ur_uv[1]);
+    LPoint2f lr(_ur_uv[0], _ll_uv[1]);
+    LVector2f sc = lr - ul;
+
+    LMatrix4f mat
+      (sc[0], 0.0f, 0.0f, 0.0f,
+       0.0f, sc[1], 0.0f, 0.0f,
+       0.0f, 0.0f,  1.0f, 0.0f,
+       ul[0], ul[1], 0.0f, 1.0f);
+    state = state->add_attrib(TexMatrixAttrib::make(mat));
+
+  } else {
+    PT(GeomSprite) sprite = new GeomSprite(get_texture());
+    _sprite_primitive = sprite;
+    _sprite_primitive->set_num_prims(0);
+
+    _sprite_primitive->set_coords(_vertex_array);
+    _sprite_primitive->set_colors(_color_array, G_PER_PRIM);
+    sprite->set_x_texel_ratio(_x_texel_array, _x_bind);
+    sprite->set_y_texel_ratio(_y_texel_array, _y_bind);
+    sprite->set_thetas(_theta_array, _theta_bind);
+    sprite->set_ll_uv(_ll_uv);
+    sprite->set_ur_uv(_ur_uv);
+    sprite->set_alpha_disable(_alpha_disable);
+  }
 
 
   GeomNode *render_node = get_render_node();
   GeomNode *render_node = get_render_node();
   render_node->remove_all_geoms();
   render_node->remove_all_geoms();
-  render_node->add_geom(_sprite_primitive, _render_state);
+  render_node->add_geom(_sprite_primitive, state);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -277,15 +363,22 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
   float *cur_x_texel = &_x_texel_array[0];
   float *cur_x_texel = &_x_texel_array[0];
   float *cur_y_texel = &_y_texel_array[0];
   float *cur_y_texel = &_y_texel_array[0];
   float *cur_theta = &_theta_array[0];
   float *cur_theta = &_theta_array[0];
-
-  if (_animate_x_ratio == false)
-    *cur_x_texel = _initial_x_texel_ratio;
-
-  if (_animate_y_ratio == false)
-    *cur_y_texel = _initial_y_texel_ratio;
-
-  if (_animate_theta == false)
-    *cur_theta = _theta;
+  qpGeomVertexWriter vertex(_vdata, InternalName::get_vertex());
+  qpGeomVertexWriter color(_vdata, InternalName::get_color());
+  qpGeomVertexWriter rotate(_vdata, InternalName::get_rotate());
+  qpGeomVertexWriter scale_x(_vdata, InternalName::get_scale_x());
+  qpGeomVertexWriter scale_y(_vdata, InternalName::get_scale_y());
+
+  if (!use_qpgeom) {
+    if (!_animate_x_ratio)
+      *cur_x_texel = _initial_x_scale;
+    
+    if (!_animate_y_ratio)
+      *cur_y_texel = _initial_y_scale;
+    
+    if (!_animate_theta)
+      *cur_theta = _theta;
+  }
 
 
   // init the aabb
   // init the aabb
   _aabb_min.set(99999.0f, 99999.0f, 99999.0f);
   _aabb_min.set(99999.0f, 99999.0f, 99999.0f);
@@ -295,31 +388,30 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
   for (i = 0; i < (int)po_vector.size(); i++) {
   for (i = 0; i < (int)po_vector.size(); i++) {
     cur_particle = (BaseParticle *) po_vector[i].p();
     cur_particle = (BaseParticle *) po_vector[i].p();
 
 
-    if (cur_particle->get_alive() == false)
+    if (!cur_particle->get_alive())
       continue;
       continue;
 
 
+    LPoint3f position = cur_particle->get_position();
+
     // x aabb adjust
     // x aabb adjust
-    if (cur_particle->get_position().get_x() > _aabb_max.get_x())
-      _aabb_max[0] = cur_particle->get_position().get_x();
-    else if (cur_particle->get_position().get_x() < _aabb_min.get_x())
-      _aabb_min[0] = cur_particle->get_position().get_x();
+    if (position[0] > _aabb_max[0])
+      _aabb_max[0] = position[0];
+    else if (position[0] < _aabb_min[0])
+      _aabb_min[0] = position[0];
 
 
     // y aabb adjust
     // y aabb adjust
-    if (cur_particle->get_position().get_y() > _aabb_max.get_y())
-      _aabb_max[1] = cur_particle->get_position().get_y();
-    else if (cur_particle->get_position().get_y() < _aabb_min.get_y())
-      _aabb_min[1] = cur_particle->get_position().get_y();
+    if (position[1] > _aabb_max[1])
+      _aabb_max[1] = position[1];
+    else if (position[1] < _aabb_min[1])
+      _aabb_min[1] = position[1];
 
 
     // z aabb adjust
     // z aabb adjust
-    if (cur_particle->get_position().get_z() > _aabb_max.get_z())
-      _aabb_max[2] = cur_particle->get_position().get_z();
-    else if (cur_particle->get_position().get_z() < _aabb_min.get_z())
-      _aabb_min[2] = cur_particle->get_position().get_z();
-
-    // put the current vertex into the array
-    *cur_vert++ = cur_particle->get_position();
+    if (position[2] > _aabb_max[2])
+      _aabb_max[2] = position[2];
+    else if (position[2] < _aabb_min[2])
+      _aabb_min[2] = position[2];
 
 
-    // put the current color into the array
+    // Calculate the color
     Colorf c = _color;
     Colorf c = _color;
 
 
     int alphamode=get_alpha_mode();
     int alphamode=get_alpha_mode();
@@ -339,41 +431,88 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
       }
       }
     }
     }
 
 
-    *cur_color++ = c;
-
-    // handle x scaling
-    if (_animate_x_ratio == true) {
-      float t = cur_particle->get_parameterized_age();
-
-      if (_blend_method == PP_BLEND_CUBIC)
-        t = CUBIC_T(t);
-
-      *cur_x_texel++ = (_initial_x_texel_ratio +
-        (t * (_final_x_texel_ratio - _initial_x_texel_ratio)));
-    }
+    if (use_qpgeom) {
+      vertex.add_data3f(position);
+      color.add_data4f(c);
+
+      if (_animate_x_ratio) {
+        float t = cur_particle->get_parameterized_age();
+        
+        if (_blend_method == PP_BLEND_CUBIC)
+          t = CUBIC_T(t);
+        
+        float scale = (_initial_x_scale +
+                       (t * (_final_x_scale - _initial_x_scale)));
+        scale_x.add_data1f(scale / _base_x_scale);
+
+      } else if (scale_x.has_column()) {
+        scale_x.add_data1f(_initial_x_scale / _base_x_scale);
+      }
 
 
-    // handle y scaling
-    if (_animate_y_ratio == true) {
-      float t = cur_particle->get_parameterized_age();
+      if (_animate_y_ratio) {
+        float t = cur_particle->get_parameterized_age();
+        
+        if (_blend_method == PP_BLEND_CUBIC)
+          t = CUBIC_T(t);
+        
+        float scale = (_initial_y_scale +
+                       (t * (_final_y_scale - _initial_y_scale)));
+        scale_y.add_data1f(scale / _base_y_scale);
+
+      } else if (scale_y.has_column()) {
+        scale_y.add_data1f(_initial_y_scale / _base_y_scale);
+      }
 
 
-      if (_blend_method == PP_BLEND_CUBIC)
-        t = CUBIC_T(t);
+      if (_animate_theta) {
+        rotate.add_data1f(cur_particle->get_theta());
+      } else if (rotate.has_column()) {
+        rotate.add_data1f(_theta);
+      }
 
 
-      *cur_y_texel++ = (_initial_y_texel_ratio +
-        (t * (_final_y_texel_ratio - _initial_y_texel_ratio)));
+    } else {
+      // put the current vertex into the array
+      *cur_vert++ = position;
+      *cur_color++ = c;
+      
+      // handle x scaling
+      if (_animate_x_ratio) {
+        float t = cur_particle->get_parameterized_age();
+        
+        if (_blend_method == PP_BLEND_CUBIC)
+          t = CUBIC_T(t);
+        
+        *cur_x_texel++ = (_initial_x_scale +
+                          (t * (_final_x_scale - _initial_x_scale)));
+      }
+      
+      // handle y scaling
+      if (_animate_y_ratio) {
+        float t = cur_particle->get_parameterized_age();
+        
+        if (_blend_method == PP_BLEND_CUBIC)
+          t = CUBIC_T(t);
+        
+        *cur_y_texel++ = (_initial_y_scale +
+                          (t * (_final_y_scale - _initial_y_scale)));
+      }
+      
+      // handle theta
+      if (_animate_theta)
+        *cur_theta++ = cur_particle->get_theta();
     }
     }
 
 
-    // handle theta
-    if (_animate_theta == true)
-      *cur_theta++ = cur_particle->get_theta();
-
     // maybe jump out early?
     // maybe jump out early?
     remaining_particles--;
     remaining_particles--;
     if (remaining_particles == 0)
     if (remaining_particles == 0)
       break;
       break;
   }
   }
 
 
-  _sprite_primitive->set_num_prims(ttl_particles);
+  if (use_qpgeom) {
+    _sprites->clear_vertices();
+    _sprites->add_next_vertices(ttl_particles);
+  } else {
+    _sprite_primitive->set_num_prims(ttl_particles);
+  }
 
 
   // done filling geompoint node, now do the bb stuff
   // done filling geompoint node, now do the bb stuff
   LPoint3f aabb_center = _aabb_min + ((_aabb_max - _aabb_min) * 0.5f);
   LPoint3f aabb_center = _aabb_min + ((_aabb_max - _aabb_min) * 0.5f);
@@ -413,10 +552,10 @@ write(ostream &out, int indent) const {
   out.width(indent+2); out<<""; out<<"_y_texel_array "<<_y_texel_array<<"\n";
   out.width(indent+2); out<<""; out<<"_y_texel_array "<<_y_texel_array<<"\n";
   out.width(indent+2); out<<""; out<<"_theta_array "<<_theta_array<<"\n";
   out.width(indent+2); out<<""; out<<"_theta_array "<<_theta_array<<"\n";
   out.width(indent+2); out<<""; out<<"_color "<<_color<<"\n";
   out.width(indent+2); out<<""; out<<"_color "<<_color<<"\n";
-  out.width(indent+2); out<<""; out<<"_initial_x_texel_ratio "<<_initial_x_texel_ratio<<"\n";
-  out.width(indent+2); out<<""; out<<"_final_x_texel_ratio "<<_final_x_texel_ratio<<"\n";
-  out.width(indent+2); out<<""; out<<"_initial_y_texel_ratio "<<_initial_y_texel_ratio<<"\n";
-  out.width(indent+2); out<<""; out<<"_final_y_texel_ratio "<<_final_y_texel_ratio<<"\n";
+  out.width(indent+2); out<<""; out<<"_initial_x_scale "<<_initial_x_scale<<"\n";
+  out.width(indent+2); out<<""; out<<"_final_x_scale "<<_final_x_scale<<"\n";
+  out.width(indent+2); out<<""; out<<"_initial_y_scale "<<_initial_y_scale<<"\n";
+  out.width(indent+2); out<<""; out<<"_final_y_scale "<<_final_y_scale<<"\n";
   out.width(indent+2); out<<""; out<<"_theta "<<_theta<<"\n";
   out.width(indent+2); out<<""; out<<"_theta "<<_theta<<"\n";
   out.width(indent+2); out<<""; out<<"_animate_x_ratio "<<_animate_x_ratio<<"\n";
   out.width(indent+2); out<<""; out<<"_animate_x_ratio "<<_animate_x_ratio<<"\n";
   out.width(indent+2); out<<""; out<<"_animate_y_ratio "<<_animate_y_ratio<<"\n";
   out.width(indent+2); out<<""; out<<"_animate_y_ratio "<<_animate_y_ratio<<"\n";

+ 19 - 8
panda/src/particlesystem/spriteParticleRenderer.h

@@ -20,15 +20,16 @@
 #define SPRITEPARTICLERENDERER_H
 #define SPRITEPARTICLERENDERER_H
 
 
 #include "pandabase.h"
 #include "pandabase.h"
+#include "baseParticleRenderer.h"
+#include "baseParticle.h"
 #include "texture.h"
 #include "texture.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "pointerToArray.h"
 #include "pointerToArray.h"
 #include "pta_float.h"
 #include "pta_float.h"
 #include "geom.h"
 #include "geom.h"
 #include "geomSprite.h"
 #include "geomSprite.h"
-
-#include "baseParticleRenderer.h"
-#include "baseParticle.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomSprites.h"
 
 
 class NodePath;
 class NodePath;
 
 
@@ -91,24 +92,34 @@ PUBLISHED:
   virtual void write(ostream &out, int indent=0) const;
   virtual void write(ostream &out, int indent=0) const;
 
 
 private:
 private:
-  PT(GeomSprite) _sprite_primitive;
+  PT(Geom) _sprite_primitive;
+  PT(qpGeomSprites) _sprites;
+  PT(Texture) _texture;
+
   PTA_Vertexf _vertex_array;
   PTA_Vertexf _vertex_array;
   PTA_Colorf _color_array;
   PTA_Colorf _color_array;
   PTA_float _x_texel_array;
   PTA_float _x_texel_array;
   PTA_float _y_texel_array;
   PTA_float _y_texel_array;
   PTA_float _theta_array;
   PTA_float _theta_array;
+  GeomBindType _x_bind, _y_bind, _theta_bind;
+  PT(qpGeomVertexData) _vdata;
 
 
   Colorf _color;
   Colorf _color;
 
 
-  float _initial_x_texel_ratio;
-  float _final_x_texel_ratio;
-  float _initial_y_texel_ratio;
-  float _final_y_texel_ratio;
+  TexCoordf _ll_uv, _ur_uv;
+  float _initial_x_scale;
+  float _final_x_scale;
+  float _initial_y_scale;
+  float _final_y_scale;
   float _theta;
   float _theta;
+  float _base_x_scale;
+  float _base_y_scale;
+  float _aspect_ratio;
 
 
   bool _animate_x_ratio;
   bool _animate_x_ratio;
   bool _animate_y_ratio;
   bool _animate_y_ratio;
   bool _animate_theta;
   bool _animate_theta;
+  bool _alpha_disable;
 
 
   ParticleRendererBlendMethod _blend_method;
   ParticleRendererBlendMethod _blend_method;
 
 

+ 25 - 4
panda/src/pgraph/renderModeAttrib.I

@@ -24,9 +24,11 @@
 //               RenderModeAttrib object.
 //               RenderModeAttrib object.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE RenderModeAttrib::
 INLINE RenderModeAttrib::
-RenderModeAttrib(RenderModeAttrib::Mode mode, float thickness) :
+RenderModeAttrib(RenderModeAttrib::Mode mode, float thickness,
+                 bool perspective) :
   _mode(mode),
   _mode(mode),
-  _thickness(thickness)
+  _thickness(thickness),
+  _perspective(perspective)
 {
 {
 }
 }
 
 
@@ -43,10 +45,29 @@ get_mode() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderModeAttrib::get_thickness
 //     Function: RenderModeAttrib::get_thickness
 //       Access: Published
 //       Access: Published
-//  Description: Returns the line width.  This is only relevant when
-//               the mode is M_wireframe.
+//  Description: Returns the line width or point thickness.  This is
+//               only relevant when rendering points or lines, such as
+//               when the mode is M_wireframe or M_point (or when
+//               rendering actual points or lines primitives in
+//               M_polygon mode).
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE float RenderModeAttrib::
 INLINE float RenderModeAttrib::
 get_thickness() const {
 get_thickness() const {
   return _thickness;
   return _thickness;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderModeAttrib::get_perspective
+//       Access: Published
+//  Description: Returns the perspective flag.  When this is true, the
+//               point thickness represented by get_thickness() is
+//               actually a width in 3-d units, and the points should
+//               scale according to perspective.  When it is false,
+//               the default, the point thickness is actually a width
+//               in pixels, and points are a uniform size regardless
+//               of distance from the camera.
+////////////////////////////////////////////////////////////////////
+INLINE bool RenderModeAttrib::
+get_perspective() const {
+  return _perspective;
+}

+ 25 - 5
panda/src/pgraph/renderModeAttrib.cxx

@@ -39,10 +39,18 @@ TypeHandle RenderModeAttrib::_type_handle;
 //               linestrip lines; it also specifies the diameter of
 //               linestrip lines; it also specifies the diameter of
 //               points.  It is not supported in DirectX, which only
 //               points.  It is not supported in DirectX, which only
 //               supports pixel-based lines and points.
 //               supports pixel-based lines and points.
+//
+//               If perspective is true, the point thickness
+//               represented is actually a width in 3-d units, and the
+//               points should scale according to perspective.  When
+//               it is false, the point thickness is actually a width
+//               in pixels, and points are a uniform size regardless
+//               of distance from the camera.  This feature is not
+//               supported by all graphics drivers.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) RenderModeAttrib::
 CPT(RenderAttrib) RenderModeAttrib::
-make(RenderModeAttrib::Mode mode, float thickness) {
-  RenderModeAttrib *attrib = new RenderModeAttrib(mode, thickness);
+make(RenderModeAttrib::Mode mode, float thickness, bool perspective) {
+  RenderModeAttrib *attrib = new RenderModeAttrib(mode, thickness, perspective);
   return return_new(attrib);
   return return_new(attrib);
 }
 }
 
 
@@ -85,6 +93,10 @@ output(ostream &out) const {
     out << "point(" << get_thickness() << ")";
     out << "point(" << get_thickness() << ")";
     break;
     break;
   }
   }
+
+  if (get_perspective()) {
+    out << ", perspective";
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -112,6 +124,9 @@ compare_to_impl(const RenderAttrib *other) const {
   if (_thickness != ta->_thickness) {
   if (_thickness != ta->_thickness) {
     return _thickness < ta->_thickness ? -1 : 1;
     return _thickness < ta->_thickness ? -1 : 1;
   }
   }
+  if (_perspective != ta->_perspective) {
+    return (int)_perspective - (int)ta->_perspective;
+  }
   return 0;
   return 0;
 }
 }
 
 
@@ -143,7 +158,7 @@ compose_impl(const RenderAttrib *other) const {
     mode = get_mode();
     mode = get_mode();
   }
   }
 
 
-  return make(mode, get_thickness());
+  return make(mode, ta->get_thickness(), ta->get_perspective());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -159,7 +174,7 @@ compose_impl(const RenderAttrib *other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 RenderAttrib *RenderModeAttrib::
 RenderAttrib *RenderModeAttrib::
 make_default_impl() const {
 make_default_impl() const {
-  return new RenderModeAttrib(M_filled, 1.0f);
+  return new RenderModeAttrib(M_filled, 1.0f, false);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -185,6 +200,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
 
 
   dg.add_int8(_mode);
   dg.add_int8(_mode);
   dg.add_float32(_thickness);
   dg.add_float32(_thickness);
+  dg.add_bool(_perspective);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -197,7 +213,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 TypedWritable *RenderModeAttrib::
 TypedWritable *RenderModeAttrib::
 make_from_bam(const FactoryParams &params) {
 make_from_bam(const FactoryParams &params) {
-  RenderModeAttrib *attrib = new RenderModeAttrib(M_filled, 0.0f);
+  RenderModeAttrib *attrib = new RenderModeAttrib(M_filled, 1.0f, false);
   DatagramIterator scan;
   DatagramIterator scan;
   BamReader *manager;
   BamReader *manager;
 
 
@@ -220,4 +236,8 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 
 
   _mode = (Mode)scan.get_int8();
   _mode = (Mode)scan.get_int8();
   _thickness = scan.get_float32();
   _thickness = scan.get_float32();
+  _perspective = false;
+  if (manager->get_file_minor_ver() >= 18) {
+    _perspective = scan.get_bool();
+  }
 }
 }

+ 5 - 2
panda/src/pgraph/renderModeAttrib.h

@@ -39,13 +39,15 @@ PUBLISHED:
   };
   };
 
 
 private:
 private:
-  INLINE RenderModeAttrib(Mode mode, float thickness);
+  INLINE RenderModeAttrib(Mode mode, float thickness, bool perspective);
 
 
 PUBLISHED:
 PUBLISHED:
-  static CPT(RenderAttrib) make(Mode mode, float thickness = 1.0f);
+  static CPT(RenderAttrib) make(Mode mode, float thickness = 1.0f,
+                                bool perspective = false);
 
 
   INLINE Mode get_mode() const;
   INLINE Mode get_mode() const;
   INLINE float get_thickness() const;
   INLINE float get_thickness() const;
+  INLINE bool get_perspective() const;
 
 
 public:
 public:
   virtual void issue(GraphicsStateGuardianBase *gsg) const;
   virtual void issue(GraphicsStateGuardianBase *gsg) const;
@@ -59,6 +61,7 @@ protected:
 private:
 private:
   Mode _mode;
   Mode _mode;
   float _thickness;
   float _thickness;
+  bool _perspective;
 
 
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();

+ 2 - 1
panda/src/putil/bam.h

@@ -34,7 +34,7 @@ static const unsigned short _bam_major_ver = 4;
 // Bumped to major version 3 on 12/8/00 to change float64's to float32's.
 // Bumped to major version 3 on 12/8/00 to change float64's to float32's.
 // Bumped to major version 4 on 4/10/02 to store new scene graph.
 // Bumped to major version 4 on 4/10/02 to store new scene graph.
 
 
-static const unsigned short _bam_minor_ver = 17;
+static const unsigned short _bam_minor_ver = 18;
 // Bumped to minor version 1 on 4/10/03 to add CullFaceAttrib::reverse.
 // Bumped to minor version 1 on 4/10/03 to add CullFaceAttrib::reverse.
 // Bumped to minor version 2 on 4/12/03 to add num_components to texture.
 // Bumped to minor version 2 on 4/12/03 to add num_components to texture.
 // Bumped to minor version 3 on 4/15/03 to add ImageBuffer::_alpha_file_channel
 // Bumped to minor version 3 on 4/15/03 to add ImageBuffer::_alpha_file_channel
@@ -52,6 +52,7 @@ static const unsigned short _bam_minor_ver = 17;
 // Bumped to minor version 15 on 1/16/05 to remove width from GeomLine, etc.
 // Bumped to minor version 15 on 1/16/05 to remove width from GeomLine, etc.
 // Bumped to minor version 16 on 2/24/05 to add TextureStage::rgb_scale, etc.
 // Bumped to minor version 16 on 2/24/05 to add TextureStage::rgb_scale, etc.
 // Bumped to minor version 17 on 3/03/05 to add 3-d textures, etc.
 // Bumped to minor version 17 on 3/03/05 to add 3-d textures, etc.
+// Bumped to minor version 18 on 4/05/05 to add RenderModeAttrib::perspective.
 
 
 
 
 #endif
 #endif