2
0
David Rose 21 жил өмнө
parent
commit
ea51a7a6f7
38 өөрчлөгдсөн 624 нэмэгдсэн , 58 устгасан
  1. 3 0
      panda/src/display/Sources.pp
  2. 18 0
      panda/src/display/colorMunger.I
  3. 101 0
      panda/src/display/colorMunger.cxx
  4. 73 0
      panda/src/display/colorMunger.h
  5. 3 1
      panda/src/display/config_display.cxx
  6. 1 0
      panda/src/display/display_composite1.cxx
  7. 4 1
      panda/src/display/graphicsStateGuardian.cxx
  8. 4 1
      panda/src/display/graphicsStateGuardian.h
  9. 3 2
      panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx
  10. 3 1
      panda/src/dxgsg8/dxGraphicsStateGuardian8.h
  11. 3 1
      panda/src/glstuff/glGeomMunger_src.I
  12. 38 1
      panda/src/glstuff/glGeomMunger_src.cxx
  13. 13 4
      panda/src/glstuff/glGeomMunger_src.h
  14. 3 2
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  15. 3 1
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  16. 1 0
      panda/src/glstuff/glmisc_src.cxx
  17. 2 1
      panda/src/gobj/drawable.cxx
  18. 2 0
      panda/src/gobj/drawable.h
  19. 2 1
      panda/src/gobj/geom.cxx
  20. 1 0
      panda/src/gobj/geom.h
  21. 3 2
      panda/src/gobj/qpgeom.cxx
  22. 1 0
      panda/src/gobj/qpgeom.h
  23. 25 1
      panda/src/gobj/qpgeomMunger.I
  24. 31 17
      panda/src/gobj/qpgeomMunger.cxx
  25. 4 1
      panda/src/gobj/qpgeomMunger.h
  26. 14 5
      panda/src/gobj/qpgeomVertexArrayFormat.cxx
  27. 4 4
      panda/src/gobj/qpgeomVertexArrayFormat.h
  28. 4 1
      panda/src/gobj/qpgeomVertexCacheManager.I
  29. 158 2
      panda/src/gobj/qpgeomVertexData.cxx
  30. 13 1
      panda/src/gobj/qpgeomVertexData.h
  31. 6 2
      panda/src/gobj/qpgeomVertexFormat.cxx
  32. 1 1
      panda/src/gobj/qpgeomVertexFormat.h
  33. 66 1
      panda/src/gobj/qpgeomVertexIterator.I
  34. 7 1
      panda/src/gobj/qpgeomVertexIterator.h
  35. 3 1
      panda/src/gsgbase/graphicsStateGuardianBase.h
  36. 1 1
      panda/src/pgraph/cullableObject.I
  37. 1 0
      panda/src/pgraph/cullableObject.cxx
  38. 1 0
      panda/src/pgraph/cullableObject.h

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

@@ -11,6 +11,7 @@
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx 
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx 
  
  
   #define SOURCES  \
   #define SOURCES  \
+    colorMunger.I colorMunger.h \
     config_display.h \
     config_display.h \
     drawableRegion.I drawableRegion.h \
     drawableRegion.I drawableRegion.h \
     displayRegion.I displayRegion.h  \
     displayRegion.I displayRegion.h  \
@@ -34,6 +35,7 @@
     lensStack.I lensStack.h
     lensStack.I lensStack.h
     
     
  #define INCLUDED_SOURCES  \
  #define INCLUDED_SOURCES  \
+    colorMunger.cxx \
     config_display.cxx \
     config_display.cxx \
     drawableRegion.cxx \
     drawableRegion.cxx \
     displayRegion.cxx \
     displayRegion.cxx \
@@ -51,6 +53,7 @@
     windowProperties.cxx
     windowProperties.cxx
 
 
   #define INSTALL_HEADERS \
   #define INSTALL_HEADERS \
+    colorMunger.I colorMunger.h \
     config_display.h \
     config_display.h \
     drawableRegion.I drawableRegion.h \
     drawableRegion.I drawableRegion.h \
     displayRegion.I displayRegion.h displayRegionStack.I \
     displayRegion.I displayRegion.h displayRegionStack.I \

+ 18 - 0
panda/src/display/colorMunger.I

@@ -0,0 +1,18 @@
+// Filename: colorMunger.I
+// Created by:  drose (21Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+

+ 101 - 0
panda/src/display/colorMunger.cxx

