Browse Source

color-scale-via-lighting

David Rose 20 years ago
parent
commit
a2eb3859cb

+ 11 - 0
panda/src/display/config_display.cxx

@@ -158,6 +158,17 @@ ConfigVariableBool auto_generate_mipmaps
           "false by default because some drivers (Intel) seem to do a "
           "false by default because some drivers (Intel) seem to do a "
           "poor job of generating mipmaps when needed."));
           "poor job of generating mipmaps when needed."));
 
 
+ConfigVariableBool color_scale_via_lighting
+("color-scale-via-lighting", true,
+ PRC_DESC("When this is true, Panda will try to implement ColorAttribs and "
+          "ColorScaleAttribs using the lighting interface, by "
+          "creating a default material and/or an ambient light if "
+          "necessary, even if lighting is ostensibly disabled.  This "
+          "avoids the need to munge the vertex data to change each vertex's "
+          "color.  Set this false to avoid this trickery, so that lighting "
+          "is only enabled when the application specifically enables "
+          "it."));
+
 ConfigVariableInt win_size
 ConfigVariableInt win_size
 ("win-size", "640 480",
 ("win-size", "640 480",
  PRC_DESC("This is the default size at which to open a new window.  This "
  PRC_DESC("This is the default size at which to open a new window.  This "

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

@@ -57,6 +57,7 @@ extern EXPCL_PANDA ConfigVariableBool copy_texture_inverted;
 extern EXPCL_PANDA ConfigVariableBool window_inverted;
 extern EXPCL_PANDA ConfigVariableBool window_inverted;
 extern EXPCL_PANDA ConfigVariableBool depth_offset_decals;
 extern EXPCL_PANDA ConfigVariableBool depth_offset_decals;
 extern EXPCL_PANDA ConfigVariableBool auto_generate_mipmaps;
 extern EXPCL_PANDA ConfigVariableBool auto_generate_mipmaps;
+extern EXPCL_PANDA ConfigVariableBool color_scale_via_lighting;
 
 
 extern EXPCL_PANDA ConfigVariableInt win_size;
 extern EXPCL_PANDA ConfigVariableInt win_size;
 extern EXPCL_PANDA ConfigVariableInt win_origin;
 extern EXPCL_PANDA ConfigVariableInt win_origin;

+ 13 - 0
panda/src/display/graphicsStateGuardian.I

@@ -316,6 +316,19 @@ get_supports_render_texture() const {
   return _supports_render_texture;
   return _supports_render_texture;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_color_scale_via_lighting
+//       Access: Published
+//  Description: Returns true if this particular GSG can implement (or
+//               would prefer to implement) set color and/or color
+//               scale using materials and/or ambient lights, or
+//               false if we need to actually munge the color.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsStateGuardian::
+get_color_scale_via_lighting() const {
+  return _color_scale_via_lighting;
+}
+
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::set_scene
 //     Function: GraphicsStateGuardian::set_scene

+ 275 - 139
panda/src/display/graphicsStateGuardian.cxx

@@ -131,6 +131,17 @@ GraphicsStateGuardian(const FrameBufferProperties &properties,
   _supports_render_texture = false;
   _supports_render_texture = false;
 
 
   _supported_geom_rendering = 0;
   _supported_geom_rendering = 0;
+
+  // If this is true, then we can apply a color and/or color scale by
+  // twiddling the material and/or ambient light (which could mean
+  // enabling lighting even without a LightAttrib).
+  _color_scale_via_lighting = color_scale_via_lighting;
+
+  if (!use_qpgeom) {
+    // The old Geom interface doesn't really work too well with the
+    // color_scale_via_lighting trick.
+    _color_scale_via_lighting = false;
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -223,6 +234,14 @@ reset() {
   _blend_mode_stale = false;
   _blend_mode_stale = false;
   _pending_texture = NULL;
   _pending_texture = NULL;
   _texture_stale = false;
   _texture_stale = false;
+  _pending_light = NULL;
+  _light_stale = false;
+  _pending_material = NULL;
+  _material_stale = false;
+
+  _has_material_force_color = false;
+  _material_force_color.set(1.0f, 1.0f, 1.0f, 1.0f);
+  _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -356,7 +375,7 @@ release_index_buffer(IndexBufferContext *) {
 //  Description: Creates a new GeomMunger object to munge vertices
 //  Description: Creates a new GeomMunger object to munge vertices
 //               appropriate to this GSG for the indicated state.
 //               appropriate to this GSG for the indicated state.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-CPT(qpGeomMunger) GraphicsStateGuardian::
+PT(qpGeomMunger) GraphicsStateGuardian::
 get_geom_munger(const RenderState *state) {
 get_geom_munger(const RenderState *state) {
   // The default implementation returns no munger at all, but
   // The default implementation returns no munger at all, but
   // presumably, every kind of GSG needs some special munging action,
   // presumably, every kind of GSG needs some special munging action,
@@ -886,6 +905,12 @@ issue_color_scale(const ColorScaleAttrib *attrib) {
   if (_texture_involves_color_scale) {
   if (_texture_involves_color_scale) {
     _texture_stale = true;
     _texture_stale = true;
   }
   }
+  if (_color_scale_via_lighting) {
+    _light_stale = true;
+    _material_stale = true;
+
+    determine_light_color_scale();
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -929,153 +954,39 @@ issue_color(const ColorAttrib *attrib) {
     _vertex_colors_enabled = true;
     _vertex_colors_enabled = true;
     break;
     break;
   }
   }
+
+  if (_color_scale_via_lighting) {
+    _light_stale = true;
+    _material_stale = true;
+
+    determine_light_color_scale();
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::issue_light
 //     Function: GraphicsStateGuardian::issue_light
 //       Access: Public, Virtual
 //       Access: Public, Virtual
-//  Description: The default implementation of issue_light() assumes
-//               we have a limited number of hardware lights
-//               available.  This function assigns each light to a
-//               different hardware light id, trying to keep each
-//               light associated with the same id where possible, but
-//               reusing id's when necessary.  When it is no longer
-//               possible to reuse existing id's (e.g. all id's are in
-//               use), slot_new_light() is called to prepare the next
-//               sequential light id.
-//
-//               It will call apply_light() each time a light is
-//               assigned to a particular id for the first time in a
-//               given frame, and it will subsequently call
-//               enable_light() to enable or disable each light as the
-//               frame is rendered, as well as enable_lighting() to
-//               enable or disable overall lighting.
-//
-//               If this model of hardware lights with id's does not
-//               apply to a particular graphics engine, it should
-//               override this function to do something more
-//               appropriate instead.
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GraphicsStateGuardian::
 void GraphicsStateGuardian::
 issue_light(const LightAttrib *attrib) {
 issue_light(const LightAttrib *attrib) {
-  // Initialize the current ambient light total and newly enabled
-  // light list
-  Colorf cur_ambient_light(0.0f, 0.0f, 0.0f, 1.0f);
-  int i;
-  int max_lights = (int)_light_info.size();
-  for (i = 0; i < max_lights; i++) {
-    _light_info[i]._next_enabled = false;
-  }
-
-  bool any_bound = false;
-
-  int num_enabled = 0;
-  int num_on_lights = attrib->get_num_on_lights();
-  for (int li = 0; li < num_on_lights; li++) {
-    NodePath light = attrib->get_on_light(li);
-    nassertv(!light.is_empty() && light.node()->as_light() != (Light *)NULL);
-    Light *light_obj = light.node()->as_light();
-
-    num_enabled++;
-
-    // Lighting should be enabled before we apply any lights.
-    enable_lighting(true);
-    _lighting_enabled = true;
-    _lighting_enabled_this_frame = true;
-
-    if (light_obj->get_type() == AmbientLight::get_class_type()) {
-      // Ambient lights don't require specific light ids; simply add
-      // in the ambient contribution to the current total
-      cur_ambient_light += light_obj->get_color();
-        
-    } else {
-      // Check to see if this light has already been bound to an id
-      int cur_light_id = -1;
-      for (i = 0; i < max_lights; i++) {
-        if (_light_info[i]._light == light) {
-          // Light has already been bound to an id, we only need to
-          // enable the light, not reapply it.
-          cur_light_id = -2;
-          enable_light(i, true);
-          _light_info[i]._enabled = true;
-          _light_info[i]._next_enabled = true;
-          break;
-        }
-      }
-        
-      // See if there are any unbound light ids
-      if (cur_light_id == -1) {
-        for (i = 0; i < max_lights; i++) {
-          if (_light_info[i]._light.is_empty()) {
-            _light_info[i]._light = light;
-            cur_light_id = i;
-            break;
-          }
-        }
-      }
-        
-      // If there were no unbound light ids, see if we can replace
-      // a currently unused but previously bound id
-      if (cur_light_id == -1) {
-        for (i = 0; i < max_lights; i++) {
-          if (!attrib->has_on_light(_light_info[i]._light)) {
-            _light_info[i]._light = light;
-            cur_light_id = i;
-            break;
-          }
-        }
-      }
-
-      // If we *still* don't have a light id, slot a new one.
-      if (cur_light_id == -1) {
-        if (slot_new_light(max_lights)) {
-          cur_light_id = max_lights;
-          _light_info.push_back(LightInfo());
-          max_lights++;
-          nassertv(max_lights == (int)_light_info.size());
-        }
-      }
-        
-      if (cur_light_id >= 0) {
-        enable_light(cur_light_id, true);
-        _light_info[cur_light_id]._enabled = true;
-        _light_info[cur_light_id]._next_enabled = true;
-        
-        if (!any_bound) {
-          begin_bind_lights();
-          any_bound = true;
-        }
-
-        // This is the first time this frame that this light has been
-        // bound to this particular id.
-        light_obj->bind(this, light, cur_light_id);
-
-      } else if (cur_light_id == -1) {
-        gsg_cat.warning()
-          << "Failed to bind " << light << " to id.\n";
-      }
-    }
-  }
-
-  // Disable all unused lights
-  for (i = 0; i < max_lights; i++) {
-    if (!_light_info[i]._next_enabled) {
-      enable_light(i, false);
-      _light_info[i]._enabled = false;
-    }
-  }
-
-  // If no lights were enabled, disable lighting
-  if (num_enabled == 0) {
-    enable_lighting(false);
-    _lighting_enabled = false;
-  } else {
-    set_ambient_light(cur_ambient_light);
-  }
+  // By default, we don't apply the light attrib right away, since
+  // it might have a dependency on the current ColorScaleAttrib.
+  _pending_light = attrib;
+  _light_stale = true;
+}
 
 
-  if (any_bound) {
-    end_bind_lights();
-  }
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::issue_material
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+issue_material(const MaterialAttrib *attrib) {
+  // By default, we don't apply the material attrib right away, since
+  // it might have a dependency on the current ColorScaleAttrib.
+  _pending_material = attrib;
+  _material_stale = true;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1278,6 +1189,181 @@ void GraphicsStateGuardian::
 bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
 bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::do_issue_light
+//       Access: Protected
+//  Description: This implementation of issue_light() assumes
+//               we have a limited number of hardware lights
+//               available.  This function assigns each light to a
+//               different hardware light id, trying to keep each
+//               light associated with the same id where possible, but
+//               reusing id's when necessary.  When it is no longer
+//               possible to reuse existing id's (e.g. all id's are in
+//               use), slot_new_light() is called to prepare the next
+//               sequential light id.
+//
+//               It will call apply_light() each time a light is
+//               assigned to a particular id for the first time in a
+//               given frame, and it will subsequently call
+//               enable_light() to enable or disable each light as the
+//               frame is rendered, as well as enable_lighting() to
+//               enable or disable overall lighting.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+do_issue_light() {
+  // Initialize the current ambient light total and newly enabled
+  // light list
+  Colorf cur_ambient_light(0.0f, 0.0f, 0.0f, 0.0f);
+  int i;
+  int max_lights = (int)_light_info.size();
+  for (i = 0; i < max_lights; i++) {
+    _light_info[i]._next_enabled = false;
+  }
+
+  bool any_bound = false;
+
+  int num_enabled = 0;
+  if (_pending_light != (LightAttrib *)NULL) {
+    int num_on_lights = _pending_light->get_num_on_lights();
+    for (int li = 0; li < num_on_lights; li++) {
+      NodePath light = _pending_light->get_on_light(li);
+      nassertv(!light.is_empty() && light.node()->as_light() != (Light *)NULL);
+      Light *light_obj = light.node()->as_light();
+      
+      num_enabled++;
+      
+      // Lighting should be enabled before we apply any lights.
+      enable_lighting(true);
+      _lighting_enabled = true;
+      _lighting_enabled_this_frame = true;
+      
+      if (light_obj->get_type() == AmbientLight::get_class_type()) {
+        // Ambient lights don't require specific light ids; simply add
+        // in the ambient contribution to the current total
+        cur_ambient_light += light_obj->get_color();
+        
+      } else {
+        // Check to see if this light has already been bound to an id
+        int cur_light_id = -1;
+        for (i = 0; i < max_lights; i++) {
+          if (_light_info[i]._light == light) {
+            // Light has already been bound to an id; reuse the same id.
+            cur_light_id = -2;
+            enable_light(i, true);
+            _light_info[i]._enabled = true;
+            _light_info[i]._next_enabled = true;
+            light_obj->bind(this, light, i);
+            break;
+          }
+        }
+        
+        // See if there are any unbound light ids
+        if (cur_light_id == -1) {
+          for (i = 0; i < max_lights; i++) {
+            if (_light_info[i]._light.is_empty()) {
+              _light_info[i]._light = light;
+              cur_light_id = i;
+              break;
+            }
+          }
+        }
+        
+        // If there were no unbound light ids, see if we can replace
+        // a currently unused but previously bound id
+        if (cur_light_id == -1) {
+          for (i = 0; i < max_lights; i++) {
+            if (!_pending_light->has_on_light(_light_info[i]._light)) {
+              _light_info[i]._light = light;
+              cur_light_id = i;
+              break;
+            }
+          }
+        }
+        
+        // If we *still* don't have a light id, slot a new one.
+        if (cur_light_id == -1) {
+          if (slot_new_light(max_lights)) {
+            cur_light_id = max_lights;
+            _light_info.push_back(LightInfo());
+            max_lights++;
+            nassertv(max_lights == (int)_light_info.size());
+          }
+        }
+        
+        if (cur_light_id >= 0) {
+          enable_light(cur_light_id, true);
+          _light_info[cur_light_id]._enabled = true;
+          _light_info[cur_light_id]._next_enabled = true;
+          
+          if (!any_bound) {
+            begin_bind_lights();
+            any_bound = true;
+          }
+          
+          // This is the first time this frame that this light has been
+          // bound to this particular id.
+          light_obj->bind(this, light, cur_light_id);
+          
+        } else if (cur_light_id == -1) {
+          gsg_cat.warning()
+            << "Failed to bind " << light << " to id.\n";
+        }
+      }
+    }
+  }
+    
+  // Disable all unused lights
+  for (i = 0; i < max_lights; i++) {
+    if (!_light_info[i]._next_enabled) {
+      enable_light(i, false);
+      _light_info[i]._enabled = false;
+    }
+  }
+
+  // If no lights were enabled, disable lighting
+  if (num_enabled == 0) {
+    if (_color_scale_via_lighting && (_has_material_force_color || _light_color_scale != LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f))) {
+      // Unless we need lighting anyway to apply a color or color
+      // scale.
+      enable_lighting(true);
+      _lighting_enabled = true;
+      _lighting_enabled_this_frame = true;
+      set_ambient_light(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
+
+    } else {
+      enable_lighting(false);
+      _lighting_enabled = false;
+    }
+
+  } else {
+    set_ambient_light(cur_ambient_light);
+  }
+
+  if (any_bound) {
+    end_bind_lights();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::do_issue_material
+//       Access: Protected, Virtual
+//  Description: Should be overridden by derived classes to actually
+//               apply the material saved in _pending_material.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+do_issue_material() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::do_issue_texture
+//       Access: Protected, Virtual
+//  Description: Should be overridden by derived classes to actually
+//               apply the texture saved in _pending_texture.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+do_issue_texture() {
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::slot_new_light
 //     Function: GraphicsStateGuardian::slot_new_light
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual
@@ -1470,6 +1556,21 @@ finish_modify_state() {
     _blend_mode_stale = false;
     _blend_mode_stale = false;
     set_blend_mode();
     set_blend_mode();
   }
   }
+
+  if (_texture_stale) {
+    _texture_stale = false;
+    do_issue_texture();
+  }
+
+  if (_material_stale) {
+    _material_stale = false;
+    do_issue_material();
+  }
+
+  if (_light_stale) {
+    _light_stale = false;
+    do_issue_light();
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1529,6 +1630,41 @@ panic_deactivate() {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::determine_light_color_scale
+//       Access: Protected
+//  Description: Called whenever the color or color scale is changed,
+//               if _color_scale_via_lighting is true.  This will
+//               rederive _material_force_color and _light_color_scale
+//               appropriately.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+determine_light_color_scale() {
+  if (_has_scene_graph_color) {
+    // If we have a scene graph color, it, plus the color scale, goes
+    // directly into the material; we don't color scale the
+    // lights--this allows an alpha color scale to work properly.
+    _has_material_force_color = true;
+    _material_force_color = _scene_graph_color;
+    _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
+    if (!_color_blend_involves_color_scale && _color_scale_enabled) {
+      _material_force_color.set(_scene_graph_color[0] * _current_color_scale[0],
+                                _scene_graph_color[1] * _current_color_scale[1],
+                                _scene_graph_color[2] * _current_color_scale[2],
+                                _scene_graph_color[3] * _current_color_scale[3]);
+    }
+
+  } else {
+    // Otherise, leave the materials alone, but we might still scale
+    // the lights.
+    _has_material_force_color = false;
+    _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
+    if (!_color_blend_involves_color_scale && _color_scale_enabled) {
+      _light_color_scale = _current_color_scale;
+    }
+  }
+}
+
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

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

@@ -41,6 +41,8 @@
 #include "colorWriteAttrib.h"
 #include "colorWriteAttrib.h"
 #include "colorBlendAttrib.h"
 #include "colorBlendAttrib.h"
 #include "textureAttrib.h"
 #include "textureAttrib.h"
+#include "materialAttrib.h"
+#include "lightAttrib.h"
 #include "transparencyAttrib.h"
 #include "transparencyAttrib.h"
 #include "config_display.h"
 #include "config_display.h"
 #include "qpgeomMunger.h"
 #include "qpgeomMunger.h"
@@ -100,6 +102,8 @@ PUBLISHED:
 
 
   virtual int get_supported_geom_rendering() const;
   virtual int get_supported_geom_rendering() const;
 
 
+  INLINE bool get_color_scale_via_lighting() const;
+
 public:
 public:
   INLINE bool set_scene(SceneSetup *scene_setup);
   INLINE bool set_scene(SceneSetup *scene_setup);
   INLINE SceneSetup *get_scene() const;
   INLINE SceneSetup *get_scene() const;
@@ -118,7 +122,7 @@ public:
   virtual IndexBufferContext *prepare_index_buffer(qpGeomPrimitive *data);
   virtual IndexBufferContext *prepare_index_buffer(qpGeomPrimitive *data);
   virtual void release_index_buffer(IndexBufferContext *ibc);
   virtual void release_index_buffer(IndexBufferContext *ibc);
 
 
-  virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state);
+  virtual PT(qpGeomMunger) get_geom_munger(const RenderState *state);
 
 
   virtual void set_state_and_transform(const RenderState *state,
   virtual void set_state_and_transform(const RenderState *state,
                                        const TransformState *transform);
                                        const TransformState *transform);
@@ -193,6 +197,7 @@ public:
   virtual void issue_color_scale(const ColorScaleAttrib *attrib);
   virtual void issue_color_scale(const ColorScaleAttrib *attrib);
   virtual void issue_color(const ColorAttrib *attrib);
   virtual void issue_color(const ColorAttrib *attrib);
   virtual void issue_light(const LightAttrib *attrib);
   virtual void issue_light(const LightAttrib *attrib);
+  virtual void issue_material(const MaterialAttrib *attrib);
   virtual void issue_color_write(const ColorWriteAttrib *attrib);
   virtual void issue_color_write(const ColorWriteAttrib *attrib);
   virtual void issue_transparency(const TransparencyAttrib *attrib);
   virtual void issue_transparency(const TransparencyAttrib *attrib);
   virtual void issue_color_blend(const ColorBlendAttrib *attrib);
   virtual void issue_color_blend(const ColorBlendAttrib *attrib);
@@ -207,6 +212,10 @@ public:
                           int light_id);
                           int light_id);
 
 
 protected:
 protected:
+  void do_issue_light();
+  virtual void do_issue_material();
+  virtual void do_issue_texture();
+
   INLINE NodePath get_light(int light_id) const;
   INLINE NodePath get_light(int light_id) const;
   virtual bool slot_new_light(int light_id);
   virtual bool slot_new_light(int light_id);
   virtual void enable_lighting(bool enable);
   virtual void enable_lighting(bool enable);
@@ -231,6 +240,8 @@ protected:
   virtual void close_gsg();
   virtual void close_gsg();
   void panic_deactivate();
   void panic_deactivate();
 
 
+  void determine_light_color_scale();
+
   INLINE void set_properties(const FrameBufferProperties &properties);
   INLINE void set_properties(const FrameBufferProperties &properties);
 
 
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS
@@ -313,6 +324,14 @@ protected:
 
 
   CPT(TextureAttrib) _pending_texture;
   CPT(TextureAttrib) _pending_texture;
   bool _texture_stale;
   bool _texture_stale;
+  CPT(LightAttrib) _pending_light;
+  bool _light_stale;
+  CPT(MaterialAttrib) _pending_material;
+  bool _material_stale;
+
+  bool _has_material_force_color;
+  Colorf _material_force_color;
+  LVecBase4f _light_color_scale;
 
 
   bool _needs_reset;
   bool _needs_reset;
   bool _closing_gsg;
   bool _closing_gsg;
@@ -332,6 +351,7 @@ protected:
   bool _supports_generate_mipmap;
   bool _supports_generate_mipmap;
   bool _supports_render_texture;
   bool _supports_render_texture;
   int _supported_geom_rendering;
   int _supported_geom_rendering;
+  bool _color_scale_via_lighting;
 
 
 public:
 public:
   // Statistics
   // Statistics

+ 105 - 33
panda/src/display/standardMunger.cxx

@@ -37,15 +37,56 @@ StandardMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state,
                int num_components,
                int num_components,
                StandardMunger::NumericType numeric_type,
                StandardMunger::NumericType numeric_type,
                StandardMunger::Contents contents) :
                StandardMunger::Contents contents) :
-  qpGeomMunger(gsg, state),
   _num_components(num_components),
   _num_components(num_components),
   _numeric_type(numeric_type),
   _numeric_type(numeric_type),
   _contents(contents)
   _contents(contents)
 {
 {
   _gsg = DCAST(GraphicsStateGuardian, gsg);
   _gsg = DCAST(GraphicsStateGuardian, gsg);
-  _color = state->get_color();
-  _color_scale = state->get_color_scale();
   _render_mode = state->get_render_mode();
   _render_mode = state->get_render_mode();
+
+  _munge_color = false;
+  _munge_color_scale = false;
+
+  CPT(ColorAttrib) color_attrib = state->get_color();
+  CPT(ColorScaleAttrib) color_scale_attrib = state->get_color_scale();
+
+  if (color_attrib != (ColorAttrib *)NULL && 
+      color_attrib->get_color_type() == ColorAttrib::T_flat) {
+
+    if (!_gsg->get_color_scale_via_lighting()) {
+      // We only need to munge the color directly if the GSG says it
+      // can't cheat the color via lighting (presumably, in this case,
+      // by applying a material).
+      _color = color_attrib->get_color();
+      if (color_scale_attrib != (ColorScaleAttrib *)NULL &&
+          color_scale_attrib->has_scale()) {
+        const LVecBase4f &cs = color_scale_attrib->get_scale();
+        _color.set(_color[0] * cs[0],
+                   _color[1] * cs[1],
+                   _color[2] * cs[2],
+                   _color[3] * cs[3]);
+      }
+      _munge_color = true;
+    }
+
+  } else if (color_scale_attrib != (ColorScaleAttrib *)NULL &&
+             color_scale_attrib->has_scale()) {
+    _color_scale = color_scale_attrib->get_scale();
+    if (!_gsg->get_color_scale_via_lighting() || _color_scale[3] != 1.0f) {
+      // We only need to apply the color scale by directly munging the
+      // color if the GSG says it can't cheat this via lighting (for
+      // instance, by applying an ambient light).  Or, since we assume
+      // lighting can't scale the alpha component, if the color scale
+      // involves alpha.
+
+      // Known bug: if there is a material on an object that would
+      // obscure the effect of color_scale, we scale the lighting
+      // anyway, thus applying the effect even if it should be
+      // obscured.  It doesn't seem worth the effort to detect this
+      // contrived situation and handle it correctly.
+      _munge_color_scale = true;
+    }
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -67,25 +108,12 @@ CPT(qpGeomVertexData) StandardMunger::
 munge_data_impl(const qpGeomVertexData *data) {
 munge_data_impl(const qpGeomVertexData *data) {
   CPT(qpGeomVertexData) new_data = 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,
+  if (_munge_color) {
+    new_data = new_data->set_color(_color, _num_components, _numeric_type,
                                    _contents);
                                    _contents);
-
-  } 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,
-                                     _contents);
+  } else if (_munge_color_scale) {
+    new_data = new_data->scale_color(_color_scale, _num_components, 
+                                     _numeric_type, _contents);
   }
   }
 
 
   qpGeomVertexAnimationSpec animation = new_data->get_format()->get_animation();
   qpGeomVertexAnimationSpec animation = new_data->get_format()->get_animation();
@@ -189,17 +217,30 @@ munge_geom_impl(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &vertex_data) {
 int StandardMunger::
 int StandardMunger::
 compare_to_impl(const qpGeomMunger *other) const {
 compare_to_impl(const qpGeomMunger *other) const {
   const StandardMunger *om = DCAST(StandardMunger, other);
   const StandardMunger *om = DCAST(StandardMunger, 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;
-  }
   if (_render_mode != om->_render_mode) {
   if (_render_mode != om->_render_mode) {
     return _render_mode < om->_render_mode ? -1 : 1;
     return _render_mode < om->_render_mode ? -1 : 1;
   }
   }
 
 
-  return qpGeomMunger::compare_to_impl(other);
+  if (_munge_color != om->_munge_color) {
+    return (int)_munge_color - (int)om->_munge_color;
+  }
+  if (_munge_color_scale != om->_munge_color_scale) {
+    return (int)_munge_color_scale - (int)om->_munge_color_scale;
+  }
+  if (_munge_color) {
+    int compare = _color.compare_to(om->_color);
+    if (compare != 0) {
+      return compare;
+    }
+  }
+  if (_munge_color_scale) {
+    int compare = _color_scale.compare_to(om->_color_scale);
+    if (compare != 0) {
+      return compare;
+    }
+  }
+
+  return StateMunger::compare_to_impl(other);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -215,12 +256,43 @@ compare_to_impl(const qpGeomMunger *other) const {
 int StandardMunger::
 int StandardMunger::
 geom_compare_to_impl(const qpGeomMunger *other) const {
 geom_compare_to_impl(const qpGeomMunger *other) const {
   const StandardMunger *om = DCAST(StandardMunger, other);
   const StandardMunger *om = DCAST(StandardMunger, other);
-  if (_color != om->_color) {
-    return _color < om->_color ? -1 : 1;
+  if (_munge_color != om->_munge_color) {
+    return (int)_munge_color - (int)om->_munge_color;
+  }
+  if (_munge_color_scale != om->_munge_color_scale) {
+    return (int)_munge_color_scale - (int)om->_munge_color_scale;
+  }
+  if (_munge_color) {
+    int compare = _color.compare_to(om->_color);
+    if (compare != 0) {
+      return compare;
+    }
   }
   }
-  if (_color_scale != om->_color_scale) {
-    return _color_scale < om->_color_scale ? -1 : 1;
+  if (_munge_color_scale) {
+    int compare = _color_scale.compare_to(om->_color_scale);
+    if (compare != 0) {
+      return compare;
+    }
+  }
+
+  return StateMunger::geom_compare_to_impl(other);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StandardMunger::munge_state_impl
+//       Access: Protectes, Virtual
+//  Description: Given an input state, returns the munged state.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) StandardMunger::
+munge_state_impl(const RenderState *state) {
+  CPT(RenderState) munged_state = state;
+
+  if (_munge_color) {
+    munged_state = munged_state->remove_attrib(ColorAttrib::get_class_type());
+    munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_type());
+  } else if (_munge_color_scale) {
+    munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_type());
   }
   }
 
 
-  return qpGeomMunger::geom_compare_to_impl(other);
+  return munged_state;
 }
 }

+ 11 - 6
panda/src/display/standardMunger.h

@@ -20,7 +20,7 @@
 #define STANDARDMUNGER_H
 #define STANDARDMUNGER_H
 
 
 #include "pandabase.h"
 #include "pandabase.h"
-#include "qpgeomMunger.h"
+#include "stateMunger.h"
 #include "graphicsStateGuardian.h"
 #include "graphicsStateGuardian.h"
 #include "colorAttrib.h"
 #include "colorAttrib.h"
 #include "colorScaleAttrib.h"
 #include "colorScaleAttrib.h"
@@ -36,7 +36,7 @@
 //
 //
 //               This is part of the experimental Geom rewrite.
 //               This is part of the experimental Geom rewrite.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA StandardMunger : public qpGeomMunger {
+class EXPCL_PANDA StandardMunger : public StateMunger {
 public:
 public:
   StandardMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state,
   StandardMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state,
                  int num_components, NumericType numeric_type,
                  int num_components, NumericType numeric_type,
@@ -48,24 +48,29 @@ protected:
   virtual int compare_to_impl(const qpGeomMunger *other) const;
   virtual int compare_to_impl(const qpGeomMunger *other) const;
   virtual bool munge_geom_impl(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &data);
   virtual bool munge_geom_impl(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &data);
   virtual int geom_compare_to_impl(const qpGeomMunger *other) const;
   virtual int geom_compare_to_impl(const qpGeomMunger *other) const;
+  virtual CPT(RenderState) munge_state_impl(const RenderState *state);
 
 
 private:
 private:
   int _num_components;
   int _num_components;
   NumericType _numeric_type;
   NumericType _numeric_type;
   Contents _contents;
   Contents _contents;
   CPT(GraphicsStateGuardian) _gsg;
   CPT(GraphicsStateGuardian) _gsg;
-  CPT(ColorAttrib) _color;
-  CPT(ColorScaleAttrib) _color_scale;
   CPT(RenderModeAttrib) _render_mode;
   CPT(RenderModeAttrib) _render_mode;
 
 
+  bool _munge_color;
+  bool _munge_color_scale;
+
+  Colorf _color;
+  LVecBase4f _color_scale;
+
 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();
+    StateMunger::init_type();
     register_type(_type_handle, "StandardMunger",
     register_type(_type_handle, "StandardMunger",
-                  qpGeomMunger::get_class_type());
+                  StateMunger::get_class_type());
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 112 - 82
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -33,7 +33,6 @@
 #include "spotlight.h"
 #include "spotlight.h"
 #include "textureAttrib.h"
 #include "textureAttrib.h"
 #include "texGenAttrib.h"
 #include "texGenAttrib.h"
-#include "lightAttrib.h"
 #include "shadeModelAttrib.h"
 #include "shadeModelAttrib.h"
 #include "cullFaceAttrib.h"
 #include "cullFaceAttrib.h"
 #include "transparencyAttrib.h"
 #include "transparencyAttrib.h"
@@ -413,8 +412,8 @@ dx_init(void) {
     _has_scene_graph_color = false;
     _has_scene_graph_color = false;
 
 
     // Apply a default material when materials are turned off.
     // Apply a default material when materials are turned off.
-    Material empty;
-    apply_material(&empty);
+    _pending_material = NULL;
+    do_issue_material();
 
 
 //  GL stuff that hasnt been translated to DX
 //  GL stuff that hasnt been translated to DX
     // none of these are implemented
     // none of these are implemented
@@ -3556,7 +3555,7 @@ release_index_buffer(IndexBufferContext *ibc) {
 //  Description: Creates a new GeomMunger object to munge vertices
 //  Description: Creates a new GeomMunger object to munge vertices
 //               appropriate to this GSG for the indicated state.
 //               appropriate to this GSG for the indicated state.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-CPT(qpGeomMunger) DXGraphicsStateGuardian8::
+PT(qpGeomMunger) DXGraphicsStateGuardian8::
 get_geom_munger(const RenderState *state) {
 get_geom_munger(const RenderState *state) {
   PT(DXGeomMunger8) munger = new DXGeomMunger8(this, state);
   PT(DXGeomMunger8) munger = new DXGeomMunger8(this, state);
   return qpGeomMunger::register_munger(munger);
   return qpGeomMunger::register_munger(munger);
@@ -3704,44 +3703,6 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const Rend
   return true;
   return true;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: DXGraphicsStateGuardian8::apply_material
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian8::
-apply_material(const Material *material) {
-  D3DMATERIAL8 cur_material;
-  cur_material.Diffuse = *(D3DCOLORVALUE *)(material->get_diffuse().get_data());
-  cur_material.Ambient = *(D3DCOLORVALUE *)(material->get_ambient().get_data());
-  cur_material.Specular = *(D3DCOLORVALUE *)(material->get_specular().get_data());
-  cur_material.Emissive = *(D3DCOLORVALUE *)(material->get_emission().get_data());
-  cur_material.Power = material->get_shininess();
-
-  _pD3DDevice->SetMaterial(&cur_material);
-
-  if (material->has_diffuse()) {
-    // If the material specifies an diffuse color, use it.
-    _pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
-  } else {
-    // Otherwise, the diffuse color comes from the object color.
-    _pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
-  }
-  if (material->has_ambient()) {
-    // If the material specifies an ambient color, use it.
-    _pD3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
-  } else {
-    // Otherwise, the ambient color comes from the object color.
-    _pD3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1);
-  }
-
-  if (material->get_local()) {
-    _pD3DDevice->SetRenderState(D3DRS_LOCALVIEWER, TRUE);
-  } else {
-    _pD3DDevice->SetRenderState(D3DRS_LOCALVIEWER, FALSE);
-  }    
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian8::apply_fog
 //     Function: DXGraphicsStateGuardian8::apply_fog
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -3977,42 +3938,6 @@ issue_shade_model(const ShadeModelAttrib *attrib) {
   }
   }
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: DXGraphicsStateGuardian8::issue_texture
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian8::
-issue_texture(const TextureAttrib *attrib) {
-  DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1));
-  if (attrib->is_off()) {
-    enable_texturing(false);
-  } else {
-    Texture *tex = attrib->get_texture();
-    nassertv(tex != (Texture *)NULL);
-
-    TextureContext *tc = tex->prepare_now(_prepared_objects, this);
-    apply_texture(tc);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DXGraphicsStateGuardian8::issue_material
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian8::
-issue_material(const MaterialAttrib *attrib) {
-  const Material *material = attrib->get_material();
-  if (material != (const Material *)NULL) {
-    apply_material(material);
-  } else {
-    // Apply a default material when materials are turned off.
-    Material empty;
-    apply_material(&empty);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian8::issue_render_mode
 //     Function: DXGraphicsStateGuardian8::issue_render_mode
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -4218,7 +4143,7 @@ bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
   black.r = black.g = black.b = black.a = 0.0f;
   black.r = black.g = black.b = black.a = 0.0f;
   D3DLIGHT8 alight;
   D3DLIGHT8 alight;
   alight.Type =  D3DLIGHT_POINT;
   alight.Type =  D3DLIGHT_POINT;
-  alight.Diffuse  = *(D3DCOLORVALUE *)(light_obj->get_color().get_data());
+  alight.Diffuse  = get_light_color(light_obj);
   alight.Ambient  =  black ;
   alight.Ambient  =  black ;
   alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data());
   alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data());
 
 
@@ -4267,7 +4192,7 @@ bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
   ZeroMemory(&alight, sizeof(D3DLIGHT8));
   ZeroMemory(&alight, sizeof(D3DLIGHT8));
 
 
   alight.Type =  D3DLIGHT_DIRECTIONAL;
   alight.Type =  D3DLIGHT_DIRECTIONAL;
-  alight.Diffuse  = *(D3DCOLORVALUE *)(light_obj->get_color().get_data());
+  alight.Diffuse  = get_light_color(light_obj);
   alight.Ambient  =  black ;
   alight.Ambient  =  black ;
   alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data());
   alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data());
 
 
@@ -4318,7 +4243,7 @@ bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
 
 
   alight.Type =  D3DLIGHT_SPOT;
   alight.Type =  D3DLIGHT_SPOT;
   alight.Ambient  =  black ;
   alight.Ambient  =  black ;
-  alight.Diffuse  = *(D3DCOLORVALUE *)(light_obj->get_color().get_data());
+  alight.Diffuse  = get_light_color(light_obj);
   alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data());
   alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data());
 
 
   alight.Position = *(D3DVECTOR *)pos.get_data();
   alight.Position = *(D3DVECTOR *)pos.get_data();
@@ -4531,6 +4456,25 @@ get_index_type(qpGeom::NumericType numeric_type) {
   return D3DFMT_INDEX16;
   return D3DFMT_INDEX16;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::get_light_color
+//       Access: Public
+//  Description: Returns the array of four floats that should be
+//               issued as the light's color, as scaled by the current
+//               value of _light_color_scale, in the case of
+//               color_scale_via_lighting.
+////////////////////////////////////////////////////////////////////
+const D3DCOLORVALUE &DXGraphicsStateGuardian8::
+get_light_color(Light *light) const {
+  static Colorf c;
+  c = light->get_color();
+  c.set(c[0] * _light_color_scale[0],
+        c[1] * _light_color_scale[1],
+        c[2] * _light_color_scale[2],
+        c[3] * _light_color_scale[3]);
+  return *(D3DCOLORVALUE *)c.get_data();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian8::set_draw_buffer
 //     Function: DXGraphicsStateGuardian8::set_draw_buffer
 //       Access: Protected
 //       Access: Protected
@@ -4652,6 +4596,86 @@ do_auto_rescale_normal() {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXGraphicsStateGuardian8::do_issue_texture
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void DXGraphicsStateGuardian8::
+do_issue_texture() {
+  DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1));
+
+  CPT(TextureAttrib) new_texture = _pending_texture->filter_to_max(_max_texture_stages);
+
+  if (new_texture->is_off()) {
+    enable_texturing(false);
+  } else {
+    Texture *tex = new_texture->get_texture();
+    nassertv(tex != (Texture *)NULL);
+
+    TextureContext *tc = tex->prepare_now(_prepared_objects, this);
+    apply_texture(tc);
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: DXGraphicsStateGuardian8::do_issue_material
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void DXGraphicsStateGuardian8::
+do_issue_material() {
+  static Material empty;
+  const Material *material;
+  if (_pending_material == (MaterialAttrib *)NULL || 
+      _pending_material->is_off()) {
+    material = &empty;
+  } else {
+    material = _pending_material->get_material();
+  }
+
+  D3DMATERIAL8 cur_material;
+  cur_material.Diffuse = *(D3DCOLORVALUE *)(material->get_diffuse().get_data());
+  cur_material.Ambient = *(D3DCOLORVALUE *)(material->get_ambient().get_data());
+  cur_material.Specular = *(D3DCOLORVALUE *)(material->get_specular().get_data());
+  cur_material.Emissive = *(D3DCOLORVALUE *)(material->get_emission().get_data());
+  cur_material.Power = material->get_shininess();
+
+  if (material->has_diffuse()) {
+    // If the material specifies an diffuse color, use it.
+    _pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
+  } else {
+    // Otherwise, the diffuse color comes from the object color.
+    if (_has_material_force_color) {
+      cur_material.Diffuse = *(D3DCOLORVALUE *)_material_force_color.get_data();
+      _pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
+    } else {
+      _pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
+    }
+  }
+  if (material->has_ambient()) {
+    // If the material specifies an ambient color, use it.
+    _pD3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
+  } else {
+    // Otherwise, the ambient color comes from the object color.
+    if (_has_material_force_color) {
+      cur_material.Ambient = *(D3DCOLORVALUE *)_material_force_color.get_data();
+      _pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
+    } else {
+      _pD3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1);
+    }
+  }
+
+  _pD3DDevice->SetMaterial(&cur_material);
+
+  if (material->get_local()) {
+    _pD3DDevice->SetRenderState(D3DRS_LOCALVIEWER, TRUE);
+  } else {
+    _pD3DDevice->SetRenderState(D3DRS_LOCALVIEWER, FALSE);
+  }    
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian8::slot_new_light
 //     Function: DXGraphicsStateGuardian8::slot_new_light
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual
@@ -4693,7 +4717,13 @@ enable_lighting(bool enable) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian8::
 void DXGraphicsStateGuardian8::
 set_ambient_light(const Colorf &color) {
 set_ambient_light(const Colorf &color) {
-  _pD3DDevice->SetRenderState(D3DRS_AMBIENT, Colorf_to_D3DCOLOR(color));
+  Colorf c = color;
+  c.set(c[0] * _light_color_scale[0],
+        c[1] * _light_color_scale[1],
+        c[2] * _light_color_scale[2],
+        c[3] * _light_color_scale[3]);
+
+  _pD3DDevice->SetRenderState(D3DRS_AMBIENT, Colorf_to_D3DCOLOR(c));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 10 - 8
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -115,20 +115,17 @@ public:
   void apply_index_buffer(IndexBufferContext *ibc);
   void apply_index_buffer(IndexBufferContext *ibc);
   virtual void release_index_buffer(IndexBufferContext *ibc);
   virtual void release_index_buffer(IndexBufferContext *ibc);
 
 
-  virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state);
+  virtual PT(qpGeomMunger) get_geom_munger(const RenderState *state);
 
 
   virtual void framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   virtual void framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
                                            const RenderBuffer &rb);
                                            const RenderBuffer &rb);
   virtual bool framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
   virtual bool framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
                                        const RenderBuffer &rb);
                                        const RenderBuffer &rb);
 
 
-  virtual void apply_material(const Material *material);
   virtual void apply_fog(Fog *fog);
   virtual void apply_fog(Fog *fog);
 
 
   virtual void issue_transform(const TransformState *transform);
   virtual void issue_transform(const TransformState *transform);
   virtual void issue_tex_matrix(const TexMatrixAttrib *attrib);
   virtual void issue_tex_matrix(const TexMatrixAttrib *attrib);
-  virtual void issue_texture(const TextureAttrib *attrib);
-  virtual void issue_material(const MaterialAttrib *attrib);
   virtual void issue_render_mode(const RenderModeAttrib *attrib);
   virtual void issue_render_mode(const RenderModeAttrib *attrib);
   virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib);
   virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib);
   virtual void issue_alpha_test(const AlphaTestAttrib *attrib);
   virtual void issue_alpha_test(const AlphaTestAttrib *attrib);
@@ -160,6 +157,8 @@ public:
 
 
   static D3DFORMAT get_index_type(qpGeom::NumericType numeric_type);
   static D3DFORMAT get_index_type(qpGeom::NumericType numeric_type);
 
 
+  const D3DCOLORVALUE &get_light_color(Light *light) const;
+
 public:
 public:
   // recreate_tex_callback needs these to be public
   // recreate_tex_callback needs these to be public
   DXScreenData *_pScrn;
   DXScreenData *_pScrn;
@@ -168,6 +167,8 @@ public:
   D3DPRESENT_PARAMETERS _PresReset;  // This is built during reset device
   D3DPRESENT_PARAMETERS _PresReset;  // This is built during reset device
 
 
 protected:
 protected:
+  virtual void do_issue_material();
+
   virtual bool slot_new_light(int light_id);
   virtual bool slot_new_light(int light_id);
   virtual void enable_lighting(bool enable);
   virtual void enable_lighting(bool enable);
   virtual void set_ambient_light(const Colorf &color);
   virtual void set_ambient_light(const Colorf &color);
@@ -192,6 +193,7 @@ protected:
   static CPT(RenderState) get_flat_state();
   static CPT(RenderState) get_flat_state();
 
 
   void do_auto_rescale_normal();
   void do_auto_rescale_normal();
+  virtual void do_issue_texture();
 
 
   bool                  _bDXisReady;
   bool                  _bDXisReady;
   HRESULT               _last_testcooplevel_result;
   HRESULT               _last_testcooplevel_result;
@@ -204,10 +206,10 @@ protected:
   bool _auto_rescale_normal;
   bool _auto_rescale_normal;
 
 
   void GenerateSphere(void *pVertexSpace,DWORD dwVertSpaceByteSize,
   void GenerateSphere(void *pVertexSpace,DWORD dwVertSpaceByteSize,
-                    void *pIndexSpace,DWORD dwIndexSpaceByteSize,
-                    D3DXVECTOR3 *pCenter, float fRadius,
-                    DWORD wNumRings, DWORD wNumSections, float sx, float sy, float sz,
-                    DWORD *pNumVertices,DWORD *pNumTris,DWORD fvfFlags,DWORD dwVertSize);
+                      void *pIndexSpace,DWORD dwIndexSpaceByteSize,
+                      D3DXVECTOR3 *pCenter, float fRadius,
+                      DWORD wNumRings, DWORD wNumSections, float sx, float sy, float sz,
+                      DWORD *pNumVertices,DWORD *pNumTris,DWORD fvfFlags,DWORD dwVertSize);
   HRESULT ReleaseAllDeviceObjects(void);
   HRESULT ReleaseAllDeviceObjects(void);
   HRESULT RecreateAllDeviceObjects(void);
   HRESULT RecreateAllDeviceObjects(void);
   HRESULT DeleteAllDeviceObjects(void);
   HRESULT DeleteAllDeviceObjects(void);

+ 121 - 87
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -861,8 +861,8 @@ reset() {
   cfa->issue(this);
   cfa->issue(this);
   ta->issue(this);
   ta->issue(this);
 
 
-  Material empty;
-  apply_material(&empty);
+  _pending_material = NULL;
+  do_issue_material();
 
 
   if (CLP(cheap_textures)) {
   if (CLP(cheap_textures)) {
     GLCAT.info()
     GLCAT.info()
@@ -1157,7 +1157,8 @@ draw_point(GeomPoint *geom, GeomContext *gc) {
 
 
   GeomIssuer::IssueColor *issue_color;
   GeomIssuer::IssueColor *issue_color;
 
 
-  if (_color_blend_involves_color_scale || !_color_scale_enabled) {
+  if (_color_blend_involves_color_scale || !_color_scale_enabled ||
+      _color_scale_via_lighting) {
     issue_color = issue_color_gl;
     issue_color = issue_color_gl;
   } else {
   } else {
     issue_color = issue_scaled_color_gl;
     issue_color = issue_scaled_color_gl;
@@ -1227,7 +1228,8 @@ draw_line(GeomLine *geom, GeomContext *gc) {
 
 
   GeomIssuer::IssueColor *issue_color;
   GeomIssuer::IssueColor *issue_color;
 
 
-  if (_color_blend_involves_color_scale || !_color_scale_enabled) {
+  if (_color_blend_involves_color_scale || !_color_scale_enabled ||
+      _color_scale_via_lighting) {
     issue_color = issue_color_gl;
     issue_color = issue_color_gl;
   } else {
   } else {
     issue_color = issue_scaled_color_gl;
     issue_color = issue_scaled_color_gl;
@@ -1304,7 +1306,8 @@ draw_linestrip(GeomLinestrip *geom, GeomContext *gc) {
 
 
   GeomIssuer::IssueColor *issue_color;
   GeomIssuer::IssueColor *issue_color;
 
 
-  if (_color_blend_involves_color_scale || !_color_scale_enabled) {
+  if (_color_blend_involves_color_scale || !_color_scale_enabled ||
+      _color_scale_via_lighting) {
     issue_color = issue_color_gl;
     issue_color = issue_color_gl;
   } else {
   } else {
     issue_color = issue_scaled_color_gl;
     issue_color = issue_scaled_color_gl;
@@ -1677,7 +1680,8 @@ draw_polygon(GeomPolygon *geom, GeomContext *gc) {
 
 
   GeomIssuer::IssueColor *issue_color;
   GeomIssuer::IssueColor *issue_color;
 
 
-  if (_color_blend_involves_color_scale || !_color_scale_enabled) {
+  if (_color_blend_involves_color_scale || !_color_scale_enabled ||
+      _color_scale_via_lighting) {
     issue_color = issue_color_gl;
     issue_color = issue_color_gl;
   } else {
   } else {
     issue_color = issue_scaled_color_gl;
     issue_color = issue_scaled_color_gl;
@@ -1758,7 +1762,8 @@ draw_tri(GeomTri *geom, GeomContext *gc) {
 
 
   GeomIssuer::IssueColor *issue_color;
   GeomIssuer::IssueColor *issue_color;
 
 
-  if (_color_blend_involves_color_scale || !_color_scale_enabled) {
+  if (_color_blend_involves_color_scale || !_color_scale_enabled ||
+      _color_scale_via_lighting) {
     issue_color = issue_color_gl;
     issue_color = issue_color_gl;
   } else {
   } else {
     issue_color = issue_scaled_color_gl;
     issue_color = issue_scaled_color_gl;
@@ -1837,7 +1842,8 @@ draw_quad(GeomQuad *geom, GeomContext *gc) {
 
 
   GeomIssuer::IssueColor *issue_color;
   GeomIssuer::IssueColor *issue_color;
 
 
-  if (_color_blend_involves_color_scale || !_color_scale_enabled) {
+  if (_color_blend_involves_color_scale || !_color_scale_enabled ||
+      _color_scale_via_lighting) {
     issue_color = issue_color_gl;
     issue_color = issue_color_gl;
   } else {
   } else {
     issue_color = issue_scaled_color_gl;
     issue_color = issue_scaled_color_gl;
@@ -1920,7 +1926,8 @@ draw_tristrip(GeomTristrip *geom, GeomContext *gc) {
 
 
   GeomIssuer::IssueColor *issue_color;
   GeomIssuer::IssueColor *issue_color;
 
 
-  if (_color_blend_involves_color_scale || !_color_scale_enabled) {
+  if (_color_blend_involves_color_scale || !_color_scale_enabled ||
+      _color_scale_via_lighting) {
     issue_color = issue_color_gl;
     issue_color = issue_color_gl;
   } else {
   } else {
     issue_color = issue_scaled_color_gl;
     issue_color = issue_scaled_color_gl;
@@ -2021,7 +2028,8 @@ draw_trifan(GeomTrifan *geom, GeomContext *gc) {
 
 
   GeomIssuer::IssueColor *issue_color;
   GeomIssuer::IssueColor *issue_color;
 
 
-  if (_color_blend_involves_color_scale || !_color_scale_enabled) {
+  if (_color_blend_involves_color_scale || !_color_scale_enabled ||
+      _color_scale_via_lighting) {
     issue_color = issue_color_gl;
     issue_color = issue_color_gl;
   } else {
   } else {
     issue_color = issue_scaled_color_gl;
     issue_color = issue_scaled_color_gl;
@@ -2119,7 +2127,8 @@ draw_sphere(GeomSphere *geom, GeomContext *gc) {
 
 
   GeomIssuer::IssueColor *issue_color;
   GeomIssuer::IssueColor *issue_color;
 
 
-  if (_color_blend_involves_color_scale || !_color_scale_enabled) {
+  if (_color_blend_involves_color_scale || !_color_scale_enabled ||
+      _color_scale_via_lighting) {
     issue_color = issue_color_gl;
     issue_color = issue_color_gl;
   } else {
   } else {
     issue_color = issue_scaled_color_gl;
     issue_color = issue_scaled_color_gl;
@@ -3206,7 +3215,7 @@ setup_primitive(const qpGeomPrimitive *data) {
 //  Description: Creates a new GeomMunger object to munge vertices
 //  Description: Creates a new GeomMunger object to munge vertices
 //               appropriate to this GSG for the indicated state.
 //               appropriate to this GSG for the indicated state.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-CPT(qpGeomMunger) CLP(GraphicsStateGuardian)::
+PT(qpGeomMunger) CLP(GraphicsStateGuardian)::
 get_geom_munger(const RenderState *state) {
 get_geom_munger(const RenderState *state) {
   PT(CLP(GeomMunger)) munger = new CLP(GeomMunger)(this, state);
   PT(CLP(GeomMunger)) munger = new CLP(GeomMunger)(this, state);
   return qpGeomMunger::register_munger(munger);
   return qpGeomMunger::register_munger(munger);
@@ -3403,52 +3412,6 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
   return true;
   return true;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::apply_material
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-apply_material(const Material *material) {
-  GLenum face = material->get_twoside() ? GL_FRONT_AND_BACK : GL_FRONT;
-
-  GLP(Materialfv)(face, GL_SPECULAR, material->get_specular().get_data());
-  GLP(Materialfv)(face, GL_EMISSION, material->get_emission().get_data());
-  GLP(Materialf)(face, GL_SHININESS, material->get_shininess());
-
-  if (material->has_ambient() && material->has_diffuse()) {
-    // The material has both an ambient and diffuse specified.  This
-    // means we do not need glMaterialColor().
-    GLP(Disable)(GL_COLOR_MATERIAL);
-    GLP(Materialfv)(face, GL_AMBIENT, material->get_ambient().get_data());
-    GLP(Materialfv)(face, GL_DIFFUSE, material->get_diffuse().get_data());
-
-  } else if (material->has_ambient()) {
-    // The material specifies an ambient, but not a diffuse component.
-    // The diffuse component comes from the object's color.
-    GLP(Materialfv)(face, GL_AMBIENT, material->get_ambient().get_data());
-    GLP(ColorMaterial)(face, GL_DIFFUSE);
-    GLP(Enable)(GL_COLOR_MATERIAL);
-
-  } else if (material->has_diffuse()) {
-    // The material specifies a diffuse, but not an ambient component.
-    // The ambient component comes from the object's color.
-    GLP(Materialfv)(face, GL_DIFFUSE, material->get_diffuse().get_data());
-    GLP(ColorMaterial)(face, GL_AMBIENT);
-    GLP(Enable)(GL_COLOR_MATERIAL);
-
-  } else {
-    // The material specifies neither a diffuse nor an ambient
-    // component.  Both components come from the object's color.
-    GLP(ColorMaterial)(face, GL_AMBIENT_AND_DIFFUSE);
-    GLP(Enable)(GL_COLOR_MATERIAL);
-  }
-
-  GLP(LightModeli)(GL_LIGHT_MODEL_LOCAL_VIEWER, material->get_local());
-  GLP(LightModeli)(GL_LIGHT_MODEL_TWO_SIDE, material->get_twoside());
-  report_my_gl_errors();
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::apply_fog
 //     Function: GLGraphicsStateGuardian::apply_fog
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -3594,24 +3557,6 @@ issue_cg_shader_bind(const CgShaderAttrib *attrib) {
 }
 }
 #endif
 #endif
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::issue_material
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-issue_material(const MaterialAttrib *attrib) {
-  const Material *material = attrib->get_material();
-  if (material != (const Material *)NULL) {
-    apply_material(material);
-  } else {
-    // Apply a default material when materials are turned off.
-    Material empty;
-    apply_material(&empty);
-  }
-  report_my_gl_errors();
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::issue_render_mode
 //     Function: GLGraphicsStateGuardian::issue_render_mode
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -3903,6 +3848,77 @@ issue_depth_offset(const DepthOffsetAttrib *attrib) {
   report_my_gl_errors();
   report_my_gl_errors();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::do_issue_material
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+do_issue_material() {
+  static Material empty;
+  const Material *material;
+  if (_pending_material == (MaterialAttrib *)NULL || 
+      _pending_material->is_off()) {
+    material = &empty;
+  } else {
+    material = _pending_material->get_material();
+  }
+
+  GLenum face = material->get_twoside() ? GL_FRONT_AND_BACK : GL_FRONT;
+
+  GLP(Materialfv)(face, GL_SPECULAR, material->get_specular().get_data());
+  GLP(Materialfv)(face, GL_EMISSION, material->get_emission().get_data());
+  GLP(Materialf)(face, GL_SHININESS, material->get_shininess());
+
+  if (material->has_ambient() && material->has_diffuse()) {
+    // The material has both an ambient and diffuse specified.  This
+    // means we do not need glMaterialColor().
+    GLP(Disable)(GL_COLOR_MATERIAL);
+    GLP(Materialfv)(face, GL_AMBIENT, material->get_ambient().get_data());
+    GLP(Materialfv)(face, GL_DIFFUSE, material->get_diffuse().get_data());
+
+  } else if (material->has_ambient()) {
+    // The material specifies an ambient, but not a diffuse component.
+    // The diffuse component comes from the object's color.
+    GLP(Materialfv)(face, GL_AMBIENT, material->get_ambient().get_data());
+    if (_has_material_force_color) {
+      GLP(Disable)(GL_COLOR_MATERIAL);
+      GLP(Materialfv)(face, GL_DIFFUSE, _material_force_color.get_data());
+    } else {
+      GLP(ColorMaterial)(face, GL_DIFFUSE);
+      GLP(Enable)(GL_COLOR_MATERIAL);
+    }
+
+  } else if (material->has_diffuse()) {
+    // The material specifies a diffuse, but not an ambient component.
+    // The ambient component comes from the object's color.
+    GLP(Materialfv)(face, GL_DIFFUSE, material->get_diffuse().get_data());
+    if (_has_material_force_color) {
+      GLP(Disable)(GL_COLOR_MATERIAL);
+      GLP(Materialfv)(face, GL_AMBIENT, _material_force_color.get_data());
+    } else {
+      GLP(ColorMaterial)(face, GL_AMBIENT);
+      GLP(Enable)(GL_COLOR_MATERIAL);
+    }
+
+  } else {
+    // The material specifies neither a diffuse nor an ambient
+    // component.  Both components come from the object's color.
+    if (_has_material_force_color) {
+      GLP(Disable)(GL_COLOR_MATERIAL);
+      GLP(Materialfv)(face, GL_AMBIENT, _material_force_color.get_data());
+      GLP(Materialfv)(face, GL_DIFFUSE, _material_force_color.get_data());
+    } else {
+      GLP(ColorMaterial)(face, GL_AMBIENT_AND_DIFFUSE);
+      GLP(Enable)(GL_COLOR_MATERIAL);
+    }
+  }
+
+  GLP(LightModeli)(GL_LIGHT_MODEL_LOCAL_VIEWER, material->get_local());
+  GLP(LightModeli)(GL_LIGHT_MODEL_TWO_SIDE, material->get_twoside());
+  report_my_gl_errors();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::bind_light
 //     Function: GLGraphicsStateGuardian::bind_light
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -3916,7 +3932,7 @@ bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
   GLenum id = get_light_id(light_id);
   GLenum id = get_light_id(light_id);
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
   GLP(Lightfv)(id, GL_AMBIENT, black.get_data());
   GLP(Lightfv)(id, GL_AMBIENT, black.get_data());
-  GLP(Lightfv)(id, GL_DIFFUSE, light_obj->get_color().get_data());
+  GLP(Lightfv)(id, GL_DIFFUSE, get_light_color(light_obj));
   GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data());
   GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data());
 
 
   // Position needs to specify x, y, z, and w
   // Position needs to specify x, y, z, and w
@@ -3956,7 +3972,7 @@ bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
   GLenum id = get_light_id( light_id );
   GLenum id = get_light_id( light_id );
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
   GLP(Lightfv)(id, GL_AMBIENT, black.get_data());
   GLP(Lightfv)(id, GL_AMBIENT, black.get_data());
-  GLP(Lightfv)(id, GL_DIFFUSE, light_obj->get_color().get_data());
+  GLP(Lightfv)(id, GL_DIFFUSE, get_light_color(light_obj));
   GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data());
   GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data());
 
 
   // Position needs to specify x, y, z, and w.
   // Position needs to specify x, y, z, and w.
@@ -4000,7 +4016,7 @@ bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
   GLenum id = get_light_id(light_id);
   GLenum id = get_light_id(light_id);
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
   GLP(Lightfv)(id, GL_AMBIENT, black.get_data());
   GLP(Lightfv)(id, GL_AMBIENT, black.get_data());
-  GLP(Lightfv)(id, GL_DIFFUSE, light_obj->get_color().get_data());
+  GLP(Lightfv)(id, GL_DIFFUSE, get_light_color(light_obj));
   GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data());
   GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data());
 
 
   // Position needs to specify x, y, z, and w
   // Position needs to specify x, y, z, and w
@@ -4984,6 +5000,25 @@ issue_scaled_color(const Colorf &color) const {
   GLP(Color4fv)(transformed.get_data());
   GLP(Color4fv)(transformed.get_data());
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::get_light_color
+//       Access: Public
+//  Description: Returns the array of four floats that should be
+//               issued as the light's color, as scaled by the current
+//               value of _light_color_scale, in the case of
+//               color_scale_via_lighting.
+////////////////////////////////////////////////////////////////////
+const float *CLP(GraphicsStateGuardian)::
+get_light_color(Light *light) const {
+  static Colorf c;
+  c = light->get_color();
+  c.set(c[0] * _light_color_scale[0],
+        c[1] * _light_color_scale[1],
+        c[2] * _light_color_scale[2],
+        c[3] * _light_color_scale[3]);
+  return c.get_data();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::slot_new_light
 //     Function: GLGraphicsStateGuardian::slot_new_light
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual
@@ -5029,7 +5064,12 @@ enable_lighting(bool enable) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 set_ambient_light(const Colorf &color) {
 set_ambient_light(const Colorf &color) {
-  GLP(LightModelfv)(GL_LIGHT_MODEL_AMBIENT, color.get_data());
+  Colorf c = color;
+  c.set(c[0] * _light_color_scale[0],
+        c[1] * _light_color_scale[1],
+        c[2] * _light_color_scale[2],
+        c[3] * _light_color_scale[3]);
+  GLP(LightModelfv)(GL_LIGHT_MODEL_AMBIENT, c.get_data());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -5306,12 +5346,6 @@ void CLP(GraphicsStateGuardian)::
 finish_modify_state() {
 finish_modify_state() {
   GraphicsStateGuardian::finish_modify_state();
   GraphicsStateGuardian::finish_modify_state();
 
 
-  // Apply the texture, if it needs to be reapplied.
-  if (_texture_stale) {
-    _texture_stale = false;
-    do_issue_texture();
-  }
-
   // If one of the previously-loaded TexGen modes modified the texture
   // If one of the previously-loaded TexGen modes modified the texture
   // matrix, then if either state changed, we have to change both of
   // matrix, then if either state changed, we have to change both of
   // them now.
   // them now.
@@ -5656,7 +5690,7 @@ do_auto_rescale_normal() {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::do_issue_texture
 //     Function: GLGraphicsStateGuardian::do_issue_texture
-//       Access: Protected
+//       Access: Protected, Virtual
 //  Description: This is called by finish_modify_state() when the
 //  Description: This is called by finish_modify_state() when the
 //               texture state has changed.
 //               texture state has changed.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 5 - 4
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -123,19 +123,17 @@ public:
   virtual void release_index_buffer(IndexBufferContext *ibc);
   virtual void release_index_buffer(IndexBufferContext *ibc);
   const unsigned char *setup_primitive(const qpGeomPrimitive *data);
   const unsigned char *setup_primitive(const qpGeomPrimitive *data);
 
 
-  virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state);
+  virtual PT(qpGeomMunger) get_geom_munger(const RenderState *state);
 
 
   virtual void framebuffer_copy_to_texture
   virtual void framebuffer_copy_to_texture
     (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb);
     (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb);
   virtual bool framebuffer_copy_to_ram
   virtual bool framebuffer_copy_to_ram
     (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb);
     (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb);
 
 
-  virtual void apply_material(const Material *material);
   void apply_fog(Fog *fog);
   void apply_fog(Fog *fog);
 
 
   virtual void issue_transform(const TransformState *transform);
   virtual void issue_transform(const TransformState *transform);
   virtual void issue_tex_matrix(const TexMatrixAttrib *attrib);
   virtual void issue_tex_matrix(const TexMatrixAttrib *attrib);
-  virtual void issue_material(const MaterialAttrib *attrib);
   virtual void issue_render_mode(const RenderModeAttrib *attrib);
   virtual void issue_render_mode(const RenderModeAttrib *attrib);
   virtual void issue_antialias(const AntialiasAttrib *);
   virtual void issue_antialias(const AntialiasAttrib *);
   virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib);
   virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib);
@@ -152,6 +150,8 @@ public:
   virtual void issue_cg_shader_bind(const CgShaderAttrib *attrib);
   virtual void issue_cg_shader_bind(const CgShaderAttrib *attrib);
 #endif
 #endif
 
 
+  virtual void do_issue_material();
+
   virtual void bind_light(PointLight *light_obj, const NodePath &light, 
   virtual void bind_light(PointLight *light_obj, const NodePath &light, 
                           int light_id);
                           int light_id);
   virtual void bind_light(DirectionalLight *light_obj, const NodePath &light, 
   virtual void bind_light(DirectionalLight *light_obj, const NodePath &light, 
@@ -170,6 +170,7 @@ public:
   void dump_state(void);
   void dump_state(void);
 
 
   void issue_scaled_color(const Colorf &color) const;
   void issue_scaled_color(const Colorf &color) const;
+  const float *get_light_color(Light *light) const;
 
 
   INLINE static bool report_errors(int line, const char *source_file);
   INLINE static bool report_errors(int line, const char *source_file);
   INLINE void report_my_errors(int line, const char *source_file);
   INLINE void report_my_errors(int line, const char *source_file);
@@ -256,7 +257,7 @@ protected:
   static CPT(RenderState) get_flat_state();
   static CPT(RenderState) get_flat_state();
 
 
   void do_auto_rescale_normal();
   void do_auto_rescale_normal();
-  void do_issue_texture();
+  virtual void do_issue_texture();
   void specify_texture(Texture *tex);
   void specify_texture(Texture *tex);
   void apply_texture(TextureContext *tc);
   void apply_texture(TextureContext *tc);
   bool upload_texture(CLP(TextureContext) *gtc);
   bool upload_texture(CLP(TextureContext) *gtc);

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

@@ -162,11 +162,11 @@ ConfigVariableBool display_list_animation
 
 
 ConfigVariableBool connect_triangle_strips
 ConfigVariableBool connect_triangle_strips
 ("connect-triangle-strips", true,
 ("connect-triangle-strips", true,
- PRC_DESC("Set this true to set a batch of triangle strips to the graphics "
+ PRC_DESC("Set this true to send a batch of triangle strips to the graphics "
           "card as one long triangle strip, connected by degenerate "
           "card as one long triangle strip, connected by degenerate "
           "triangles, or false to send them as separate triangle strips "
           "triangles, or false to send them as separate triangle strips "
-          "with no degenerate triangles.  In many cases, using one long "
-          "triangle strip can help performance by reducing the number "
+          "with no degenerate triangles.  On PC hardware, using one long "
+          "triangle strip may help performance by reducing the number "
           "of separate graphics calls that have to be made."));
           "of separate graphics calls that have to be made."));
 
 
 ConfigVariableBool use_qpgeom
 ConfigVariableBool use_qpgeom

+ 3 - 3
panda/src/gobj/material.I

@@ -24,10 +24,10 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Material::
 INLINE Material::
 Material() {
 Material() {
-  _ambient.set(0.0f, 0.0f, 0.0f, 0.0f);
+  _ambient.set(1.0f, 1.0f, 1.0f, 1.0f);
   _diffuse.set(1.0f, 1.0f, 1.0f, 1.0f);
   _diffuse.set(1.0f, 1.0f, 1.0f, 1.0f);
-  _specular.set(0.0f, 0.0f, 0.0f, 0.0f);
-  _emission.set(0.0f, 0.0f, 0.0f, 0.0f);
+  _specular.set(0.0f, 0.0f, 0.0f, 1.0f);
+  _emission.set(0.0f, 0.0f, 0.0f, 1.0f);
   _shininess = 0.0;
   _shininess = 0.0;
   _flags = 0;
   _flags = 0;
 }
 }

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

@@ -633,81 +633,6 @@ transform_vertices(const LMatrix4f &mat) {
   }
   }
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeom::munge_geom
-//       Access: Published
-//  Description: Applies the indicated munger to the geom and its
-//               data, and returns a (possibly different) geom and
-//               data, according to the munger's whim.  
-//
-//               The assumption is that for a particular geom and a
-//               particular munger, the result will always be the
-//               same; so this result may be cached.
-////////////////////////////////////////////////////////////////////
-void qpGeom::
-munge_geom(const qpGeomMunger *munger,
-           CPT(qpGeom) &result, CPT(qpGeomVertexData) &data) const {
-  CPT(qpGeomVertexData) source_data = data;
-
-  // Look up the munger in our cache--maybe we've recently applied it.
-  {
-    CDReader cdata(_cycler);
-    CacheEntry temp_entry(source_data, munger);
-    temp_entry.local_object();
-    Cache::const_iterator ci = cdata->_cache.find(&temp_entry);
-    if (ci != cdata->_cache.end()) {
-      CacheEntry *entry = (*ci);
-
-      if (get_modified() <= entry->_geom_result->get_modified() &&
-          data->get_modified() <= entry->_data_result->get_modified()) {
-        // The cache entry is still good; use it.
-
-        // Record a cache hit, so this element will stay in the cache a
-        // while longer.
-        entry->refresh();
-        result = entry->_geom_result;
-        data = entry->_data_result;
-        return;
-      }
-
-      // The cache entry is stale, remove it.
-      if (gobj_cat.is_debug()) {
-        gobj_cat.debug()
-          << "Cache entry " << *entry << " is stale, removing.\n";
-      }
-      entry->erase();
-      CDWriter cdataw(((qpGeom *)this)->_cycler, cdata);
-      cdataw->_cache.erase(entry);
-    }
-  }
-
-  // Ok, invoke the munger.
-  PStatTimer timer(qpGeomMunger::_munge_pcollector);
-
-  result = this;
-  if (munger != (qpGeomMunger *)NULL) {
-    data = munger->munge_data(data);
-    ((qpGeomMunger *)munger)->munge_geom_impl(result, data);
-  }
-
-  {
-    // Record the new result in the cache.
-    CacheEntry *entry;
-    {
-      CDWriter cdata(((qpGeom *)this)->_cycler);
-      entry = new CacheEntry((qpGeom *)this, source_data, munger,
-                             result, data);
-      bool inserted = cdata->_cache.insert(entry).second;
-      nassertv(inserted);
-    }
-    
-    // And tell the cache manager about the new entry.  (It might
-    // immediately request a delete from the cache of the thing we
-    // just added.)
-    entry->record();
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeom::check_valid
 //     Function: qpGeom::check_valid
 //       Access: Published
 //       Access: Published

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

@@ -105,9 +105,6 @@ PUBLISHED:
   // Temporarily virtual.
   // Temporarily virtual.
   virtual void transform_vertices(const LMatrix4f &mat);
   virtual void transform_vertices(const LMatrix4f &mat);
 
 
-  void munge_geom(const qpGeomMunger *munger,
-                  CPT(qpGeom) &result, CPT(qpGeomVertexData) &data) const;
-
   // Temporarily virtual.
   // Temporarily virtual.
   virtual bool check_valid() const;
   virtual bool check_valid() const;
 
 
@@ -227,6 +224,7 @@ private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
 
 
   friend class CacheEntry;
   friend class CacheEntry;
+  friend class qpGeomMunger;
 };
 };
 
 
 INLINE ostream &operator << (ostream &out, const qpGeom &obj);
 INLINE ostream &operator << (ostream &out, const qpGeom &obj);

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

@@ -45,7 +45,7 @@ is_registered() const {
 //               normally; you should use only the returned value from
 //               normally; you should use only the returned value from
 //               this point on.
 //               this point on.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE CPT(qpGeomMunger) qpGeomMunger::
+INLINE PT(qpGeomMunger) qpGeomMunger::
 register_munger(qpGeomMunger *munger) {
 register_munger(qpGeomMunger *munger) {
   return get_registry()->register_munger(munger);
   return get_registry()->register_munger(munger);
 }
 }

+ 75 - 2
panda/src/gobj/qpgeomMunger.cxx

@@ -32,7 +32,7 @@ PStatCollector qpGeomMunger::_munge_pcollector("*:Munge");
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 qpGeomMunger::
 qpGeomMunger::
-qpGeomMunger(const GraphicsStateGuardianBase *, const RenderState *) :
+qpGeomMunger() :
   _is_registered(false)
   _is_registered(false)
 {
 {
 #ifndef NDEBUG
 #ifndef NDEBUG
@@ -92,6 +92,79 @@ remove_data(const qpGeomVertexData *data) {
   nassertv(_is_registered);
   nassertv(_is_registered);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::munge_geom
+//       Access: Published
+//  Description: Applies the indicated munger to the geom and its
+//               data, and returns a (possibly different) geom and
+//               data, according to the munger's whim.  
+//
+//               The assumption is that for a particular geom and a
+//               particular munger, the result will always be the
+//               same; so this result may be cached.
+////////////////////////////////////////////////////////////////////
+void qpGeomMunger::
+munge_geom(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &data) {
+  CPT(qpGeomVertexData) source_data = data;
+
+  // Look up the munger in the geom's cache--maybe we've recently
+  // applied it.
+  {
+    qpGeom::CDReader cdata(geom->_cycler);
+    qpGeom::CacheEntry temp_entry(source_data, this);
+    temp_entry.local_object();
+    qpGeom::Cache::const_iterator ci = cdata->_cache.find(&temp_entry);
+    if (ci != cdata->_cache.end()) {
+      qpGeom::CacheEntry *entry = (*ci);
+
+      if (geom->get_modified() <= entry->_geom_result->get_modified() &&
+          data->get_modified() <= entry->_data_result->get_modified()) {
+        // The cache entry is still good; use it.
+
+        // Record a cache hit, so this element will stay in the cache a
+        // while longer.
+        entry->refresh();
+        geom = entry->_geom_result;
+        data = entry->_data_result;
+        return;
+      }
+
+      // The cache entry is stale, remove it.
+      if (gobj_cat.is_debug()) {
+        gobj_cat.debug()
+          << "Cache entry " << *entry << " is stale, removing.\n";
+      }
+      entry->erase();
+      qpGeom::CDWriter cdataw(((qpGeom *)geom.p())->_cycler, cdata);
+      cdataw->_cache.erase(entry);
+    }
+  }
+
+  // Ok, invoke the munger.
+  PStatTimer timer(_munge_pcollector);
+
+  CPT(qpGeom) orig_geom = geom;
+  data = munge_data(data);
+  munge_geom_impl(geom, data);
+
+  {
+    // Record the new result in the cache.
+    qpGeom::CacheEntry *entry;
+    {
+      qpGeom::CDWriter cdata(((qpGeom *)orig_geom.p())->_cycler);
+      entry = new qpGeom::CacheEntry((qpGeom *)orig_geom.p(), source_data, this,
+                                     geom, data);
+      bool inserted = cdata->_cache.insert(entry).second;
+      nassertv(inserted);
+    }
+    
+    // And tell the cache manager about the new entry.  (It might
+    // immediately request a delete from the cache of the thing we
+    // just added.)
+    entry->record();
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomMunger::do_munge_format
 //     Function: qpGeomMunger::do_munge_format
 //       Access: Protected
 //       Access: Protected
@@ -286,7 +359,7 @@ Registry() {
 //               normally; you should use only the returned value from
 //               normally; you should use only the returned value from
 //               this point on.
 //               this point on.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-CPT(qpGeomMunger) qpGeomMunger::Registry::
+PT(qpGeomMunger) qpGeomMunger::Registry::
 register_munger(qpGeomMunger *munger) {
 register_munger(qpGeomMunger *munger) {
   if (munger->is_registered()) {
   if (munger->is_registered()) {
     return munger;
     return munger;

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

@@ -60,13 +60,13 @@ class qpGeom;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA qpGeomMunger : public TypedReferenceCount, public qpGeomEnums {
 class EXPCL_PANDA qpGeomMunger : public TypedReferenceCount, public qpGeomEnums {
 public:
 public:
-  qpGeomMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state);
+  qpGeomMunger();
   qpGeomMunger(const qpGeomMunger &copy);
   qpGeomMunger(const qpGeomMunger &copy);
   void operator = (const qpGeomMunger &copy);
   void operator = (const qpGeomMunger &copy);
   virtual ~qpGeomMunger();
   virtual ~qpGeomMunger();
 
 
   INLINE bool is_registered() const;
   INLINE bool is_registered() const;
-  INLINE static CPT(qpGeomMunger) register_munger(qpGeomMunger *munger);
+  INLINE static PT(qpGeomMunger) register_munger(qpGeomMunger *munger);
 
 
   INLINE CPT(qpGeomVertexFormat) munge_format(const qpGeomVertexFormat *format,
   INLINE CPT(qpGeomVertexFormat) munge_format(const qpGeomVertexFormat *format,
                                               const qpGeomVertexAnimationSpec &animation) const;
                                               const qpGeomVertexAnimationSpec &animation) const;
@@ -74,7 +74,7 @@ public:
   INLINE CPT(qpGeomVertexData) munge_data(const qpGeomVertexData *data) const;
   INLINE CPT(qpGeomVertexData) munge_data(const qpGeomVertexData *data) const;
   void remove_data(const qpGeomVertexData *data);
   void remove_data(const qpGeomVertexData *data);
 
 
-  // Also see Geom::munge_geom() for the primary interface.
+  void munge_geom(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &data);
 
 
 public:
 public:
   INLINE int compare_to(const qpGeomMunger &other) const;
   INLINE int compare_to(const qpGeomMunger &other) const;
@@ -132,7 +132,7 @@ private:
   class EXPCL_PANDA Registry {
   class EXPCL_PANDA Registry {
   public:
   public:
     Registry();
     Registry();
-    CPT(qpGeomMunger) register_munger(qpGeomMunger *munger);
+    PT(qpGeomMunger) register_munger(qpGeomMunger *munger);
     void unregister_munger(qpGeomMunger *munger);
     void unregister_munger(qpGeomMunger *munger);
 
 
     Mungers _mungers;
     Mungers _mungers;

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

@@ -145,7 +145,7 @@ public:
   virtual IndexBufferContext *prepare_index_buffer(qpGeomPrimitive *data)=0;
   virtual IndexBufferContext *prepare_index_buffer(qpGeomPrimitive *data)=0;
   virtual void release_index_buffer(IndexBufferContext *ibc)=0;
   virtual void release_index_buffer(IndexBufferContext *ibc)=0;
 
 
-  virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state)=0;
+  virtual PT(qpGeomMunger) get_geom_munger(const RenderState *state)=0;
 
 
   virtual void set_state_and_transform(const RenderState *state,
   virtual void set_state_and_transform(const RenderState *state,
                                        const TransformState *transform)=0;
                                        const TransformState *transform)=0;
@@ -205,8 +205,6 @@ public:
   virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex)=0;
   virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex)=0;
   virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex)=0;
   virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex)=0;
 
 
-  virtual void apply_material(const Material *material)=0;
-
   virtual CoordinateSystem get_internal_coordinate_system() const=0;
   virtual CoordinateSystem get_internal_coordinate_system() const=0;
 
 
   virtual void issue_transform(const TransformState *) { }
   virtual void issue_transform(const TransformState *) { }

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

@@ -91,6 +91,7 @@
     shadeModelAttrib.I shadeModelAttrib.h \
     shadeModelAttrib.I shadeModelAttrib.h \
     showBoundsEffect.I showBoundsEffect.h \
     showBoundsEffect.I showBoundsEffect.h \
     spotlight.I spotlight.h \
     spotlight.I spotlight.h \
+    stateMunger.I stateMunger.h \
     switchNode.I switchNode.h \
     switchNode.I switchNode.h \
     texMatrixAttrib.I texMatrixAttrib.h \
     texMatrixAttrib.I texMatrixAttrib.h \
     texProjectorEffect.I texProjectorEffect.h \
     texProjectorEffect.I texProjectorEffect.h \
@@ -188,6 +189,7 @@
     shadeModelAttrib.cxx \
     shadeModelAttrib.cxx \
     showBoundsEffect.cxx \
     showBoundsEffect.cxx \
     spotlight.cxx \
     spotlight.cxx \
+    stateMunger.cxx \
     switchNode.cxx \
     switchNode.cxx \
     texMatrixAttrib.cxx \
     texMatrixAttrib.cxx \
     texProjectorEffect.cxx \
     texProjectorEffect.cxx \
@@ -281,6 +283,7 @@
     shadeModelAttrib.I shadeModelAttrib.h \
     shadeModelAttrib.I shadeModelAttrib.h \
     showBoundsEffect.I showBoundsEffect.h \
     showBoundsEffect.I showBoundsEffect.h \
     spotlight.I spotlight.h \
     spotlight.I spotlight.h \
+    stateMunger.I stateMunger.h \
     switchNode.I switchNode.h \
     switchNode.I switchNode.h \
     texMatrixAttrib.I texMatrixAttrib.h \
     texMatrixAttrib.I texMatrixAttrib.h \
     texProjectorEffect.I texProjectorEffect.h \
     texProjectorEffect.I texProjectorEffect.h \

+ 2 - 0
panda/src/pgraph/config_pgraph.cxx

@@ -82,6 +82,7 @@
 #include "shadeModelAttrib.h"
 #include "shadeModelAttrib.h"
 #include "showBoundsEffect.h"
 #include "showBoundsEffect.h"
 #include "spotlight.h"
 #include "spotlight.h"
+#include "stateMunger.h"
 #include "switchNode.h"
 #include "switchNode.h"
 #include "texMatrixAttrib.h"
 #include "texMatrixAttrib.h"
 #include "texProjectorEffect.h"
 #include "texProjectorEffect.h"
@@ -320,6 +321,7 @@ init_libpgraph() {
   ShadeModelAttrib::init_type();
   ShadeModelAttrib::init_type();
   ShowBoundsEffect::init_type();
   ShowBoundsEffect::init_type();
   Spotlight::init_type();
   Spotlight::init_type();
+  StateMunger::init_type();
   SwitchNode::init_type();
   SwitchNode::init_type();
   TexMatrixAttrib::init_type();
   TexMatrixAttrib::init_type();
   TexProjectorEffect::init_type();
   TexProjectorEffect::init_type();

+ 2 - 2
panda/src/pgraph/cullResult.I

@@ -63,13 +63,13 @@ get_bin(int bin_index) {
 //               if we haven't already created one for this state;
 //               if we haven't already created one for this state;
 //               otherwise, it will return the existing one.
 //               otherwise, it will return the existing one.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE CPT(qpGeomMunger) CullResult::
+INLINE PT(qpGeomMunger) CullResult::
 get_geom_munger(const RenderState *state) {
 get_geom_munger(const RenderState *state) {
   Mungers::iterator mi = _mungers.find(state);
   Mungers::iterator mi = _mungers.find(state);
   if (mi != _mungers.end()) {
   if (mi != _mungers.end()) {
     return (*mi).second;
     return (*mi).second;
   }
   }
-  CPT(qpGeomMunger) munger = _gsg->get_geom_munger(state);
+  PT(qpGeomMunger) munger = _gsg->get_geom_munger(state);
   _mungers.insert(Mungers::value_type(state, munger));
   _mungers.insert(Mungers::value_type(state, munger));
   return munger;
   return munger;
 }
 }

+ 2 - 2
panda/src/pgraph/cullResult.h

@@ -66,7 +66,7 @@ public:
 
 
 private:
 private:
   CullBin *make_new_bin(int bin_index);
   CullBin *make_new_bin(int bin_index);
-  INLINE CPT(qpGeomMunger) get_geom_munger(const RenderState *state);
+  INLINE PT(qpGeomMunger) get_geom_munger(const RenderState *state);
 
 
   static CPT(RenderState) get_binary_state();
   static CPT(RenderState) get_binary_state();
   static CPT(RenderState) get_dual_transparent_state();
   static CPT(RenderState) get_dual_transparent_state();
@@ -75,7 +75,7 @@ private:
 
 
   GraphicsStateGuardianBase *_gsg;
   GraphicsStateGuardianBase *_gsg;
 
 
-  typedef pmap<CPT(RenderState), CPT(qpGeomMunger) > Mungers;
+  typedef pmap<CPT(RenderState), PT(qpGeomMunger) > Mungers;
   Mungers _mungers;
   Mungers _mungers;
 
 
   typedef pvector< PT(CullBin) > Bins;
   typedef pvector< PT(CullBin) > Bins;

+ 8 - 2
panda/src/pgraph/cullableObject.cxx

@@ -23,6 +23,7 @@
 #include "cullTraverser.h"
 #include "cullTraverser.h"
 #include "sceneSetup.h"
 #include "sceneSetup.h"
 #include "lens.h"
 #include "lens.h"
+#include "stateMunger.h"
 #include "pStatTimer.h"
 #include "pStatTimer.h"
 #include "qpgeomVertexWriter.h"
 #include "qpgeomVertexWriter.h"
 #include "qpgeomVertexReader.h"
 #include "qpgeomVertexReader.h"
@@ -42,7 +43,7 @@ TypeHandle CullableObject::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CullableObject::
 void CullableObject::
 munge_geom(GraphicsStateGuardianBase *gsg,
 munge_geom(GraphicsStateGuardianBase *gsg,
-           const qpGeomMunger *munger, const CullTraverser *traverser) {
+           qpGeomMunger *munger, const CullTraverser *traverser) {
   if (_geom != (Geom *)NULL) {
   if (_geom != (Geom *)NULL) {
     // 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.
@@ -73,7 +74,12 @@ munge_geom(GraphicsStateGuardianBase *gsg,
 
 
       // Now invoke the munger to ensure the resulting geometry is in
       // Now invoke the munger to ensure the resulting geometry is in
       // a GSG-friendly form.
       // a GSG-friendly form.
-      qpgeom->munge_geom(munger, qpgeom, _munged_data);
+      munger->munge_geom(qpgeom, _munged_data);
+
+      StateMunger *state_munger;
+      DCAST_INTO_V(state_munger, munger);
+      _state = state_munger->munge_state(_state);
+
       CPT(qpGeomVertexData) animated_vertices = 
       CPT(qpGeomVertexData) animated_vertices = 
         _munged_data->animate_vertices();
         _munged_data->animate_vertices();
 #ifndef NDEBUG
 #ifndef NDEBUG

+ 2 - 2
panda/src/pgraph/cullableObject.h

@@ -58,7 +58,7 @@ public:
   INLINE bool has_decals() const;
   INLINE bool has_decals() const;
 
 
   void munge_geom(GraphicsStateGuardianBase *gsg,
   void munge_geom(GraphicsStateGuardianBase *gsg,
-                  const qpGeomMunger *munger, const CullTraverser *traverser);
+                  qpGeomMunger *munger, const CullTraverser *traverser);
   INLINE void draw(GraphicsStateGuardianBase *gsg);
   INLINE void draw(GraphicsStateGuardianBase *gsg);
 
 
 public:
 public:
@@ -77,7 +77,7 @@ PUBLISHED:
 
 
 public:
 public:
   CPT(Geom) _geom;
   CPT(Geom) _geom;
-  CPT(qpGeomMunger) _munger;
+  PT(qpGeomMunger) _munger;
   CPT(qpGeomVertexData) _munged_data;
   CPT(qpGeomVertexData) _munged_data;
   CPT(RenderState) _state;
   CPT(RenderState) _state;
   CPT(TransformState) _transform;
   CPT(TransformState) _transform;

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

@@ -11,6 +11,7 @@
 #include "shadeModelAttrib.cxx"
 #include "shadeModelAttrib.cxx"
 #include "showBoundsEffect.cxx"
 #include "showBoundsEffect.cxx"
 #include "spotlight.cxx"
 #include "spotlight.cxx"
+#include "stateMunger.cxx"
 #include "switchNode.cxx"
 #include "switchNode.cxx"
 #include "texMatrixAttrib.cxx"
 #include "texMatrixAttrib.cxx"
 #include "texProjectorEffect.cxx"
 #include "texProjectorEffect.cxx"

+ 18 - 0
panda/src/pgraph/stateMunger.I

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

+ 50 - 0
panda/src/pgraph/stateMunger.cxx

@@ -0,0 +1,50 @@
+// Filename: stateMunger.cxx
+// Created by:  drose (04May05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "stateMunger.h"
+
+TypeHandle StateMunger::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: StateMunger::munge_state
+//       Access: Public
+//  Description: Given an input state, returns the munged state.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) StateMunger::
+munge_state(const RenderState *state) {
+  CPT(RenderState) ptstate = state;
+  StateMap::iterator mi = _state_map.find(ptstate);
+  if (mi != _state_map.end()) {
+    return (*mi).second;
+  }
+
+  CPT(RenderState) result = munge_state_impl(state);
+  _state_map[ptstate] = result;
+
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StateMunger::munge_state_impl
+//       Access: Protected, Virtual
+//  Description: Given an input state, returns the munged state.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) StateMunger::
+munge_state_impl(const RenderState *state) {
+  return state;
+}

+ 65 - 0
panda/src/pgraph/stateMunger.h

@@ -0,0 +1,65 @@
+// Filename: stateMunger.h
+// Created by:  drose (04May05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 STATEMUNGER_H
+#define STATEMUNGER_H
+
+#include "pandabase.h"
+#include "qpgeomMunger.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : StateMunger
+// Description : This is just a simple derivative of GeomMunger that
+//               adds the ability to munge states.  That functionality
+//               can't be declared in the base class, since it doesn't
+//               really know about RenderState.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA StateMunger : public qpGeomMunger {
+public:
+  CPT(RenderState) munge_state(const RenderState *state);
+
+protected:
+  CPT(RenderState) munge_state_impl(const RenderState *state);
+
+  typedef pmap<CPT(RenderState), CPT(RenderState) > StateMap;
+  StateMap _state_map;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    qpGeomMunger::init_type();
+    register_type(_type_handle, "StateMunger",
+                  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 "stateMunger.I"
+
+#endif
+