2
0
Эх сурвалжийг харах

add alpha-scale-via-texture

David Rose 19 жил өмнө
parent
commit
962f43800d

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

@@ -201,7 +201,19 @@ ConfigVariableBool color_scale_via_lighting
           "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."));
+          "it.  See also alpha-scale-via-texture."));
+
+ConfigVariableBool alpha_scale_via_texture
+("alpha-scale-via-texture", false,
+ PRC_DESC("When this is true, Panda will try to implement "
+          "ColorScaleAttribs that affect alpha by "
+          "creating an additional Texture layer over the geometry "
+          "with a uniform alpha scale applied everywhere, if there "
+          "is at least one available Texture slot available on the "
+          "multitexture pipeline.  Set this false to avoid this "
+          "trickery, so that texturing is only enabled when the "
+          "application specifically enables it.  See also "
+          "color-scale-via-lighting."));
 
 ConfigVariableInt win_size
 ("win-size", "640 480",

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

@@ -61,6 +61,7 @@ extern EXPCL_PANDA ConfigVariableString red_blue_stereo_colors;
 extern EXPCL_PANDA ConfigVariableBool depth_offset_decals;
 extern EXPCL_PANDA ConfigVariableBool auto_generate_mipmaps;
 extern EXPCL_PANDA ConfigVariableBool color_scale_via_lighting;
+extern EXPCL_PANDA ConfigVariableBool alpha_scale_via_texture;
 
 extern EXPCL_PANDA ConfigVariableInt win_size;
 extern EXPCL_PANDA ConfigVariableInt win_origin;

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

@@ -573,6 +573,51 @@ get_color_scale_via_lighting() const {
   return _color_scale_via_lighting;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_alpha_scale_via_texture
+//       Access: Published
+//  Description: Returns true if this particular GSG can implement (or
+//               would prefer to implement) an alpha scale via an
+//               additional Texture layer, or false if we need to
+//               actually munge the alpha.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsStateGuardian::
+get_alpha_scale_via_texture() const {
+  return _alpha_scale_via_texture;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_alpha_scale_via_texture
+//       Access: Published
+//  Description: This variant of get_alpha_scale_via_texture() answers
+//               the question of whether the GSG can implement an
+//               alpha scale via an additional Texture layer,
+//               considering the current TextureAttrib that will be in
+//               effect.  This considers whether there is at least one
+//               additional texture slot available on the GSG.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsStateGuardian::
+get_alpha_scale_via_texture(const TextureAttrib *tex_attrib) const {
+  return _alpha_scale_via_texture &&
+    (tex_attrib->get_num_on_stages() < get_max_texture_stages());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_alpha_scale_texture_stage
+//       Access: Published, Static
+//  Description: Returns the TextureStage that will be used to apply
+//               an alpha scale, if get_alpha_scale_via_texture()
+//               returns true.
+////////////////////////////////////////////////////////////////////
+INLINE TextureStage *GraphicsStateGuardian::
+get_alpha_scale_texture_stage() {
+  if (_alpha_scale_texture_stage == (TextureStage *)NULL) {
+    _alpha_scale_texture_stage = new TextureStage("alpha-scale");
+    _alpha_scale_texture_stage->set_sort(1000000000);
+  }
+  return _alpha_scale_texture_stage;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_coordinate_system
 //       Access: Published

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

@@ -38,6 +38,7 @@
 #include "drawableRegion.h"
 #include "displayRegion.h"
 #include "graphicsOutput.h"
+#include "texturePool.h"
 
 #include <algorithm>
 #include <limits.h>
@@ -68,6 +69,7 @@ PStatCollector GraphicsStateGuardian::_draw_primitive_pcollector("Draw:Primitive
 PStatCollector GraphicsStateGuardian::_clear_pcollector("Draw:Clear");
 PStatCollector GraphicsStateGuardian::_flush_pcollector("Draw:Flush");
 
+PT(TextureStage) GraphicsStateGuardian::_alpha_scale_texture_stage = NULL;
 GraphicsStateGuardian *GraphicsStateGuardian::_global_gsg = NULL;
 
 TypeHandle GraphicsStateGuardian::_type_handle;
@@ -163,6 +165,10 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   // enabling lighting even without a LightAttrib).
   _color_scale_via_lighting = color_scale_via_lighting;
 
+  // Similarly for applying a texture to achieve uniform alpha
+  // scaling.
+  _alpha_scale_via_texture = alpha_scale_via_texture;
+
   _stencil_render_states = 0;
 
   // The default is no shader support.
@@ -311,6 +317,7 @@ reset() {
 
   _color_scale_enabled = false;
   _current_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
+  _has_texture_alpha_scale = false;
 
   _has_material_force_color = false;
   _material_force_color.set(1.0f, 1.0f, 1.0f, 1.0f);
@@ -1564,6 +1571,7 @@ do_issue_color_scale() {
   const ColorScaleAttrib *attrib = _target._color_scale;
   _color_scale_enabled = attrib->has_scale();
   _current_color_scale = attrib->get_scale();
+  _has_texture_alpha_scale = false;
 
   if (_color_blend_involves_color_scale) {
     _state_rs = 0;
@@ -1580,6 +1588,13 @@ do_issue_color_scale() {
 
     determine_light_color_scale();
   }
+  if (_alpha_scale_via_texture && !_has_scene_graph_color &&
+      attrib->has_alpha_scale()) {
+    _state._texture = 0;
+    _state._tex_matrix = 0;
+
+    _has_texture_alpha_scale = true;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1909,6 +1924,28 @@ void GraphicsStateGuardian::
 end_bind_clip_planes() {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::determine_effective_texture
+//       Access: Protected
+//  Description: Assigns _effective_texture and _effective_tex_gen
+//               based on the current settings of _target._texture and
+//               _target._color_scale.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+determine_effective_texture() {
+  _effective_texture = _target._texture->filter_to_max(_max_texture_stages);
+  _effective_tex_gen = _target._tex_gen;
+
+  if (_has_texture_alpha_scale) {
+    PT(TextureStage) stage = get_alpha_scale_texture_stage();
+    PT(Texture) texture = TexturePool::get_alpha_scale_map();
+
+    _effective_texture = DCAST(TextureAttrib, _effective_texture->add_on_stage(stage, texture));
+    _effective_tex_gen = DCAST(TexGenAttrib, _effective_tex_gen->add_stage
+                               (stage, TexGenAttrib::M_constant, TexCoord3f(_current_color_scale[3], 0.0f, 0.0f)));
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::free_pointers
 //       Access: Protected, Virtual

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

@@ -139,6 +139,10 @@ PUBLISHED:
   virtual int get_supported_geom_rendering() const;
 
   INLINE bool get_color_scale_via_lighting() const;
+  INLINE bool get_alpha_scale_via_texture() const;
+  INLINE bool get_alpha_scale_via_texture(const TextureAttrib *tex_attrib) const;
+
+  INLINE static TextureStage *get_alpha_scale_texture_stage();
 
   void set_coordinate_system(CoordinateSystem cs);
   INLINE CoordinateSystem get_coordinate_system() const;
@@ -268,6 +272,8 @@ protected:
   virtual void bind_clip_plane(const NodePath &plane, int plane_id);
   virtual void end_bind_clip_planes();
 
+  void determine_effective_texture();
+
   virtual void free_pointers();
   virtual void close_gsg();
   void panic_deactivate();
@@ -292,6 +298,13 @@ protected:
   CPT(RenderState) _target_rs;
   CPT(TransformState) _internal_transform;
 
+  // The current TextureAttrib is a special case; we may further
+  // restrict it (according to graphics cards limits) or extend it
+  // (according to ColorScaleAttribs in effect) beyond what is
+  // specifically requested in the scene graph.
+  CPT(TextureAttrib) _effective_texture;
+  CPT(TexGenAttrib) _effective_tex_gen;
+
   // These are set by begin_draw_primitives(), and are only valid
   // between begin_draw_primitives() and end_draw_primitives().
   CPT(GeomMunger) _munger;
@@ -329,6 +342,7 @@ protected:
   bool _has_material_force_color;
   Colorf _material_force_color;
   LVecBase4f _light_color_scale;
+  bool _has_texture_alpha_scale;
 
   bool _tex_gen_modifies_mat;
   bool _tex_gen_point_sprite;
@@ -383,6 +397,7 @@ protected:
 
   int _supported_geom_rendering;
   bool _color_scale_via_lighting;
+  bool _alpha_scale_via_texture;
 
   int _stereo_buffer_mask;
 
@@ -391,6 +406,8 @@ protected:
   int _auto_detect_shader_model;
   int _shader_model;
 
+  static PT(TextureStage) _alpha_scale_texture_stage;
+
 public:
   // Statistics
   static PStatCollector _vertex_buffer_switch_pcollector;

+ 13 - 12
panda/src/display/standardMunger.cxx

@@ -73,20 +73,21 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
   } 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] < 0.999f) {
-      // 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.
+
+    CPT(TextureAttrib) tex_attrib = state->get_texture();
+
+    // If the GSG says it can't cheat this RGB or alpha scale, we have
+    // to apply the color scale directly.
+    if ((color_scale_attrib->has_rgb_scale() && !_gsg->get_color_scale_via_lighting()) ||
+        (color_scale_attrib->has_alpha_scale() && !_gsg->get_alpha_scale_via_texture(tex_attrib))) {
       _munge_color_scale = true;
     }
+
+    // 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.
   }
 }
 

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

@@ -5676,23 +5676,6 @@ set_state_and_transform(const RenderState *target,
     _state._texture = 0;
   }
 
-  if (_target._texture != _state._texture) {
-    do_issue_texture();
-    _state._texture = _target._texture;
-    _state._tex_gen = 0;
-    _state._tex_matrix = 0;
-  }
-
-  if (_target._material != _state._material) {
-    do_issue_material();
-    _state._material = _target._material;
-  }
-
-  if (_target._light != _state._light) {
-    do_issue_light();
-    _state._light = _target._light;
-  }
-
   // If one of the previously-loaded TexGen modes modified the texture
   // matrix, then if either state changed, we have to change both of
   // them now.
@@ -5704,14 +5687,29 @@ set_state_and_transform(const RenderState *target,
     }
   }
 
+  if (_target._texture != _state._texture ||
+      _target._tex_gen != _state._tex_gen) {
+    determine_effective_texture();
+    do_issue_texture();
+    do_issue_tex_gen();
+    _state._texture = _target._texture;
+    _state._tex_gen = _target._tex_gen;
+    _state._tex_matrix = 0;
+  }
+
   if (_target._tex_matrix != _state._tex_matrix) {
     do_issue_tex_matrix();
     _state._tex_matrix = _target._tex_matrix;
   }
 
-  if (_target._tex_gen != _state._tex_gen) {
-    do_issue_tex_gen();
-    _state._tex_gen = _target._tex_gen;
+  if (_target._material != _state._material) {
+    do_issue_material();
+    _state._material = _target._material;
+  }
+
+  if (_target._light != _state._light) {
+    do_issue_light();
+    _state._light = _target._light;
   }
 
   if (_target._stencil != _state._stencil) {
@@ -5822,7 +5820,7 @@ do_issue_texture() {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 update_standard_texture_bindings() {
-  int num_stages = _target._texture->get_num_on_stages();
+  int num_stages = _effective_texture->get_num_on_stages();
   int num_old_stages = _max_texture_stages;
   if (_state._texture != (TextureAttrib *)NULL) {
     num_old_stages = _state._texture->get_num_on_stages();
@@ -5837,8 +5835,8 @@ update_standard_texture_bindings() {
   int last_stage = -1;
   int i;
   for (i = 0; i < num_stages; i++) {
-    TextureStage *stage = _target._texture->get_on_stage(i);
-    Texture *texture = _target._texture->get_on_texture(stage);
+    TextureStage *stage = _effective_texture->get_on_stage(i);
+    Texture *texture = _effective_texture->get_on_texture(stage);
     nassertv(texture != (Texture *)NULL);
 
     if (i >= num_old_stages ||
@@ -6057,11 +6055,11 @@ disable_standard_texture_bindings() {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 do_issue_tex_matrix() {
-  int num_stages = _target._texture->get_num_on_stages();
+  int num_stages = _effective_texture->get_num_on_stages();
   nassertv(num_stages <= _max_texture_stages);
 
   for (int i = 0; i < num_stages; i++) {
-    TextureStage *stage = _target._texture->get_on_stage(i);
+    TextureStage *stage = _effective_texture->get_on_stage(i);
     _glActiveTexture(GL_TEXTURE0 + i);
 
     GLP(MatrixMode)(GL_TEXTURE);
@@ -6091,7 +6089,7 @@ void CLP(GraphicsStateGuardian)::
 do_issue_tex_gen() {
   bool force_normal = false;
 
-  int num_stages = _target._texture->get_num_on_stages();
+  int num_stages = _effective_texture->get_num_on_stages();
   nassertv(num_stages <= _max_texture_stages);
 
   // These are passed in for the four OBJECT_PLANE or EYE_PLANE
@@ -6109,7 +6107,7 @@ do_issue_tex_gen() {
   bool got_point_sprites = false;
 
   for (int i = 0; i < num_stages; i++) {
-    TextureStage *stage = _target._texture->get_on_stage(i);
+    TextureStage *stage = _effective_texture->get_on_stage(i);
     _glActiveTexture(GL_TEXTURE0 + i);
     GLP(Disable)(GL_TEXTURE_GEN_S);
     GLP(Disable)(GL_TEXTURE_GEN_T);
@@ -6119,7 +6117,7 @@ do_issue_tex_gen() {
       GLP(TexEnvi)(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE);
     }
 
-    TexGenAttrib::Mode mode = _target._tex_gen->get_mode(stage);
+    TexGenAttrib::Mode mode = _effective_tex_gen->get_mode(stage);
     switch (mode) {
     case TexGenAttrib::M_off:
     case TexGenAttrib::M_light_vector:
@@ -6301,6 +6299,35 @@ do_issue_tex_gen() {
       }
       break;
 
+    case TexGenAttrib::M_constant:
+      // To generate a constant UV(w) coordinate everywhere, we use
+      // EYE_LINEAR mode, but we construct a special matrix that
+      // flattens the vertex position to zero and then adds our
+      // desired value.
+      {
+        const TexCoord3f &v = _effective_tex_gen->get_constant_value(stage);
+
+        GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+        GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+        GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+        GLP(TexGeni)(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+
+        LVecBase4f s(0.0f, 0.0f, 0.0f, v[0]);
+        LVecBase4f t(0.0f, 0.0f, 0.0f, v[1]);
+        LVecBase4f r(0.0f, 0.0f, 0.0f, v[2]);
+
+        GLP(TexGenfv)(GL_S, GL_OBJECT_PLANE, s.get_data());
+        GLP(TexGenfv)(GL_T, GL_OBJECT_PLANE, t.get_data());
+        GLP(TexGenfv)(GL_R, GL_OBJECT_PLANE, r.get_data());
+        GLP(TexGenfv)(GL_Q, GL_OBJECT_PLANE, q_data);
+
+        GLP(Enable)(GL_TEXTURE_GEN_S);
+        GLP(Enable)(GL_TEXTURE_GEN_T);
+        GLP(Enable)(GL_TEXTURE_GEN_R);
+        GLP(Enable)(GL_TEXTURE_GEN_Q);
+      }
+      break;
+
     case TexGenAttrib::M_unused:
       break;
     }

+ 25 - 0
panda/src/gobj/texture.cxx

@@ -350,6 +350,31 @@ generate_normalization_cube_map(int size) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::generate_alpha_scale_map
+//       Access: Published
+//  Description: Generates a special 256x1 1-d texture that can be
+//               used to apply an arbitrary alpha scale to objects by
+//               judicious use of texture matrix.  The texture is a
+//               gradient, with an alpha of 0 on the left (U = 0), and
+//               255 on the right (U = 1).
+////////////////////////////////////////////////////////////////////
+void Texture::
+generate_alpha_scale_map() {
+  setup_1d_texture(256, T_unsigned_byte, F_alpha);
+  set_wrap_u(WM_clamp);
+  set_minfilter(FT_nearest);
+  set_magfilter(FT_nearest);
+
+  PTA_uchar image = make_ram_image();
+  _keep_ram_image = true;
+
+  unsigned char *p = image;
+  for (int xi = 0; xi < 256; ++xi) {
+    *p++ = xi;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::estimate_texture_memory
 //       Access: Published

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

@@ -199,6 +199,7 @@ PUBLISHED:
                              ComponentType component_type, Format format);
 
   void generate_normalization_cube_map(int size);
+  void generate_alpha_scale_map();
 
   INLINE bool read(const Filename &fullpath);
   INLINE bool read(const Filename &fullpath, const Filename &alpha_fullpath,

+ 16 - 0
panda/src/gobj/texturePool.I

@@ -143,6 +143,22 @@ get_normalization_cube_map(int size) {
   return get_global_ptr()->ns_get_normalization_cube_map(size);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePool::get_alpha_scale_map
+//       Access: Published, Static
+//  Description: Returns a standard Texture object that has been
+//               created with Texture::generate_alpha_scale_map().
+//
+//               This Texture object is used internally by Panda to
+//               apply an alpha scale to an object (instead of munging
+//               its vertices) when gsg->get_alpha_scale_via_texture()
+//               returns true.
+////////////////////////////////////////////////////////////////////
+INLINE Texture *TexturePool::
+get_alpha_scale_map() {
+  return get_global_ptr()->ns_get_alpha_scale_map();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TexturePool::add_texture
 //       Access: Published, Static

+ 17 - 0
panda/src/gobj/texturePool.cxx

@@ -657,6 +657,23 @@ ns_get_normalization_cube_map(int size) {
   return _normalization_cube_map;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePool::ns_get_alpha_scale_map
+//       Access: Private
+//  Description: The nonstatic implementation of get_alpha_scale_map().
+////////////////////////////////////////////////////////////////////
+Texture *TexturePool::
+ns_get_alpha_scale_map() {
+  MutexHolder holder(_lock);
+
+  if (_alpha_scale_map == (Texture *)NULL) {
+    _alpha_scale_map = new Texture("alpha_scale_map");
+    _alpha_scale_map->generate_alpha_scale_map();
+  }
+
+  return _alpha_scale_map;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TexturePool::ns_add_texture
 //       Access: Private

+ 3 - 0
panda/src/gobj/texturePool.h

@@ -57,6 +57,7 @@ PUBLISHED:
 				       bool read_mipmaps = false);
 
   INLINE static Texture *get_normalization_cube_map(int size);
+  INLINE static Texture *get_alpha_scale_map();
 
   INLINE static void add_texture(Texture *texture);
   INLINE static void release_texture(Texture *texture);
@@ -101,6 +102,7 @@ private:
   Texture *ns_load_cube_map(const Filename &filename_pattern,
 			    bool read_mipmaps);
   Texture *ns_get_normalization_cube_map(int size);
+  Texture *ns_get_alpha_scale_map();
 
   void ns_add_texture(Texture *texture);
   void ns_release_texture(Texture *texture);
@@ -128,6 +130,7 @@ private:
   string _fake_texture_image;
 
   PT(Texture) _normalization_cube_map;
+  PT(Texture) _alpha_scale_map;
 
   typedef pmap<string, MakeTextureFunc *> TypeRegistry;
   TypeRegistry _type_registry;

+ 26 - 15
panda/src/pgraph/colorScaleAttrib.I

@@ -17,21 +17,6 @@
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: ColorScaleAttrib::Constructor
-//       Access: Protected
-//  Description: Use ColorScaleAttrib::make() to construct a new
-//               ColorScaleAttrib object.
-////////////////////////////////////////////////////////////////////
-INLINE ColorScaleAttrib::
-ColorScaleAttrib(bool off, const LVecBase4f &scale) :
-  _off(off),
-  _scale(scale)
-{
-  quantize_scale();
-  _has_scale = !_scale.almost_equal(LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f));
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: ColorScaleAttrib::Copy Constructor
 //       Access: Protected
@@ -42,6 +27,8 @@ INLINE ColorScaleAttrib::
 ColorScaleAttrib(const ColorScaleAttrib &copy) :
   _off(copy._off),
   _has_scale(copy._has_scale),
+  _has_rgb_scale(copy._has_rgb_scale),
+  _has_alpha_scale(copy._has_alpha_scale),
   _scale(copy._scale)
 {
 }
@@ -84,6 +71,30 @@ has_scale() const {
   return _has_scale;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ColorScaleAttrib::has_rgb_scale
+//       Access: Published
+//  Description: Returns true if the ColorScaleAttrib has a
+//               non-identity scale in the RGB components (ignoring
+//               alpha), or false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool ColorScaleAttrib::
+has_rgb_scale() const {
+  return _has_rgb_scale;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorScaleAttrib::has_alpha_scale
+//       Access: Published
+//  Description: Returns true if the ColorScaleAttrib has a
+//               non-identity scale in the alpha component (ignoring
+//               RGB), or false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool ColorScaleAttrib::
+has_alpha_scale() const {
+  return _has_alpha_scale;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ColorScaleAttrib::get_scale
 //       Access: Published

+ 21 - 0
panda/src/pgraph/colorScaleAttrib.cxx

@@ -29,6 +29,23 @@
 TypeHandle ColorScaleAttrib::_type_handle;
 CPT(RenderAttrib) ColorScaleAttrib::_identity_attrib;
 
+////////////////////////////////////////////////////////////////////
+//     Function: ColorScaleAttrib::Constructor
+//       Access: Protected
+//  Description: Use ColorScaleAttrib::make() to construct a new
+//               ColorScaleAttrib object.
+////////////////////////////////////////////////////////////////////
+ColorScaleAttrib::
+ColorScaleAttrib(bool off, const LVecBase4f &scale) :
+  _off(off),
+  _scale(scale)
+{
+  quantize_scale();
+  _has_scale = !_scale.almost_equal(LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f));
+  _has_rgb_scale = !LVecBase3f(_scale[0], _scale[1], _scale[2]).almost_equal(LVecBase3f(1.0f, 1.0f, 1.0f));
+  _has_alpha_scale = !IS_NEARLY_EQUAL(_scale[3], 1.0f);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ColorScaleAttrib::make_identity
 //       Access: Published, Static
@@ -85,6 +102,8 @@ set_scale(const LVecBase4f &scale) const {
   attrib->_scale = scale;
   attrib->quantize_scale();
   attrib->_has_scale = !scale.almost_equal(LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f));
+  attrib->_has_rgb_scale = !LVecBase3f(scale[0], scale[1], scale[2]).almost_equal(LVecBase3f(1.0f, 1.0f, 1.0f));
+  attrib->_has_alpha_scale = !IS_NEARLY_EQUAL(scale[3], 1.0f);
   return return_new(attrib);
 }
 
@@ -346,4 +365,6 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   _scale.read_datagram(scan);
   quantize_scale();
   _has_scale = !_scale.almost_equal(LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f));
+  _has_rgb_scale = !LVecBase3f(_scale[0], _scale[1], _scale[2]).almost_equal(LVecBase3f(1.0f, 1.0f, 1.0f));
+  _has_alpha_scale = !IS_NEARLY_EQUAL(_scale[3], 1.0f);
 }

+ 5 - 1
panda/src/pgraph/colorScaleAttrib.h

@@ -33,7 +33,7 @@ class FactoryParams;
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA ColorScaleAttrib : public RenderAttrib {
 protected:
-  INLINE ColorScaleAttrib(bool off, const LVecBase4f &scale);
+  ColorScaleAttrib(bool off, const LVecBase4f &scale);
   INLINE ColorScaleAttrib(const ColorScaleAttrib &copy);
 
 PUBLISHED:
@@ -44,6 +44,8 @@ PUBLISHED:
   INLINE bool is_off() const;
   INLINE bool is_identity() const;
   INLINE bool has_scale() const;
+  INLINE bool has_rgb_scale() const;
+  INLINE bool has_alpha_scale() const;
   INLINE const LVecBase4f &get_scale() const;
   CPT(RenderAttrib) set_scale(const LVecBase4f &scale) const;
 
@@ -64,6 +66,8 @@ private:
 private:
   bool _off;
   bool _has_scale;
+  bool _has_rgb_scale;
+  bool _has_alpha_scale;
   LVecBase4f _scale;
   static CPT(RenderAttrib) _identity_attrib;
 

+ 30 - 0
panda/src/pgraph/nodePath.cxx

@@ -3576,6 +3576,36 @@ set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode,
   node()->set_attrib(tga->add_stage(stage, mode, source_name, light), priority);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_tex_gen
+//       Access: Published
+//  Description: Enables automatic texture coordinate generation for
+//               the indicated texture stage.  This version of this
+//               method is useful when setting M_constant, which
+//               requires a constant texture coordinate value.
+////////////////////////////////////////////////////////////////////
+void NodePath::
+set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, 
+            const TexCoord3f &constant_value, int priority) {
+  nassertv_always(!is_empty());
+
+  const RenderAttrib *attrib =
+    node()->get_attrib(TexGenAttrib::get_class_type());
+
+  CPT(TexGenAttrib) tga;
+
+  if (attrib != (const RenderAttrib *)NULL) {
+    priority = max(priority,
+                   node()->get_state()->get_override(TextureAttrib::get_class_type()));
+    tga = DCAST(TexGenAttrib, attrib);
+
+  } else {
+    tga = DCAST(TexGenAttrib, TexGenAttrib::make());
+  }
+
+  node()->set_attrib(tga->add_stage(stage, mode, constant_value), priority);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::clear_tex_gen
 //       Access: Published

+ 3 - 0
panda/src/pgraph/nodePath.h

@@ -636,6 +636,9 @@ PUBLISHED:
   void set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, 
                    const string &source_name, const NodePath &light, 
                    int priority = 0);
+  void set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, 
+                   const TexCoord3f &constant_value,
+                   int priority = 0);
   void clear_tex_gen();
   void clear_tex_gen(TextureStage *stage);
   bool has_tex_gen(TextureStage *stage) const;

+ 5 - 0
panda/src/pgraph/renderAttrib.h

@@ -164,6 +164,11 @@ PUBLISHED:
     // tangent and binormal for the particular named texture
     // coordinate set.
     M_light_vector,
+
+    // M_constant generates the same fixed texture coordinates at each
+    // vertex.  Not terribly useful, of course, except for certain
+    // special effects involving moving a flat color over an object.
+    M_constant,
   };
 
 protected:

+ 1 - 1
panda/src/pgraph/stateMunger.h

@@ -37,7 +37,7 @@ public:
   CPT(RenderState) munge_state(const RenderState *state);
 
 protected:
-  CPT(RenderState) munge_state_impl(const RenderState *state);
+  virtual CPT(RenderState) munge_state_impl(const RenderState *state);
 
   typedef pmap< WCPT(RenderState), WCPT(RenderState) > StateMap;
   StateMap _state_map;

+ 6 - 1
panda/src/pgraph/texGenAttrib.I

@@ -117,6 +117,11 @@ compare_to(const TexGenAttrib::ModeDef &other) const {
   if (compare != 0) {
     return compare;
   }
-  return strcmp(_source_name.c_str(), other._source_name.c_str());
+  compare = strcmp(_source_name.c_str(), other._source_name.c_str());
+  if (compare != 0) {
+    return compare;
+  }
+  compare = _constant_value.compare_to(other._constant_value);
+  return compare;
 }
 

+ 76 - 3
panda/src/pgraph/texGenAttrib.cxx

@@ -62,9 +62,8 @@ make() {
 //               indicated stage.
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) TexGenAttrib::
-make(TextureStage *stage, TexGenAttrib::Mode mode, 
-     const string &source_name, const NodePath &light) {
-  return DCAST(TexGenAttrib, make())->add_stage(stage, mode, source_name, light);
+make(TextureStage *stage, TexGenAttrib::Mode mode) {
+  return DCAST(TexGenAttrib, make())->add_stage(stage, mode);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -76,8 +75,35 @@ make(TextureStage *stage, TexGenAttrib::Mode mode,
 //               replaced.
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) TexGenAttrib::
+add_stage(TextureStage *stage, TexGenAttrib::Mode mode) const {
+  nassertr(mode != M_light_vector && mode != M_constant, this);
+
+  CPT(RenderAttrib) removed = remove_stage(stage);
+  TexGenAttrib *attrib = new TexGenAttrib(*DCAST(TexGenAttrib, removed));
+
+  ModeDef &mode_def = attrib->_stages[stage];
+  mode_def._mode = mode;
+  attrib->record_stage(stage, mode_def);
+
+  return return_new(attrib);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TexGenAttrib::add_stage
+//       Access: Published, Static
+//  Description: Returns a new TexGenAttrib just like this one,
+//               with the indicated generation mode for the given
+//               stage.  If this stage already exists, its mode is
+//               replaced.
+//
+//               This variant also accepts source_name and light,
+//               which are only meaningful if mode is M_light_vector.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) TexGenAttrib::
 add_stage(TextureStage *stage, TexGenAttrib::Mode mode, 
           const string &source_name, const NodePath &light) const {
+  nassertr(mode == M_light_vector, this);
+
   CPT(RenderAttrib) removed = remove_stage(stage);
   TexGenAttrib *attrib = new TexGenAttrib(*DCAST(TexGenAttrib, removed));
 
@@ -90,6 +116,33 @@ add_stage(TextureStage *stage, TexGenAttrib::Mode mode,
   return return_new(attrib);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TexGenAttrib::add_stage
+//       Access: Published, Static
+//  Description: Returns a new TexGenAttrib just like this one,
+//               with the indicated generation mode for the given
+//               stage.  If this stage already exists, its mode is
+//               replaced.
+//
+//               This variant also accepts constant_value, which is
+//               only meaningful if mode is M_constant.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) TexGenAttrib::
+add_stage(TextureStage *stage, TexGenAttrib::Mode mode, 
+          const TexCoord3f &constant_value) const {
+  nassertr(mode == M_constant, this);
+
+  CPT(RenderAttrib) removed = remove_stage(stage);
+  TexGenAttrib *attrib = new TexGenAttrib(*DCAST(TexGenAttrib, removed));
+
+  ModeDef &mode_def = attrib->_stages[stage];
+  mode_def._mode = mode;
+  mode_def._constant_value = constant_value;
+  attrib->record_stage(stage, mode_def);
+
+  return return_new(attrib);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TexGenAttrib::remove_stage
 //       Access: Published, Static
@@ -200,6 +253,22 @@ get_light(TextureStage *stage) const {
   return NodePath();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TexGenAttrib::get_constant_value
+//       Access: Published
+//  Description: Returns the constant value associated with the named
+//               texture stage.  This is only meaningful if the mode
+//               is M_constant.
+////////////////////////////////////////////////////////////////////
+const TexCoord3f &TexGenAttrib::
+get_constant_value(TextureStage *stage) const {
+  Stages::const_iterator mi = _stages.find(stage);
+  if (mi != _stages.end()) {
+    return (*mi).second._constant_value;
+  }
+  return TexCoord3f::zero();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TexGenAttrib::output
 //       Access: Public, Virtual
@@ -253,6 +322,10 @@ output(ostream &out) const {
           << mode_def._light;
       break;
 
+    case M_constant:
+      out << "constant: " << mode_def._constant_value;
+      break;
+
     case M_unused:
       break;
     }

+ 6 - 2
panda/src/pgraph/texGenAttrib.h

@@ -54,9 +54,11 @@ public:
 
 PUBLISHED:
   static CPT(RenderAttrib) make();
-  static CPT(RenderAttrib) make(TextureStage *stage, Mode mode, const string &source_name = string(), const NodePath &light = NodePath());
+  static CPT(RenderAttrib) make(TextureStage *stage, Mode mode);
 
-  CPT(RenderAttrib) add_stage(TextureStage *stage, Mode mode, const string &source_name = string(), const NodePath &light = NodePath()) const;
+  CPT(RenderAttrib) add_stage(TextureStage *stage, Mode mode) const;
+  CPT(RenderAttrib) add_stage(TextureStage *stage, Mode mode, const string &source_name, const NodePath &light) const;
+  CPT(RenderAttrib) add_stage(TextureStage *stage, Mode mode, const TexCoord3f &constant_value) const;
   CPT(RenderAttrib) remove_stage(TextureStage *stage) const;
 
   bool is_empty() const;
@@ -64,6 +66,7 @@ PUBLISHED:
   Mode get_mode(TextureStage *stage) const;
   string get_source_name(TextureStage *stage) const;
   NodePath get_light(TextureStage *stage) const;
+  const TexCoord3f &get_constant_value(TextureStage *stage) const;
 
   INLINE int get_geom_rendering(int geom_rendering) const;
 
@@ -94,6 +97,7 @@ private:
     Mode _mode;
     string _source_name;
     NodePath _light;
+    TexCoord3f _constant_value;
   };
   typedef pmap<PT(TextureStage), ModeDef> Stages;
   Stages _stages;