@@ -0,0 +1,101 @@
+// Filename: colorMunger.cxx
+// Created by:  drose (21Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "colorMunger.h"
+#include "renderState.h"
+#include "dcast.h"
+
+TypeHandle ColorMunger::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorMunger::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ColorMunger::
+ColorMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state,
+            int num_components,
+            qpGeomVertexDataType::NumericType numeric_type) :
+  qpGeomMunger(gsg, state),
+  _num_components(num_components),
+  _numeric_type(numeric_type)
+{
+  _color = state->get_color();
+  _color_scale = state->get_color_scale();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorMunger::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ColorMunger::
+~ColorMunger() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorMunger::munge_data_impl
+//       Access: Protected, Virtual
+//  Description: Given a source GeomVertexData, converts it as
+//               necessary for rendering.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomVertexData) ColorMunger::
+munge_data_impl(const qpGeomVertexData *data) {
+  CPT(qpGeomVertexData) new_data = data;
+
+  if (_color != (ColorAttrib *)NULL && 
+      _color->get_color_type() == ColorAttrib::T_flat) {
+    Colorf color = _color->get_color();
+    if (_color_scale != (ColorScaleAttrib *)NULL &&
+        _color_scale->has_scale()) {
+      const LVecBase4f &cs = _color_scale->get_scale();
+      color.set(color[0] * cs[0],
+                color[1] * cs[1],
+                color[2] * cs[2],
+                color[3] * cs[3]);
+    }
+    new_data = new_data->set_color(color, _num_components, _numeric_type);
+
+  } else if (_color_scale != (ColorScaleAttrib *)NULL &&
+             _color_scale->has_scale()) {
+    const LVecBase4f &cs = _color_scale->get_scale();
+    new_data = new_data->scale_color(cs, _num_components, _numeric_type);
+  }
+
+  return qpGeomMunger::munge_data_impl(new_data);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorMunger::compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Called to compare two GeomMungers who are known to be
+//               of the same type, for an apples-to-apples comparison.
+//               This will never be called on two pointers of a
+//               different type.
+////////////////////////////////////////////////////////////////////
+int ColorMunger::
+compare_to_impl(const qpGeomMunger *other) const {
+  const ColorMunger *om = DCAST(ColorMunger, other);
+  if (_color != om->_color) {
+    return _color < om->_color ? -1 : 1;
+  }
+  if (_color_scale != om->_color_scale) {
+    return _color_scale < om->_color_scale ? -1 : 1;
+  }
+  return 0;
+}

+ 73 - 0
panda/src/display/colorMunger.h

@@ -0,0 +1,73 @@
+// Filename: colorMunger.h
+// Created by:  drose (21Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 COLORMUNGER_H
+#define COLORMUNGER_H
+
+#include "pandabase.h"
+#include "qpgeomMunger.h"
+#include "colorAttrib.h"
+#include "colorScaleAttrib.h"
+#include "pointerTo.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ColorMunger
+// Description : Applies ColorAttrib and ColorScaleAttrib by munging
+//               the vertex data.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA ColorMunger : public qpGeomMunger {
+public:
+  ColorMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state,
+              int num_components,
+              qpGeomVertexDataType::NumericType numeric_type);
+  virtual ~ColorMunger();
+
+protected:
+  virtual CPT(qpGeomVertexData) munge_data_impl(const qpGeomVertexData *data);
+  virtual int compare_to_impl(const qpGeomMunger *other) const;
+
+private:
+  int _num_components;
+  qpGeomVertexDataType::NumericType _numeric_type;
+  CPT(ColorAttrib) _color;
+  CPT(ColorScaleAttrib) _color_scale;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    qpGeomMunger::init_type();
+    register_type(_type_handle, "ColorMunger",
+                  qpGeomMunger::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "colorMunger.I"
+
+#endif
+

+ 3 - 1
panda/src/display/config_display.cxx

@@ -18,6 +18,7 @@
 
 
 
 
 #include "config_display.h"
 #include "config_display.h"
+#include "colorMunger.h"
 #include "graphicsStateGuardian.h"
 #include "graphicsStateGuardian.h"
 #include "graphicsPipe.h"
 #include "graphicsPipe.h"
 #include "graphicsOutput.h"
 #include "graphicsOutput.h"
@@ -246,7 +247,8 @@ init_libdisplay() {
     return;
     return;
   }
   }
   initialized = true;
   initialized = true;
-
+  
+  ColorMunger::init_type();
   GraphicsStateGuardian::init_type();
   GraphicsStateGuardian::init_type();
   GraphicsPipe::init_type();
   GraphicsPipe::init_type();
   GraphicsOutput::init_type();
   GraphicsOutput::init_type();

+ 1 - 0
panda/src/display/display_composite1.cxx

@@ -1,3 +1,4 @@
+#include "colorMunger.cxx"
 #include "drawableRegion.cxx"
 #include "drawableRegion.cxx"
 #include "displayRegion.cxx"
 #include "displayRegion.cxx"
 #include "graphicsEngine.cxx"
 #include "graphicsEngine.cxx"

+ 4 - 1
panda/src/display/graphicsStateGuardian.cxx

@@ -670,7 +670,9 @@ finish_decal() {
 //               are ok, false to abort this group of primitives.
 //               are ok, false to abort this group of primitives.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GraphicsStateGuardian::
 bool GraphicsStateGuardian::
-begin_draw_primitives(const qpGeom *, const qpGeomVertexData *data) {
+begin_draw_primitives(const qpGeom *, const qpGeomMunger *munger,
+                      const qpGeomVertexData *data) {
+  _munger = munger;
   _vertex_data = data;
   _vertex_data = data;
   return true;
   return true;
 }
 }
@@ -719,6 +721,7 @@ draw_trifans(const qpGeomTrifans *primitive) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GraphicsStateGuardian::
 void GraphicsStateGuardian::
 end_draw_primitives() {
 end_draw_primitives() {
+  _munger = NULL;
   _vertex_data = NULL;
   _vertex_data = NULL;
 }
 }
 
 

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

@@ -148,7 +148,9 @@ public:
   virtual CPT(RenderState) begin_decal_base_second();
   virtual CPT(RenderState) begin_decal_base_second();
   virtual void finish_decal();
   virtual void finish_decal();
 
 
-  virtual bool begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data);
+  virtual bool begin_draw_primitives(const qpGeom *geom, 
+                                     const qpGeomMunger *munger,
+                                     const qpGeomVertexData *vertex_data);
   virtual void draw_triangles(const qpGeomTriangles *primitive);
   virtual void draw_triangles(const qpGeomTriangles *primitive);
   virtual void draw_tristrips(const qpGeomTristrips *primitive);
   virtual void draw_tristrips(const qpGeomTristrips *primitive);
   virtual void draw_trifans(const qpGeomTrifans *primitive);
   virtual void draw_trifans(const qpGeomTrifans *primitive);
@@ -251,6 +253,7 @@ protected:
 
 
   CPT(RenderState) _state;
   CPT(RenderState) _state;
   CPT(TransformState) _transform;
   CPT(TransformState) _transform;
+  CPT(qpGeomMunger) _munger;
   CPT(qpGeomVertexData) _vertex_data;
   CPT(qpGeomVertexData) _vertex_data;
 
 
   int _buffer_mask;
   int _buffer_mask;

+ 3 - 2
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -2607,10 +2607,11 @@ draw_sphere(GeomSphere *geom, GeomContext *gc) {
 //               are ok, false to abort this group of primitives.
 //               are ok, false to abort this group of primitives.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool DXGraphicsStateGuardian8::
 bool DXGraphicsStateGuardian8::
-begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data) {
+begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
+                      const qpGeomVertexData *vertex_data) {
   DO_PSTATS_STUFF(_draw_primitive_pcollector.start());
   DO_PSTATS_STUFF(_draw_primitive_pcollector.start());
 
 
-  if (!GraphicsStateGuardian::begin_draw_primitives(geom, vertex_data)) {
+  if (!GraphicsStateGuardian::begin_draw_primitives(geom, munger, vertex_data)) {
     return false;
     return false;
   }
   }
   nassertr(_vertex_data != (qpGeomVertexData *)NULL, false);
   nassertr(_vertex_data != (qpGeomVertexData *)NULL, false);

+ 3 - 1
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -90,7 +90,9 @@ public:
   virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc);
   virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc);
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
 
 
-  virtual bool begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data);
+  virtual bool begin_draw_primitives(const qpGeom *geom, 
+                                     const qpGeomMunger *munger,
+                                     const qpGeomVertexData *vertex_data);
   virtual void draw_triangles(const qpGeomTriangles *primitive);
   virtual void draw_triangles(const qpGeomTriangles *primitive);
   virtual void draw_tristrips(const qpGeomTristrips *primitive);
   virtual void draw_tristrips(const qpGeomTristrips *primitive);
   virtual void end_draw_primitives();
   virtual void end_draw_primitives();

+ 3 - 1
panda/src/glstuff/glGeomMunger_src.I

@@ -24,6 +24,8 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CLP(GeomMunger)::
 INLINE CLP(GeomMunger)::
 CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state) :
 CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state) :
-  qpGeomMunger(gsg, state)
+  ColorMunger(gsg, state, 4, qpGeomVertexDataType::NT_uint8),
+  _texture(state->get_texture()),
+  _tex_gen(state->get_tex_gen())
 {
 {
 }
 }

+ 38 - 1
panda/src/glstuff/glGeomMunger_src.cxx

@@ -16,8 +16,9 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
-TypeHandle CLP(GeomMunger)::_type_handle;
+#include "dcast.h"
 
 
+TypeHandle CLP(GeomMunger)::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GeomMunger)::munge_format_impl
 //     Function: CLP(GeomMunger)::munge_format_impl
@@ -65,3 +66,39 @@ munge_format_impl(const qpGeomVertexFormat *orig) {
 
 
   return format;
   return format;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GeomMunger)::compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Called to compare two GeomMungers who are known to be
+//               of the same type, for an apples-to-apples comparison.
+//               This will never be called on two pointers of a
+//               different type.
+////////////////////////////////////////////////////////////////////
+int CLP(GeomMunger)::
+compare_to_impl(const qpGeomMunger *other) const {
+  const CLP(GeomMunger) *om = DCAST(CLP(GeomMunger), other);
+  if (_texture != om->_texture) {
+    return _texture < om->_texture ? -1 : 1;
+  }
+  if (_tex_gen != om->_tex_gen) {
+    return _tex_gen < om->_tex_gen ? -1 : 1;
+  }
+  return ColorMunger::compare_to_impl(other);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GeomMunger)::geom_compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Called to compare two GeomMungers who are known to be
+//               of the same type, for an apples-to-apples comparison.
+//               This will never be called on two pointers of a
+//               different type.
+////////////////////////////////////////////////////////////////////
+int CLP(GeomMunger)::
+geom_compare_to_impl(const qpGeomMunger *other) const {
+  // We don't consider _texture and _tex_gen for these purposes; they
+  // affect only whether the GL display list should be regenerated or
+  // not.
+  return ColorMunger::compare_to_impl(other);
+}

+ 13 - 4
panda/src/glstuff/glGeomMunger_src.h

@@ -17,8 +17,11 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "pandabase.h"
 #include "pandabase.h"
-#include "qpgeomMunger.h"
+#include "colorMunger.h"
 #include "graphicsStateGuardian.h"
 #include "graphicsStateGuardian.h"
+#include "textureAttrib.h"
+#include "texGenAttrib.h"
+#include "renderState.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : GLGeomMunger
 //       Class : GLGeomMunger
@@ -26,21 +29,27 @@
 //               for OpenGL rendering.  In particular, it makes sure
 //               for OpenGL rendering.  In particular, it makes sure
 //               colors aren't stored in DirectX's packed_argb format.
 //               colors aren't stored in DirectX's packed_argb format.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_GL CLP(GeomMunger) : public qpGeomMunger {
+class EXPCL_GL CLP(GeomMunger) : public ColorMunger {
 public:
 public:
   INLINE CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state);
   INLINE CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state);
 
 
 protected:
 protected:
   virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig);
   virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig);
+  virtual int compare_to_impl(const qpGeomMunger *other) const;
+  virtual int geom_compare_to_impl(const qpGeomMunger *other) const;
+
+private:
+  CPT(TextureAttrib) _texture;
+  CPT(TexGenAttrib) _tex_gen;
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;
   }
   }
   static void init_type() {
   static void init_type() {
-    qpGeomMunger::init_type();
+    ColorMunger::init_type();
     register_type(_type_handle, CLASSPREFIX_QUOTED "GeomMunger",
     register_type(_type_handle, CLASSPREFIX_QUOTED "GeomMunger",
-                  qpGeomMunger::get_class_type());
+                  ColorMunger::get_class_type());
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

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

@@ -2037,8 +2037,9 @@ draw_sphere(GeomSphere *geom, GeomContext *gc) {
 //               are ok, false to abort this group of primitives.
 //               are ok, false to abort this group of primitives.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
 bool CLP(GraphicsStateGuardian)::
-begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data) {
-  if (!GraphicsStateGuardian::begin_draw_primitives(geom, vertex_data)) {
+begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
+                      const qpGeomVertexData *vertex_data) {
+  if (!GraphicsStateGuardian::begin_draw_primitives(geom, munger, vertex_data)) {
     return false;
     return false;
   }
   }
   nassertr(_vertex_data != (qpGeomVertexData *)NULL, false);
   nassertr(_vertex_data != (qpGeomVertexData *)NULL, false);

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

@@ -92,7 +92,9 @@ public:
   virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc);
   virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc);
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
 
 
-  virtual bool begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data);
+  virtual bool begin_draw_primitives(const qpGeom *geom, 
+                                     const qpGeomMunger *munger,
+                                     const qpGeomVertexData *vertex_data);
   virtual void draw_triangles(const qpGeomTriangles *primitive);
   virtual void draw_triangles(const qpGeomTriangles *primitive);
   virtual void draw_tristrips(const qpGeomTristrips *primitive);
   virtual void draw_tristrips(const qpGeomTristrips *primitive);
   virtual void end_draw_primitives();
   virtual void end_draw_primitives();

+ 1 - 0
panda/src/glstuff/glmisc_src.cxx

@@ -75,6 +75,7 @@ void CLP(init_classes)() {
   CLP(GeomContext)::init_type();
   CLP(GeomContext)::init_type();
   CLP(VertexBufferContext)::init_type();
   CLP(VertexBufferContext)::init_type();
   CLP(IndexBufferContext)::init_type();
   CLP(IndexBufferContext)::init_type();
+  CLP(GeomMunger)::init_type();
 
 
   PandaSystem *ps = PandaSystem::get_global_ptr();
   PandaSystem *ps = PandaSystem::get_global_ptr();
   ps->add_system(GLSYSTEM_NAME);
   ps->add_system(GLSYSTEM_NAME);

+ 2 - 1
panda/src/gobj/drawable.cxx

@@ -48,7 +48,8 @@ dDrawable::
 //               At this level, this doesn't do very much.
 //               At this level, this doesn't do very much.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void dDrawable::
 void dDrawable::
-draw(GraphicsStateGuardianBase *, const qpGeomVertexData *) const { 
+draw(GraphicsStateGuardianBase *, const qpGeomMunger *,
+     const qpGeomVertexData *) const { 
   if (is_dirty()) {
   if (is_dirty()) {
     ((dDrawable *)this)->config(); 
     ((dDrawable *)this)->config(); 
   }
   }

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

@@ -34,6 +34,7 @@ class Datagram;
 class DatagramIterator;
 class DatagramIterator;
 class BamReader;
 class BamReader;
 class BamWriter;
 class BamWriter;
+class qpGeomMunger;
 class qpGeomVertexData;
 class qpGeomVertexData;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -52,6 +53,7 @@ public:
   virtual ~dDrawable();
   virtual ~dDrawable();
 
 
   virtual void draw(GraphicsStateGuardianBase *gsg, 
   virtual void draw(GraphicsStateGuardianBase *gsg, 
+                    const qpGeomMunger *munger,
                     const qpGeomVertexData *vertex_data) const;
                     const qpGeomVertexData *vertex_data) const;
   virtual bool is_dynamic() const;
   virtual bool is_dynamic() const;
 
 

+ 2 - 1
panda/src/gobj/geom.cxx

@@ -915,7 +915,8 @@ release_all() {
 //  Description: Actually draws the Geom with the indicated GSG.
 //  Description: Actually draws the Geom with the indicated GSG.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void Geom::
 void Geom::
-draw(GraphicsStateGuardianBase *gsg, const qpGeomVertexData *) const {
+draw(GraphicsStateGuardianBase *gsg, 
+     const qpGeomMunger *, const qpGeomVertexData *) const {
   PreparedGraphicsObjects *prepared_objects = gsg->get_prepared_objects();
   PreparedGraphicsObjects *prepared_objects = gsg->get_prepared_objects();
   if (is_dirty()) {
   if (is_dirty()) {
     ((Geom *)this)->config(); 
     ((Geom *)this)->config(); 

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

@@ -241,6 +241,7 @@ public:
 
 
   // From parent dDrawable
   // From parent dDrawable
   virtual void draw(GraphicsStateGuardianBase *gsg, 
   virtual void draw(GraphicsStateGuardianBase *gsg, 
+                    const qpGeomMunger *munger,
                     const qpGeomVertexData *vertex_data) const;
                     const qpGeomVertexData *vertex_data) const;
 
 
   // From parent Configurable
   // From parent Configurable

+ 3 - 2
panda/src/gobj/qpgeom.cxx

@@ -354,7 +354,8 @@ clear_cache() {
 //               pre-munged to support the GSG's needs).
 //               pre-munged to support the GSG's needs).
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void qpGeom::
 void qpGeom::
-draw(GraphicsStateGuardianBase *gsg, const qpGeomVertexData *vertex_data) const {
+draw(GraphicsStateGuardianBase *gsg, const qpGeomMunger *munger,
+     const qpGeomVertexData *vertex_data) const {
 #ifdef DO_PIPELINING
 #ifdef DO_PIPELINING
   // Make sure the usage_hint is already updated before we start to
   // Make sure the usage_hint is already updated before we start to
   // draw, so we don't end up with a circular lock if the GSG asks us
   // draw, so we don't end up with a circular lock if the GSG asks us
@@ -373,7 +374,7 @@ draw(GraphicsStateGuardianBase *gsg, const qpGeomVertexData *vertex_data) const
 
 
   CDReader cdata(_cycler);
   CDReader cdata(_cycler);
   
   
-  if (gsg->begin_draw_primitives(this, vertex_data)) {
+  if (gsg->begin_draw_primitives(this, munger, vertex_data)) {
     Primitives::const_iterator pi;
     Primitives::const_iterator pi;
     for (pi = cdata->_primitives.begin(); 
     for (pi = cdata->_primitives.begin(); 
          pi != cdata->_primitives.end();
          pi != cdata->_primitives.end();

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

@@ -90,6 +90,7 @@ PUBLISHED:
 
 
 public:
 public:
   void draw(GraphicsStateGuardianBase *gsg, 
   void draw(GraphicsStateGuardianBase *gsg, 
+            const qpGeomMunger *munger,
             const qpGeomVertexData *vertex_data) const;
             const qpGeomVertexData *vertex_data) const;
 
 
   static UpdateSeq get_next_modified();
   static UpdateSeq get_next_modified();

+ 25 - 1
panda/src/gobj/qpgeomMunger.I

@@ -71,6 +71,30 @@ compare_to(const qpGeomMunger &other) const {
   return compare_to_impl(&other);
   return compare_to_impl(&other);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::geom_compare_to
+//       Access: Public
+//  Description: Compares two GeomMungers, considering only whether
+//               they would produce a different answer to
+//               munge_format(), munge_data(), or munge_geom().  (They
+//               still might be different in other ways, but if they
+//               would produce the same answer, this function consider
+//               them to be the same.)
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomMunger::
+geom_compare_to(const qpGeomMunger &other) const {
+  // First, we compare the types; if they are of different types then
+  // they sort differently.
+  TypeHandle type = get_type();
+  TypeHandle other_type = other.get_type();
+  if (type != other_type) {
+    return type.get_index() - other_type.get_index();
+  }
+
+  // We only call compare_to_impl() if they have the same type.
+  return geom_compare_to_impl(&other);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomMunger::munge_format
 //     Function: qpGeomMunger::munge_format
 //       Access: Public
 //       Access: Public
@@ -96,7 +120,7 @@ munge_data(const qpGeomVertexData *data) const {
   // We cast away the const pointer, because do_munge_data() needs to
   // We cast away the const pointer, because do_munge_data() needs to
   // update caches and stuff, but we trust it not to change any
   // update caches and stuff, but we trust it not to change any
   // user-definable parameters.
   // user-definable parameters.
-  return ((qpGeomMunger *)this)->do_munge_data(data);
+  return ((qpGeomMunger *)this)->munge_data_impl(data);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 31 - 17
panda/src/gobj/qpgeomMunger.cxx

@@ -140,13 +140,24 @@ do_munge_format(const qpGeomVertexFormat *format) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: qpGeomMunger::do_munge_data
-//       Access: Protected
-//  Description: The protected implementation of munge_data().  This
-//               exists just to cast away the const pointer.
+//     Function: qpGeomMunger::munge_format_impl
+//       Access: Protected, Virtual
+//  Description: Given a source GeomVertexFormat, converts it if
+//               necessary to the appropriate format for rendering.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomVertexFormat) qpGeomMunger::
+munge_format_impl(const qpGeomVertexFormat *orig) {
+  return orig;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::munge_data_impl
+//       Access: Protected, Virtual
+//  Description: Given a source GeomVertexData, converts it as
+//               necessary for rendering.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(qpGeomVertexData) qpGeomMunger::
 CPT(qpGeomVertexData) qpGeomMunger::
-do_munge_data(const qpGeomVertexData *data) {
+munge_data_impl(const qpGeomVertexData *data) {
   nassertr(_is_registered, NULL);
   nassertr(_is_registered, NULL);
 
 
   CPT(qpGeomVertexFormat) orig_format = data->get_format();
   CPT(qpGeomVertexFormat) orig_format = data->get_format();
@@ -160,17 +171,6 @@ do_munge_data(const qpGeomVertexData *data) {
   return data->convert_to(new_format);
   return data->convert_to(new_format);
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomMunger::munge_format_impl
-//       Access: Protected, Virtual
-//  Description: Given a source GeomVertexFormat, converts it if
-//               necessary to the appropriate format for rendering.
-////////////////////////////////////////////////////////////////////
-CPT(qpGeomVertexFormat) qpGeomMunger::
-munge_format_impl(const qpGeomVertexFormat *orig) {
-  return orig;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomMunger::munge_geom_impl
 //     Function: qpGeomMunger::munge_geom_impl
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual
@@ -178,7 +178,8 @@ munge_format_impl(const qpGeomVertexFormat *orig) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void qpGeomMunger::
 void qpGeomMunger::
 munge_geom_impl(CPT(qpGeom) &, CPT(qpGeomVertexData) &) {
 munge_geom_impl(CPT(qpGeom) &, CPT(qpGeomVertexData) &) {
-  // The default implementation does nothing.
+  // The default implementation does nothing (the work has already
+  // been done in munge_format_impl).
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -194,6 +195,19 @@ compare_to_impl(const qpGeomMunger *other) const {
   return 0;
   return 0;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::geom_compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Called to compare two GeomMungers who are known to be
+//               of the same type, for an apples-to-apples comparison.
+//               This will never be called on two pointers of a
+//               different type.
+////////////////////////////////////////////////////////////////////
+int qpGeomMunger::
+geom_compare_to_impl(const qpGeomMunger *other) const {
+  return compare_to_impl(other);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomMunger::make_registry
 //     Function: qpGeomMunger::make_registry
 //       Access: Private
 //       Access: Private

+ 4 - 1
panda/src/gobj/qpgeomMunger.h

@@ -74,14 +74,16 @@ public:
 
 
 public:
 public:
   INLINE int compare_to(const qpGeomMunger &other) const;
   INLINE int compare_to(const qpGeomMunger &other) const;
+  INLINE int geom_compare_to(const qpGeomMunger &other) const;
 
 
 protected:
 protected:
   CPT(qpGeomVertexFormat) do_munge_format(const qpGeomVertexFormat *format);
   CPT(qpGeomVertexFormat) do_munge_format(const qpGeomVertexFormat *format);
-  CPT(qpGeomVertexData) do_munge_data(const qpGeomVertexData *data);
 
 
   virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig);
   virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig);
+  virtual CPT(qpGeomVertexData) munge_data_impl(const qpGeomVertexData *data);
   virtual void munge_geom_impl(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &data);
   virtual void munge_geom_impl(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &data);
   virtual int compare_to_impl(const qpGeomMunger *other) const;
   virtual int compare_to_impl(const qpGeomMunger *other) const;
+  virtual int geom_compare_to_impl(const qpGeomMunger *other) const;
 
 
 private:
 private:
   class Registry;
   class Registry;
@@ -91,6 +93,7 @@ private:
   void do_register();
   void do_register();
   void do_unregister();
   void do_unregister();
 
 
+private:
   typedef pmap<const qpGeomVertexFormat *, const qpGeomVertexFormat *> Formats;
   typedef pmap<const qpGeomVertexFormat *, const qpGeomVertexFormat *> Formats;
   Formats _formats;
   Formats _formats;
 
 

+ 14 - 5
panda/src/gobj/qpgeomVertexArrayFormat.cxx

@@ -188,8 +188,11 @@ qpGeomVertexArrayFormat::
 //               "vertex" or "normal"; you must specify where in each
 //               "vertex" or "normal"; you must specify where in each
 //               record the table starts, and how many components
 //               record the table starts, and how many components
 //               (dimensions) exist per vertex.
 //               (dimensions) exist per vertex.
+//
+//               The return value is the index number of the new data
+//               type.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void qpGeomVertexArrayFormat::
+int qpGeomVertexArrayFormat::
 add_data_type(const InternalName *name, int num_components, 
 add_data_type(const InternalName *name, int num_components, 
               qpGeomVertexDataType::NumericType numeric_type, int start) {
               qpGeomVertexDataType::NumericType numeric_type, int start) {
   if (start < 0) {
   if (start < 0) {
@@ -200,8 +203,8 @@ add_data_type(const InternalName *name, int num_components,
     start = ((start + pad_to - 1) / pad_to) * pad_to;
     start = ((start + pad_to - 1) / pad_to) * pad_to;
   }
   }
 
 
-  add_data_type(qpGeomVertexDataType(name, num_components, 
-                                     numeric_type, start));
+  return add_data_type(qpGeomVertexDataType(name, num_components, 
+                                            numeric_type, start));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -216,10 +219,13 @@ add_data_type(const InternalName *name, int num_components,
 //               Adding a data type with the same name as a previous
 //               Adding a data type with the same name as a previous
 //               type, or that overlaps with one or more previous
 //               type, or that overlaps with one or more previous
 //               types, quietly removes the previous type(s).
 //               types, quietly removes the previous type(s).
+//
+//               The return value is the index number of the new data
+//               type.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void qpGeomVertexArrayFormat::
+int qpGeomVertexArrayFormat::
 add_data_type(const qpGeomVertexDataType &data_type) {
 add_data_type(const qpGeomVertexDataType &data_type) {
-  nassertv(!_is_registered);
+  nassertr(!_is_registered, -1);
 
 
   // Make sure there isn't already a data type with this name.
   // Make sure there isn't already a data type with this name.
   remove_data_type(data_type.get_name());
   remove_data_type(data_type.get_name());
@@ -242,8 +248,11 @@ add_data_type(const qpGeomVertexDataType &data_type) {
     _data_types_unsorted = true;
     _data_types_unsorted = true;
   }
   }
 
 
+  int new_index = (int)_data_types.size();
   _data_types.push_back(new_data_type);
   _data_types.push_back(new_data_type);
   _data_types_by_name.insert(DataTypesByName::value_type(new_data_type->get_name(), new_data_type));
   _data_types_by_name.insert(DataTypesByName::value_type(new_data_type->get_name(), new_data_type));
+
+  return new_index;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 4 - 4
panda/src/gobj/qpgeomVertexArrayFormat.h

@@ -83,10 +83,10 @@ PUBLISHED:
   INLINE int get_total_bytes() const;
   INLINE int get_total_bytes() const;
   INLINE int get_pad_to() const;
   INLINE int get_pad_to() const;
 
 
-  void add_data_type(const InternalName *name, int num_components,
-                     qpGeomVertexDataType::NumericType numeric_type,
-                     int start = -1);
-  void add_data_type(const qpGeomVertexDataType &data_type);
+  int add_data_type(const InternalName *name, int num_components,
+                    qpGeomVertexDataType::NumericType numeric_type,
+                    int start = -1);
+  int add_data_type(const qpGeomVertexDataType &data_type);
   void remove_data_type(const InternalName *name);
   void remove_data_type(const InternalName *name);
   void clear_data_types();
   void clear_data_types();
 
 

+ 4 - 1
panda/src/gobj/qpgeomVertexCacheManager.I

@@ -286,7 +286,10 @@ operator < (const qpGeomVertexCacheManager::Entry &other) const {
     if (_u._geom._source != other._u._geom._source) {
     if (_u._geom._source != other._u._geom._source) {
       return _u._geom._source < other._u._geom._source;
       return _u._geom._source < other._u._geom._source;
     }
     }
-    return _u._geom._modifier < other._u._geom._modifier;
+    if (_u._geom._modifier != other._u._geom._modifier) {
+      return _u._geom._modifier->geom_compare_to(*other._u._geom._modifier) < 0;
+    }
+    return 0;
   }
   }
 
 
   return false;
   return false;

+ 158 - 2
panda/src/gobj/qpgeomVertexData.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "qpgeomVertexData.h"
 #include "qpgeomVertexData.h"
+#include "qpgeomVertexIterator.h"
 #include "pStatTimer.h"
 #include "pStatTimer.h"
 #include "bamReader.h"
 #include "bamReader.h"
 #include "bamWriter.h"
 #include "bamWriter.h"
@@ -24,7 +25,9 @@
 
 
 TypeHandle qpGeomVertexData::_type_handle;
 TypeHandle qpGeomVertexData::_type_handle;
 
 
-PStatCollector qpGeomVertexData::_munge_data_pcollector("Cull:Munge:Data");
+PStatCollector qpGeomVertexData::_convert_pcollector("Cull:Munge:Convert");
+PStatCollector qpGeomVertexData::_scale_color_pcollector("Cull:Munge:Scale color");
+PStatCollector qpGeomVertexData::_set_color_pcollector("Cull:Munge:Set color");
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexData::Default Constructor
 //     Function: qpGeomVertexData::Default Constructor
@@ -219,7 +222,7 @@ convert_to(const qpGeomVertexFormat *new_format) const {
     gobj_cat.debug()
     gobj_cat.debug()
       << "Converting " << num_vertices << " vertices.\n";
       << "Converting " << num_vertices << " vertices.\n";
   }
   }
-  PStatTimer timer(_munge_data_pcollector);
+  PStatTimer timer(_convert_pcollector);
 
 
   PT(qpGeomVertexData) new_data = 
   PT(qpGeomVertexData) new_data = 
     new qpGeomVertexData(new_format, get_usage_hint());
     new qpGeomVertexData(new_format, get_usage_hint());
@@ -287,6 +290,159 @@ convert_to(const qpGeomVertexFormat *new_format) const {
   return new_data;
   return new_data;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::scale_color
+//       Access: Published
+//  Description: Returns a new GeomVertexData object with the color
+//               table replaced with a new color table that has been
+//               scaled by the indicated value.  The new color table
+//               will be added as a new array; if the old color table
+//               was interleaved with a previous array, the previous
+//               array will not be repacked.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomVertexData) qpGeomVertexData::
+scale_color(const LVecBase4f &color_scale, int num_components,
+            qpGeomVertexDataType::NumericType numeric_type) const {
+  int old_color_array = _format->get_array_with(InternalName::get_color());
+  if (old_color_array == -1) {
+    // Oops, no color anyway.
+    return this;
+  }
+
+  int num_vertices = get_num_vertices();
+
+  if (gobj_cat.is_debug()) {
+    gobj_cat.debug()
+      << "Scaling color for " << num_vertices << " vertices by "
+      << color_scale << ".\n";
+  }
+  PStatTimer timer(_scale_color_pcollector);
+
+  PT(qpGeomVertexData) new_data = replace_data_type
+    (InternalName::get_color(), num_components, numeric_type);
+
+  // Now go through and apply the scale, copying it to the new data.
+  qpGeomVertexIterator from(this, InternalName::get_color());
+  qpGeomVertexIterator to(new_data, InternalName::get_color());
+
+  for (int i = 0; i < num_vertices; i++) {
+    Colorf color = from.get_data4();
+    to.set_data4(color[0] * color_scale[0],
+                 color[1] * color_scale[1],
+                 color[2] * color_scale[2],
+                 color[3] * color_scale[3]);
+  }
+
+  return new_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::set_color
+//       Access: Published
+//  Description: Returns a new GeomVertexData object with the color
+//               table replaced with a new color table for which each
+//               vertex has the indicated value.  The new color table
+//               will be added as a new array; if the old color table
+//               was interleaved with a previous array, the previous
+//               array will not be repacked.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomVertexData) qpGeomVertexData::
+set_color(const Colorf &color, int num_components,
+          qpGeomVertexDataType::NumericType numeric_type) const {
+  int num_vertices = get_num_vertices();
+
+  if (gobj_cat.is_debug()) {
+    gobj_cat.debug()
+      << "Setting color for " << num_vertices << " vertices to "
+      << color << ".\n";
+  }
+  PStatTimer timer(_set_color_pcollector);
+
+  PT(qpGeomVertexData) new_data = replace_data_type
+    (InternalName::get_color(), num_components, numeric_type);
+
+  // Now go through and set the new color value.
+  qpGeomVertexIterator to(new_data, InternalName::get_color());
+
+  for (int i = 0; i < num_vertices; i++) {
+    to.set_data4(color);
+  }
+
+  return new_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::replace_data_type
+//       Access: Published
+//  Description: Returns a new GeomVertexData object, suitable for
+//               modification, with the indicated data type replaced
+//               with a new table filled with undefined values.  The
+//               new table will be added as a new array; if the old
+//               table was interleaved with a previous array, the
+//               previous array will not be repacked.
+////////////////////////////////////////////////////////////////////
+PT(qpGeomVertexData) qpGeomVertexData::
+replace_data_type(const InternalName *name, int num_components,
+                  qpGeomVertexDataType::NumericType numeric_type) const {
+  PT(qpGeomVertexFormat) new_format = new qpGeomVertexFormat(*_format);
+
+  // Remove the old description of the type from the format.
+  bool removed_type_array = false;
+  int old_type_array = _format->get_array_with(name);
+  if (old_type_array != -1) {
+    qpGeomVertexArrayFormat *array_format = new_format->modify_array(old_type_array);
+    if (array_format->get_num_data_types() == 1) {
+      // Actually, this array didn't have any other data types, so
+      // just drop the whole array.
+      new_format->remove_array(old_type_array);
+      removed_type_array = true;
+      
+    } else {
+      // Remove the description for the type, but don't bother to
+      // repack the array.
+      array_format->remove_data_type(name);
+    }
+  }
+    
+  // Now define a new array to contain just the type.
+  PT(qpGeomVertexArrayFormat) type_array_format = 
+    new qpGeomVertexArrayFormat(name, num_components, numeric_type);
+  int new_type_array = new_format->add_array(type_array_format);
+  
+  PT(qpGeomVertexData) new_data = 
+    new qpGeomVertexData(qpGeomVertexFormat::register_format(new_format),
+                         get_usage_hint());
+
+  int j = 0;
+  int num_arrays = get_num_arrays();
+  for (int i = 0; i < num_arrays; ++i) {
+    if (i == old_type_array) {
+      if (!removed_type_array) {
+        // Pointer-copy the original array that includes the type
+        // (since it also includes other data).
+        new_data->set_array(j, get_array(i));
+        ++j;
+      }
+
+    } else {
+      // Just pointer-copy any arrays other than type.
+      new_data->set_array(j, get_array(i));
+      ++j;
+    }
+  }
+
+  nassertr(j == new_type_array, new_data);
+
+  // For the new type array, we set up a temporary array that has
+  // room for the right number of vertices.
+  PT(qpGeomVertexArrayData) new_array = new qpGeomVertexArrayData
+    (new_format->get_array(j), get_usage_hint());
+  new_array->set_num_vertices(get_num_vertices());
+  new_data->set_array(j, new_array);
+
+  return new_data;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexData::output
 //     Function: qpGeomVertexData::output
 //       Access: Published
 //       Access: Published

+ 13 - 1
panda/src/gobj/qpgeomVertexData.h

@@ -85,6 +85,16 @@ PUBLISHED:
   INLINE UpdateSeq get_modified() const;
   INLINE UpdateSeq get_modified() const;
 
 
   CPT(qpGeomVertexData) convert_to(const qpGeomVertexFormat *new_format) const;
   CPT(qpGeomVertexData) convert_to(const qpGeomVertexFormat *new_format) const;
+  CPT(qpGeomVertexData) 
+    scale_color(const LVecBase4f &color_scale, int num_components,
+                qpGeomVertexDataType::NumericType numeric_type) const;
+  CPT(qpGeomVertexData) 
+    set_color(const Colorf &color, int num_components,
+              qpGeomVertexDataType::NumericType numeric_type) const;
+
+  PT(qpGeomVertexData) 
+    replace_data_type(const InternalName *name, int num_components,
+                      qpGeomVertexDataType::NumericType numeric_type) const;
 
 
   void output(ostream &out) const;
   void output(ostream &out) const;
   void write(ostream &out, int indent_level = 0) const;
   void write(ostream &out, int indent_level = 0) const;
@@ -135,7 +145,9 @@ private:
 private:
 private:
   bool do_set_num_vertices(int n, CDWriter &cdata);
   bool do_set_num_vertices(int n, CDWriter &cdata);
 
 
-  static PStatCollector _munge_data_pcollector;
+  static PStatCollector _convert_pcollector;
+  static PStatCollector _scale_color_pcollector;
+  static PStatCollector _set_color_pcollector;
 
 
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();

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

@@ -138,12 +138,16 @@ remove_array(int array) {
 //       Access: Published
 //       Access: Published
 //  Description: Adds the indicated array definition to the list of
 //  Description: Adds the indicated array definition to the list of
 //               arrays included within this vertex format definition.
 //               arrays included within this vertex format definition.
+//               The return value is the index number of the new
+//               array.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void qpGeomVertexFormat::
+int qpGeomVertexFormat::
 add_array(qpGeomVertexArrayFormat *array_format) {
 add_array(qpGeomVertexArrayFormat *array_format) {
-  nassertv(!_is_registered);
+  nassertr(!_is_registered, -1);
 
 
+  int new_array = (int)_arrays.size();
   _arrays.push_back(array_format);
   _arrays.push_back(array_format);
+  return new_array;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/gobj/qpgeomVertexFormat.h

@@ -71,7 +71,7 @@ PUBLISHED:
   qpGeomVertexArrayFormat *modify_array(int array);
   qpGeomVertexArrayFormat *modify_array(int array);
   void set_array(int array, qpGeomVertexArrayFormat *format);
   void set_array(int array, qpGeomVertexArrayFormat *format);
   void remove_array(int array);
   void remove_array(int array);
-  void add_array(qpGeomVertexArrayFormat *array_format);
+  int add_array(qpGeomVertexArrayFormat *array_format);
   void clear_arrays();
   void clear_arrays();
 
 
   int get_num_data_types() const;
   int get_num_data_types() const;

+ 66 - 1
panda/src/gobj/qpgeomVertexIterator.I

@@ -26,6 +26,7 @@
 INLINE qpGeomVertexIterator::
 INLINE qpGeomVertexIterator::
 qpGeomVertexIterator(qpGeomVertexData *data) :
 qpGeomVertexIterator(qpGeomVertexData *data) :
   _data(data),
   _data(data),
+  _const_data(false),
   _array(0),
   _array(0),
   _data_type(NULL),
   _data_type(NULL),
   _start_vertex(0),
   _start_vertex(0),
@@ -44,6 +45,7 @@ qpGeomVertexIterator(qpGeomVertexData *data) :
 INLINE qpGeomVertexIterator::
 INLINE qpGeomVertexIterator::
 qpGeomVertexIterator(qpGeomVertexData *data, const string &name) :
 qpGeomVertexIterator(qpGeomVertexData *data, const string &name) :
   _data(data),
   _data(data),
+  _const_data(false),
   _array(0),
   _array(0),
   _data_type(NULL),
   _data_type(NULL),
   _start_vertex(0),
   _start_vertex(0),
@@ -63,6 +65,65 @@ qpGeomVertexIterator(qpGeomVertexData *data, const string &name) :
 INLINE qpGeomVertexIterator::
 INLINE qpGeomVertexIterator::
 qpGeomVertexIterator(qpGeomVertexData *data, const InternalName *name) :
 qpGeomVertexIterator(qpGeomVertexData *data, const InternalName *name) :
   _data(data),
   _data(data),
+  _const_data(false),
+  _array(0),
+  _data_type(NULL),
+  _start_vertex(0),
+  _read_vertex(0),
+  _write_vertex(0)
+{
+  set_data_type(name);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::Constructor
+//       Access: Published
+//  Description: Constructs a new iterator to process the vertices of
+//               the indicated data object.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexIterator::
+qpGeomVertexIterator(const qpGeomVertexData *data) :
+  _data((qpGeomVertexData *)data),
+  _const_data(true),
+  _array(0),
+  _data_type(NULL),
+  _start_vertex(0),
+  _read_vertex(0),
+  _write_vertex(0)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::Constructor
+//       Access: Published
+//  Description: Constructs a new iterator to process the vertices of
+//               the indicated data object.  This flavor creates the
+//               iterator specifically to process the named data type.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexIterator::
+qpGeomVertexIterator(const qpGeomVertexData *data, const string &name) :
+  _data((qpGeomVertexData *)data),
+  _const_data(true),
+  _array(0),
+  _data_type(NULL),
+  _start_vertex(0),
+  _read_vertex(0),
+  _write_vertex(0)
+{
+  set_data_type(name);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::Constructor
+//       Access: Published
+//  Description: Constructs a new iterator to process the vertices of
+//               the indicated data object.  This flavor creates the
+//               iterator specifically to process the named data type.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexIterator::
+qpGeomVertexIterator(const qpGeomVertexData *data, const InternalName *name) :
+  _data((qpGeomVertexData *)data),
+  _const_data(true),
   _array(0),
   _array(0),
   _data_type(NULL),
   _data_type(NULL),
   _start_vertex(0),
   _start_vertex(0),
@@ -78,7 +139,7 @@ qpGeomVertexIterator(qpGeomVertexData *data, const InternalName *name) :
 //  Description: Returns the current data object that the iterator is
 //  Description: Returns the current data object that the iterator is
 //               processing.
 //               processing.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE qpGeomVertexData *qpGeomVertexIterator::
+INLINE const qpGeomVertexData *qpGeomVertexIterator::
 get_data() const {
 get_data() const {
   return _data;
   return _data;
 }
 }
@@ -237,6 +298,7 @@ get_write_vertex() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void qpGeomVertexIterator::
 INLINE void qpGeomVertexIterator::
 set_data1(float data) {
 set_data1(float data) {
+  nassertv(!_const_data);
   _data->set_data(_array, _data_type, _write_vertex, &data, 1);
   _data->set_data(_array, _data_type, _write_vertex, &data, 1);
   ++_write_vertex;
   ++_write_vertex;
 }
 }
@@ -260,6 +322,7 @@ set_data2(float x, float y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void qpGeomVertexIterator::
 INLINE void qpGeomVertexIterator::
 set_data2(const LVecBase2f &data) {
 set_data2(const LVecBase2f &data) {
+  nassertv(!_const_data);
   _data->set_data(_array, _data_type, _write_vertex, data.get_data(), 2);
   _data->set_data(_array, _data_type, _write_vertex, data.get_data(), 2);
   ++_write_vertex;
   ++_write_vertex;
 }
 }
@@ -283,6 +346,7 @@ set_data3(float x, float y, float z) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void qpGeomVertexIterator::
 INLINE void qpGeomVertexIterator::
 set_data3(const LVecBase3f &data) {
 set_data3(const LVecBase3f &data) {
+  nassertv(!_const_data);
   _data->set_data(_array, _data_type, _write_vertex, data.get_data(), 3);
   _data->set_data(_array, _data_type, _write_vertex, data.get_data(), 3);
   ++_write_vertex;
   ++_write_vertex;
 }
 }
@@ -306,6 +370,7 @@ set_data4(float x, float y, float z, float w) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void qpGeomVertexIterator::
 INLINE void qpGeomVertexIterator::
 set_data4(const LVecBase4f &data) {
 set_data4(const LVecBase4f &data) {
+  nassertv(!_const_data);
   _data->set_data(_array, _data_type, _write_vertex, data.get_data(), 4);
   _data->set_data(_array, _data_type, _write_vertex, data.get_data(), 4);
   ++_write_vertex;
   ++_write_vertex;
 }
 }

+ 7 - 1
panda/src/gobj/qpgeomVertexIterator.h

@@ -41,8 +41,13 @@ PUBLISHED:
                               const string &name);
                               const string &name);
   INLINE qpGeomVertexIterator(qpGeomVertexData *data,
   INLINE qpGeomVertexIterator(qpGeomVertexData *data,
                               const InternalName *name);
                               const InternalName *name);
+  INLINE qpGeomVertexIterator(const qpGeomVertexData *data);
+  INLINE qpGeomVertexIterator(const qpGeomVertexData *data,
+                              const string &name);
+  INLINE qpGeomVertexIterator(const qpGeomVertexData *data,
+                              const InternalName *name);
 
 
-  INLINE qpGeomVertexData *get_data() const;
+  INLINE const qpGeomVertexData *get_data() const;
 
 
   INLINE void set_data_type(int data_type);
   INLINE void set_data_type(int data_type);
   INLINE void set_data_type(const string &name);
   INLINE void set_data_type(const string &name);
@@ -73,6 +78,7 @@ PUBLISHED:
 
 
 private:
 private:
   PT(qpGeomVertexData) _data;
   PT(qpGeomVertexData) _data;
+  bool _const_data;
   int _array;
   int _array;
   const qpGeomVertexDataType *_data_type;
   const qpGeomVertexDataType *_data_type;
 
 

+ 3 - 1
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -184,7 +184,9 @@ public:
   virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc)=0;
   virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc)=0;
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc)=0;
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc)=0;
 
 
-  virtual bool begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data)=0;
+  virtual bool begin_draw_primitives(const qpGeom *geom, 
+                                     const qpGeomMunger *munger,
+                                     const qpGeomVertexData *vertex_data)=0;
   virtual void draw_triangles(const qpGeomTriangles *primitive)=0;
   virtual void draw_triangles(const qpGeomTriangles *primitive)=0;
   virtual void draw_tristrips(const qpGeomTristrips *primitive)=0;
   virtual void draw_tristrips(const qpGeomTristrips *primitive)=0;
   virtual void draw_trifans(const qpGeomTrifans *primitive)=0;
   virtual void draw_trifans(const qpGeomTrifans *primitive)=0;

+ 1 - 1
panda/src/pgraph/cullableObject.I

@@ -124,7 +124,7 @@ munge_geom(GraphicsStateGuardianBase *gsg) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void CullableObject::
 INLINE void CullableObject::
 draw(GraphicsStateGuardianBase *gsg) {
 draw(GraphicsStateGuardianBase *gsg) {
-  _geom->draw(gsg, _munged_data);
+  _geom->draw(gsg, _munger, _munged_data);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

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

@@ -35,6 +35,7 @@ munge_geom(const qpGeomMunger *munger) {
     // Temporary test and dcast until the experimental Geom rewrite
     // Temporary test and dcast until the experimental Geom rewrite
     // becomes the actual Geom rewrite.
     // becomes the actual Geom rewrite.
     if (_geom->is_exact_type(qpGeom::get_class_type())) {
     if (_geom->is_exact_type(qpGeom::get_class_type())) {
+      _munger = munger;
       CPT(qpGeom) qpgeom = DCAST(qpGeom, _geom);
       CPT(qpGeom) qpgeom = DCAST(qpGeom, _geom);
       qpgeom->munge_geom(munger, qpgeom, _munged_data);
       qpgeom->munge_geom(munger, qpgeom, _munged_data);
       _geom = qpgeom;
       _geom = qpgeom;

+ 1 - 0
panda/src/pgraph/cullableObject.h

@@ -74,6 +74,7 @@ PUBLISHED:
 
 
 public:
 public:
   CPT(Geom) _geom;
   CPT(Geom) _geom;
+  CPT(qpGeomMunger) _munger;
   CPT(qpGeomVertexData) _munged_data;
   CPT(qpGeomVertexData) _munged_data;
   CPT(RenderState) _state;
   CPT(RenderState) _state;
   CPT(TransformState) _transform;
   CPT(TransformState) _transform;