Browse Source

Support using setShaderInput with a light to bind to GLSL struct

rdb 11 years ago
parent
commit
dad8f79e96

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

@@ -1167,6 +1167,31 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LMatrix4 &
     t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,d[0],d[1],d[2],cutoff);
     t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,d[0],d[1],d[2],cutoff);
     return &t;
     return &t;
   }
   }
+  case Shader::SMO_light_ambient: {
+    LColor cur_ambient_light(0.0f, 0.0f, 0.0f, 0.0f);
+    const LightAttrib *target_light = (const LightAttrib *)
+      _target_rs->get_attrib_def(LightAttrib::get_class_slot());
+
+    int num_on_lights = target_light->get_num_on_lights();
+    if (num_on_lights == 0) {
+      // There are no lights at all.  This means, to follow the fixed-
+      // function model, we pretend there is an all-white ambient light.
+      t.set_row(3, LVecBase4(1, 1, 1, 1));
+    } else {
+      for (int li = 0; li < num_on_lights; li++) {
+        NodePath light = target_light->get_on_light(li);
+        nassertr(!light.is_empty(), &LMatrix4::zeros_mat());
+        Light *light_obj = light.node()->as_light();
+        nassertr(light_obj != (Light *)NULL, &LMatrix4::zeros_mat());
+
+        if (light_obj->get_type() == AmbientLight::get_class_type()) {
+          cur_ambient_light += light_obj->get_color();
+        }
+      }
+      t.set_row(3, cur_ambient_light);
+    }
+    return &t;
+  }
   case Shader::SMO_texmat_x: {
   case Shader::SMO_texmat_x: {
     const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, _target_rs->get_attrib_def(TexMatrixAttrib::get_class_slot()));
     const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, _target_rs->get_attrib_def(TexMatrixAttrib::get_class_slot()));
     const TextureAttrib *ta = DCAST(TextureAttrib, _target_rs->get_attrib_def(TextureAttrib::get_class_slot()));
     const TextureAttrib *ta = DCAST(TextureAttrib, _target_rs->get_attrib_def(TextureAttrib::get_class_slot()));
@@ -1330,6 +1355,167 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LMatrix4 &
       calc_projection_mat(lens)->get_mat();
       calc_projection_mat(lens)->get_mat();
     return &t;
     return &t;
   }
   }
+  case Shader::SMO_vec_constant_x_attrib: {
+    // This system is not ideal.  It will be improved in the future.
+    if (_target_shader->has_shader_input(name)) {
+      // There is an input specifying precisely this whole thing, with
+      // dot and all.  Support this, even if only for backward compatibility.
+      const LVecBase4 &data = _target_shader->get_shader_input_vector(name);
+      t = LMatrix4(data[0],data[1],data[2],data[3],
+                   data[0],data[1],data[2],data[3],
+                   data[0],data[1],data[2],data[3],
+                   data[0],data[1],data[2],data[3]);
+      return &t;
+    }
+
+    const NodePath &np = _target_shader->get_shader_input_nodepath(name->get_parent());
+    nassertr(!np.is_empty(), &LMatrix4::ident_mat());
+
+    CPT_InternalName attrib = name->get_basename();
+
+    static const CPT_InternalName IN_ambient("ambient");
+    static const CPT_InternalName IN_diffuse("diffuse");
+    static const CPT_InternalName IN_specular("specular");
+    static const CPT_InternalName IN_position("position");
+    static const CPT_InternalName IN_spotDirection("spotDirection");
+    static const CPT_InternalName IN_spotCutoff("spotCutoff");
+    static const CPT_InternalName IN_spotCosCutoff("spotCosCutoff");
+    static const CPT_InternalName IN_spotExponent("spotExponent");
+    static const CPT_InternalName IN_constantAttenuation("constantAttenuation");
+    static const CPT_InternalName IN_linearAttenuation("linearAttenuation");
+    static const CPT_InternalName IN_quadraticAttenuation("quadraticAttenuation");
+
+    if (attrib == IN_ambient) {
+#ifndef NDEBUG
+      Light *light = np.node()->as_light();
+      nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
+#endif
+      // Lights don't currently have an ambient color in Panda3D.
+      // We still have to support the attribute.
+      t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f));
+      return &t;
+
+    } else if (attrib == IN_diffuse) {
+      Light *light = np.node()->as_light();
+      nassertr(light != (Light *)NULL, &LMatrix4::ones_mat());
+
+      LColor c = light->get_color();
+      c.componentwise_mult(_light_color_scale);
+      t.set_row(3, c);
+      return &t;
+
+    } else if (attrib == IN_specular) {
+      Light *light = np.node()->as_light();
+      nassertr(light != (Light *)NULL, &LMatrix4::ones_mat());
+      t.set_row(3, light->get_specular_color());
+      return &t;
+
+    } else if (attrib == IN_position) {
+      if (np.node()->is_of_type(DirectionalLight::get_class_type())) {
+        DirectionalLight *light;
+        DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
+
+        CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent());
+        LVector3 dir = -(light->get_direction() * transform->get_mat());
+        dir *= get_scene()->get_cs_world_transform()->get_mat();
+        t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],0);
+        return &t;
+      } else {
+        LightLensNode *light;
+        DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
+        Lens *lens = light->get_lens();
+        nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
+
+        CPT(TransformState) transform =
+          get_scene()->get_cs_world_transform()->compose(
+            np.get_transform(_scene_setup->get_scene_root().get_parent()));
+
+        const LMatrix4 &light_mat = transform->get_mat();
+        LPoint3 pos = lens->get_nodal_point() * light_mat;
+        t = LMatrix4::translate_mat(pos);
+        return &t;
+      }
+    } else if (attrib == IN_spotDirection) {
+      LightLensNode *light;
+      DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
+      Lens *lens = light->get_lens();
+      nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
+
+      CPT(TransformState) transform =
+        get_scene()->get_cs_world_transform()->compose(
+          np.get_transform(_scene_setup->get_scene_root().get_parent()));
+
+      const LMatrix4 &light_mat = transform->get_mat();
+      LVector3 dir = lens->get_view_vector() * light_mat;
+      t.set_row(3, dir);
+      return &t;
+
+    } else if (attrib == IN_spotCutoff) {
+      if (np.node()->is_of_type(Spotlight::get_class_type())) {
+        LightLensNode *light;
+        DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
+        Lens *lens = light->get_lens();
+        nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
+
+        float cutoff = lens->get_hfov() * 0.5f;
+        t.set_row(3, LVecBase4(cutoff));
+        return &t;
+      } else {
+        // Other lights have no cut-off.
+        t.set_row(3, LVecBase4(180));
+        return &t;
+      }
+
+    } else if (attrib == IN_spotCosCutoff) {
+      if (np.node()->is_of_type(Spotlight::get_class_type())) {
+        LightLensNode *light;
+        DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
+        Lens *lens = light->get_lens();
+        nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
+
+        float cutoff = lens->get_hfov() * 0.5f;
+        t.set_row(3, LVecBase4(ccos(deg_2_rad(cutoff))));
+        return &t;
+      } else {
+        // Other lights have no cut-off.
+        t.set_row(3, LVecBase4(-1));
+        return &t;
+      }
+    } else if (attrib == IN_spotExponent) {
+      Light *light = np.node()->as_light();
+      nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
+
+      t.set_row(3, LVecBase4(light->get_exponent()));
+      return &t;
+
+    } else if (attrib == IN_constantAttenuation) {
+      Light *light = np.node()->as_light();
+      nassertr(light != (Light *)NULL, &LMatrix4::ones_mat());
+
+      t.set_row(3, LVecBase4(light->get_attenuation()[0]));
+      return &t;
+
+    } else if (attrib == IN_linearAttenuation) {
+      Light *light = np.node()->as_light();
+      nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
+
+      t.set_row(3, LVecBase4(light->get_attenuation()[1]));
+      return &t;
+
+    } else if (attrib == IN_quadraticAttenuation) {
+      Light *light = np.node()->as_light();
+      nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
+
+      t.set_row(3, LVecBase4(light->get_attenuation()[2]));
+      return &t;
+
+    } else {
+      display_cat.error()
+        << "Shader input requests invalid attribute " << *name
+        << " from node " << np << "\n";
+      return &LMatrix4::ident_mat();
+    }
+  }
   default:
   default:
     nassertr(false /*should never get here*/, &LMatrix4::ident_mat());
     nassertr(false /*should never get here*/, &LMatrix4::ident_mat());
     return &LMatrix4::ident_mat();
     return &LMatrix4::ident_mat();

+ 12 - 7
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -4220,8 +4220,8 @@ issue_memory_barrier(GLbitfield barriers) {
 
 
   PStatGPUTimer timer(this, _memory_barrier_pcollector);
   PStatGPUTimer timer(this, _memory_barrier_pcollector);
 
 
-  if (GLCAT.is_debug()) {
-    GLCAT.debug() << "Issuing memory barriers:";
+  if (GLCAT.is_spam()) {
+    GLCAT.spam() << "Issuing memory barriers:";
   }
   }
 
 
   _glMemoryBarrier(barriers);
   _glMemoryBarrier(barriers);
@@ -4230,25 +4230,25 @@ issue_memory_barrier(GLbitfield barriers) {
   // the relevant lists of textures.
   // the relevant lists of textures.
   if (barriers & GL_TEXTURE_FETCH_BARRIER_BIT) {
   if (barriers & GL_TEXTURE_FETCH_BARRIER_BIT) {
     _textures_needing_fetch_barrier.clear();
     _textures_needing_fetch_barrier.clear();
-    GLCAT.debug(false) << " texture_fetch";
+    GLCAT.spam(false) << " texture_fetch";
   }
   }
 
 
   if (barriers & GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) {
   if (barriers & GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) {
     _textures_needing_image_access_barrier.clear();
     _textures_needing_image_access_barrier.clear();
-    GLCAT.debug(false) << " shader_image_access";
+    GLCAT.spam(false) << " shader_image_access";
   }
   }
 
 
   if (barriers & GL_TEXTURE_UPDATE_BARRIER_BIT) {
   if (barriers & GL_TEXTURE_UPDATE_BARRIER_BIT) {
     _textures_needing_update_barrier.clear();
     _textures_needing_update_barrier.clear();
-    GLCAT.debug(false) << " texture_update";
+    GLCAT.spam(false) << " texture_update";
   }
   }
 
 
   if (barriers & GL_FRAMEBUFFER_BARRIER_BIT) {
   if (barriers & GL_FRAMEBUFFER_BARRIER_BIT) {
     _textures_needing_framebuffer_barrier.clear();
     _textures_needing_framebuffer_barrier.clear();
-    GLCAT.debug(false) << " framebuffer";
+    GLCAT.spam(false) << " framebuffer";
   }
   }
 
 
-  GLCAT.debug(false) << "\n";
+  GLCAT.spam(false) << "\n";
 
 
   report_my_gl_errors();
   report_my_gl_errors();
 #endif  // OPENGLES
 #endif  // OPENGLES
@@ -8989,6 +8989,11 @@ set_state_and_transform(const RenderState *target,
     //PStatGPUTimer timer(this, _draw_set_state_light_pcollector);
     //PStatGPUTimer timer(this, _draw_set_state_light_pcollector);
     do_issue_light();
     do_issue_light();
     _state_mask.set_bit(light_slot);
     _state_mask.set_bit(light_slot);
+#ifndef OPENGLES_1
+    if (_current_shader_context) {
+      _current_shader_context->issue_parameters(Shader::SSD_light);
+    }
+#endif
   }
   }
 
 
   int stencil_slot = StencilAttrib::get_class_slot();
   int stencil_slot = StencilAttrib::get_class_slot();

+ 54 - 7
panda/src/glstuff/glShaderContext_src.cxx

@@ -412,6 +412,20 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             s->_mat_spec.push_back(bind);
             s->_mat_spec.push_back(bind);
             continue;
             continue;
           }
           }
+          if (noprefix == "LightModel.ambient") {
+            Shader::ShaderMatSpec bind;
+            bind._id = arg_id;
+            bind._piece = Shader::SMP_row3;
+            bind._func = Shader::SMF_first;
+            bind._part[0] = Shader::SMO_light_ambient;
+            bind._arg[0] = NULL;
+            bind._dep[0] = Shader::SSD_general | Shader::SSD_light;
+            bind._part[1] = Shader::SMO_identity;
+            bind._arg[1] = NULL;
+            bind._dep[1] = Shader::SSD_NONE;
+            s->_mat_spec.push_back(bind);
+            continue;
+          }
           GLCAT.error() << "Unrecognized uniform name '" << param_name_cstr << "'!\n";
           GLCAT.error() << "Unrecognized uniform name '" << param_name_cstr << "'!\n";
           continue;
           continue;
 
 
@@ -565,7 +579,8 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
               bind._arg[1] = NULL;
               bind._arg[1] = NULL;
               bind._dep[1] = Shader::SSD_NONE;
               bind._dep[1] = Shader::SSD_NONE;
               s->_mat_spec.push_back(bind);
               s->_mat_spec.push_back(bind);
-              continue; }
+              continue;
+            }
             case GL_FLOAT_MAT4: {
             case GL_FLOAT_MAT4: {
               Shader::ShaderMatSpec bind;
               Shader::ShaderMatSpec bind;
               bind._id = arg_id;
               bind._id = arg_id;
@@ -578,7 +593,43 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
               bind._arg[1] = NULL;
               bind._arg[1] = NULL;
               bind._dep[1] = Shader::SSD_NONE;
               bind._dep[1] = Shader::SSD_NONE;
               s->_mat_spec.push_back(bind);
               s->_mat_spec.push_back(bind);
-              continue; }
+              continue;
+            }
+            case GL_FLOAT:
+            case GL_FLOAT_VEC2:
+            case GL_FLOAT_VEC3:
+            case GL_FLOAT_VEC4: {
+              PT(InternalName) iname = InternalName::make(param_name);
+              if (iname->get_parent() != InternalName::get_root()) {
+                // It might be something like an attribute of a shader
+                // input, like a light parameter.  It might also just be
+                // a custom struct parameter.  We can't know yet, sadly.
+                Shader::ShaderMatSpec bind;
+                bind._id = arg_id;
+                switch (param_type) {
+                case GL_FLOAT:
+                  bind._piece = Shader::SMP_row3x1;
+                  break;
+                case GL_FLOAT_VEC2:
+                  bind._piece = Shader::SMP_row3x2;
+                  break;
+                case GL_FLOAT_VEC3:
+                  bind._piece = Shader::SMP_row3x3;
+                  break;
+                default:
+                  bind._piece = Shader::SMP_row3;
+                }
+                bind._func = Shader::SMF_first;
+                bind._part[0] = Shader::SMO_vec_constant_x_attrib;
+                bind._arg[0] = iname;
+                bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
+                bind._part[1] = Shader::SMO_identity;
+                bind._arg[1] = NULL;
+                bind._dep[1] = Shader::SSD_NONE;
+                s->_mat_spec.push_back(bind);
+                continue;
+              } // else fall through
+            }
             case GL_BOOL:
             case GL_BOOL:
             case GL_BOOL_VEC2:
             case GL_BOOL_VEC2:
             case GL_BOOL_VEC3:
             case GL_BOOL_VEC3:
@@ -586,11 +637,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             case GL_INT:
             case GL_INT:
             case GL_INT_VEC2:
             case GL_INT_VEC2:
             case GL_INT_VEC3:
             case GL_INT_VEC3:
-            case GL_INT_VEC4:
-            case GL_FLOAT:
-            case GL_FLOAT_VEC2:
-            case GL_FLOAT_VEC3:
-            case GL_FLOAT_VEC4: {
+            case GL_INT_VEC4: {
               Shader::ShaderPtrSpec bind;
               Shader::ShaderPtrSpec bind;
               bind._id = arg_id;
               bind._id = arg_id;
               switch (param_type) {
               switch (param_type) {

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

@@ -423,6 +423,7 @@ cp_dependency(ShaderMatInput inp) {
       (inp == SMO_satten_x) ||
       (inp == SMO_satten_x) ||
       (inp == SMO_mat_constant_x) ||
       (inp == SMO_mat_constant_x) ||
       (inp == SMO_vec_constant_x) ||
       (inp == SMO_vec_constant_x) ||
+      (inp == SMO_vec_constant_x_attrib) ||
       (inp == SMO_clipplane_x) ||
       (inp == SMO_clipplane_x) ||
       (inp == SMO_view_x_to_view) ||
       (inp == SMO_view_x_to_view) ||
       (inp == SMO_view_to_view_x) ||
       (inp == SMO_view_to_view_x) ||
@@ -434,6 +435,15 @@ cp_dependency(ShaderMatInput inp) {
       (inp == SMO_view_to_apiclip_x)) {
       (inp == SMO_view_to_apiclip_x)) {
     dep |= SSD_shaderinputs;
     dep |= SSD_shaderinputs;
   }
   }
+  if ((inp == SMO_light_ambient) ||
+      (inp == SMO_light_source_i_attrib)) {
+    dep |= SSD_light;
+  }
+  if ((inp == SMO_light_product_i_ambient) ||
+      (inp == SMO_light_product_i_diffuse) ||
+      (inp == SMO_light_product_i_specular)) {
+    dep |= (SSD_light | SSD_material);
+  }
 
 
   return dep;
   return dep;
 }
 }

+ 14 - 2
panda/src/gobj/shader.h

@@ -173,6 +173,16 @@ public:
     SMO_frame_time,
     SMO_frame_time,
     SMO_frame_delta,
     SMO_frame_delta,
 
 
+    SMO_mat_constant_x_attrib,
+    SMO_vec_constant_x_attrib,
+
+    SMO_light_ambient,
+    SMO_light_source_i_attrib,
+
+    SMO_light_product_i_ambient,
+    SMO_light_product_i_diffuse,
+    SMO_light_product_i_specular,
+
     SMO_INVALID
     SMO_INVALID
   };
   };
 
 
@@ -250,6 +260,7 @@ public:
     SSD_material      = 0x010,
     SSD_material      = 0x010,
     SSD_shaderinputs  = 0x020,
     SSD_shaderinputs  = 0x020,
     SSD_fog           = 0x040,
     SSD_fog           = 0x040,
+    SSD_light         = 0x080,
   };
   };
 
 
   enum ShaderBug {
   enum ShaderBug {
@@ -337,13 +348,14 @@ public:
   };
   };
 
 
   struct ShaderMatSpec {
   struct ShaderMatSpec {
+    LMatrix4          _cache[2];
+    LMatrix4          _value;
     ShaderArgId       _id;
     ShaderArgId       _id;
     ShaderMatFunc     _func;
     ShaderMatFunc     _func;
     ShaderMatInput    _part[2];
     ShaderMatInput    _part[2];
     PT(InternalName)  _arg[2];
     PT(InternalName)  _arg[2];
     int               _dep[2];
     int               _dep[2];
-    LMatrix4          _cache[2];
-    LMatrix4          _value;
+    int               _index;
     ShaderMatPiece    _piece;
     ShaderMatPiece    _piece;
   };
   };
 
 

+ 40 - 1
panda/src/pgraph/light.cxx

@@ -59,7 +59,7 @@ fillin(DatagramIterator &scan, BamReader *) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Light::Destructor
 //     Function: Light::Destructor
 //       Access: Published, Virtual
 //       Access: Published, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 Light::
 Light::
 ~Light() {
 ~Light() {
@@ -76,6 +76,45 @@ is_ambient_light() const {
   return false;
   return false;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Light::get_exponent
+//       Access: Public, Virtual
+//  Description: For spotlights, returns the exponent that controls
+//               the amount of light falloff from the center of the
+//               spotlight.  For other kinds of lights, returns 0.
+////////////////////////////////////////////////////////////////////
+PN_stdfloat Light::
+get_exponent() const {
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Light::get_specular_color
+//       Access: Public, Virtual
+//  Description: Returns the color of specular highlights generated
+//               by the light.  This value is meaningless for ambient
+//               lights.
+////////////////////////////////////////////////////////////////////
+const LColor &Light::
+get_specular_color() const {
+  static const LColor white(1, 1, 1, 1);
+  return white;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Light::get_attenuation
+//       Access: Public, Virtual
+//  Description: Returns the terms of the attenuation equation for the
+//               light.  These are, in order, the constant, linear,
+//               and quadratic terms based on the distance from the
+//               point to the vertex.
+////////////////////////////////////////////////////////////////////
+const LVecBase3 &Light::
+get_attenuation() const {
+  static const LVecBase3 no_atten(1, 0, 0);
+  return no_atten;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Light::get_vector_to_light
 //     Function: Light::get_vector_to_light
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 4 - 0
panda/src/pgraph/light.h

@@ -51,6 +51,10 @@ PUBLISHED:
   INLINE const LColor &get_color() const;
   INLINE const LColor &get_color() const;
   INLINE void set_color(const LColor &color);
   INLINE void set_color(const LColor &color);
 
 
+  virtual PN_stdfloat get_exponent() const;
+  virtual const LColor &get_specular_color() const;
+  virtual const LVecBase3 &get_attenuation() const;
+
   INLINE void set_priority(int priority);
   INLINE void set_priority(int priority);
   INLINE int get_priority() const;
   INLINE int get_priority() const;
   virtual int get_class_priority() const=0;
   virtual int get_class_priority() const=0;

+ 11 - 0
panda/src/pgraph/shaderAttrib.I

@@ -113,6 +113,17 @@ get_flag(int index) const {
   return (_flags & (1<<index)) ? true:false;
   return (_flags & (1<<index)) ? true:false;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderAttrib::has_shader_input
+//       Access: Published
+//  Description: Returns true if there is a ShaderInput of the given
+//               name.
+////////////////////////////////////////////////////////////////////
+bool ShaderAttrib::
+has_shader_input(CPT_InternalName id) const {
+  return (_inputs.find(id) != _inputs.end());
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ShaderAttrib::set_shader_input
 //     Function: ShaderAttrib::set_shader_input
 //       Access: Published
 //       Access: Published

+ 29 - 3
panda/src/pgraph/shaderAttrib.cxx

@@ -340,7 +340,7 @@ get_shader_input_nodepath(const InternalName *id) const {
 //  Description: Returns the ShaderInput as a vector.  Assertion
 //  Description: Returns the ShaderInput as a vector.  Assertion
 //               fails if there is none, or if it is not a vector.
 //               fails if there is none, or if it is not a vector.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-const LVecBase4 &ShaderAttrib::
+LVecBase4 ShaderAttrib::
 get_shader_input_vector(InternalName *id) const {
 get_shader_input_vector(InternalName *id) const {
   static LVecBase4 resfail(0,0,0,0);
   static LVecBase4 resfail(0,0,0,0);
   Inputs::const_iterator i = _inputs.find(id);
   Inputs::const_iterator i = _inputs.find(id);
@@ -352,9 +352,34 @@ get_shader_input_vector(InternalName *id) const {
   } else {
   } else {
     const ShaderInput *p = (*i).second;
     const ShaderInput *p = (*i).second;
 
 
-    if (p->get_value_type() == ShaderInput::M_numeric) {
+    if (p->get_value_type() == ShaderInput::M_vector) {
       return p->get_vector();
       return p->get_vector();
 
 
+    } else if (p->get_value_type() == ShaderInput::M_numeric && p->get_ptr()._size <= 4) {
+      const Shader::ShaderPtrData &ptr = p->get_ptr();
+
+      switch (ptr._type) {
+      case Shader::SPT_float:
+        {
+          LVector4f vectorf;
+          memcpy(&vectorf[0], ptr._ptr, sizeof(float) * ptr._size);
+          return LCAST(PN_stdfloat, vectorf);
+        }
+      case Shader::SPT_double:
+        {
+          LVector4d vectord;
+          memcpy(&vectord[0], ptr._ptr, sizeof(double) * ptr._size);
+          return LCAST(PN_stdfloat, vectord);
+        }
+      default:
+       {
+          ostringstream strm;
+          strm << "Shader input " << id->get_name() << " does not contain floating-point data.\n";
+          nassert_raise(strm.str());
+          return resfail;
+        }
+      }
+
     } else if (p->get_value_type() == ShaderInput::M_param) {
     } else if (p->get_value_type() == ShaderInput::M_param) {
       // Temporary solution until the new param system
       // Temporary solution until the new param system
       ParamValueBase *param = p->get_param();
       ParamValueBase *param = p->get_param();
@@ -387,7 +412,8 @@ get_shader_input_ptr(const InternalName *id) const {
     return NULL;
     return NULL;
   } else {
   } else {
     const ShaderInput *p = (*i).second;
     const ShaderInput *p = (*i).second;
-    if (p->get_value_type() != ShaderInput::M_numeric) {
+    if (p->get_value_type() != ShaderInput::M_numeric &&
+        p->get_value_type() != ShaderInput::M_vector) {
       ostringstream strm;
       ostringstream strm;
       strm << "Shader input " << id->get_name() << " is not a PTA(float/double) type.\n";
       strm << "Shader input " << id->get_name() << " is not a PTA(float/double) type.\n";
       nassert_raise(strm.str());
       nassert_raise(strm.str());

+ 2 - 1
panda/src/pgraph/shaderAttrib.h

@@ -98,13 +98,14 @@ PUBLISHED:
   CPT(RenderAttrib) clear_all_shader_inputs() const;
   CPT(RenderAttrib) clear_all_shader_inputs() const;
 
 
   INLINE bool get_flag(int flag) const;
   INLINE bool get_flag(int flag) const;
+  INLINE bool has_shader_input(CPT_InternalName id) const;
 
 
   const Shader *get_shader() const;
   const Shader *get_shader() const;
   const ShaderInput *get_shader_input(const InternalName *id) const;
   const ShaderInput *get_shader_input(const InternalName *id) const;
   const ShaderInput *get_shader_input(const string &id) const;
   const ShaderInput *get_shader_input(const string &id) const;
 
 
   const NodePath &get_shader_input_nodepath(const InternalName *id) const;
   const NodePath &get_shader_input_nodepath(const InternalName *id) const;
-  const LVecBase4 &get_shader_input_vector(InternalName *id) const;
+  LVecBase4 get_shader_input_vector(InternalName *id) const;
   Texture *get_shader_input_texture(const InternalName *id) const;
   Texture *get_shader_input_texture(const InternalName *id) const;
   const SamplerState &get_shader_input_sampler(const InternalName *id) const;
   const SamplerState &get_shader_input_sampler(const InternalName *id) const;
   const Shader::ShaderPtrData *get_shader_input_ptr(const InternalName *id) const;
   const Shader::ShaderPtrData *get_shader_input_ptr(const InternalName *id) const;

+ 3 - 3
panda/src/pgraph/shaderInput.I

@@ -212,7 +212,7 @@ ShaderInput(CPT_InternalName name, const PTA_LVecBase2f &ptr, int priority) :
 INLINE ShaderInput::
 INLINE ShaderInput::
 ShaderInput(CPT_InternalName name, const LVecBase4f &vec, int priority) :
 ShaderInput(CPT_InternalName name, const LVecBase4f &vec, int priority) :
   _name(MOVE(name)),
   _name(MOVE(name)),
-  _type(M_numeric),
+  _type(M_vector),
   _priority(priority),
   _priority(priority),
   _stored_ptr(vec),
   _stored_ptr(vec),
   _stored_vector(LCAST(PN_stdfloat, vec)),
   _stored_vector(LCAST(PN_stdfloat, vec)),
@@ -230,7 +230,7 @@ ShaderInput(CPT_InternalName name, const LVecBase4f &vec, int priority) :
 INLINE ShaderInput::
 INLINE ShaderInput::
 ShaderInput(CPT_InternalName name, const LVecBase3f &vec, int priority) :
 ShaderInput(CPT_InternalName name, const LVecBase3f &vec, int priority) :
   _name(MOVE(name)),
   _name(MOVE(name)),
-  _type(M_numeric),
+  _type(M_vector),
   _priority(priority),
   _priority(priority),
   _stored_ptr(vec),
   _stored_ptr(vec),
   _stored_vector(vec.get_x(), vec.get_y(), vec.get_z(), 0.0),
   _stored_vector(vec.get_x(), vec.get_y(), vec.get_z(), 0.0),
@@ -248,7 +248,7 @@ ShaderInput(CPT_InternalName name, const LVecBase3f &vec, int priority) :
 INLINE ShaderInput::
 INLINE ShaderInput::
 ShaderInput(CPT_InternalName name, const LVecBase2f &vec, int priority) :
 ShaderInput(CPT_InternalName name, const LVecBase2f &vec, int priority) :
   _name(MOVE(name)),
   _name(MOVE(name)),
-  _type(M_numeric),
+  _type(M_vector),
   _priority(priority),
   _priority(priority),
   _stored_ptr(vec),
   _stored_ptr(vec),
   _stored_vector(vec.get_x(), vec.get_y(), 0.0, 0.0),
   _stored_vector(vec.get_x(), vec.get_y(), 0.0, 0.0),

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

@@ -94,6 +94,7 @@ PUBLISHED:
     M_invalid = 0,
     M_invalid = 0,
     M_texture,
     M_texture,
     M_nodepath,
     M_nodepath,
+    M_vector,
     M_numeric,
     M_numeric,
     M_texture_sampler,
     M_texture_sampler,
     M_param
     M_param

+ 1 - 1
panda/src/pgraphnodes/directionalLight.I

@@ -41,7 +41,7 @@ CData(const DirectionalLight::CData &copy) :
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DirectionalLight::get_specular_color
 //     Function: DirectionalLight::get_specular_color
-//       Access: Public
+//       Access: Public, Final
 //  Description: Returns the color of specular highlights generated by
 //  Description: Returns the color of specular highlights generated by
 //               the light.
 //               the light.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 5 - 5
panda/src/pgraphnodes/directionalLight.h

@@ -37,21 +37,21 @@ public:
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
 
 
   virtual bool get_vector_to_light(LVector3 &result,
   virtual bool get_vector_to_light(LVector3 &result,
-                                   const LPoint3 &from_object_point, 
+                                   const LPoint3 &from_object_point,
                                    const LMatrix4 &to_object_space);
                                    const LMatrix4 &to_object_space);
 
 
 PUBLISHED:
 PUBLISHED:
-  INLINE const LColor &get_specular_color() const;
+  INLINE const LColor &get_specular_color() const FINAL;
   INLINE void set_specular_color(const LColor &color);
   INLINE void set_specular_color(const LColor &color);
-  
+
   INLINE const LPoint3 &get_point() const;
   INLINE const LPoint3 &get_point() const;
   INLINE void set_point(const LPoint3 &point);
   INLINE void set_point(const LPoint3 &point);
-  
+
   INLINE const LVector3 &get_direction() const;
   INLINE const LVector3 &get_direction() const;
   INLINE void set_direction(const LVector3 &direction);
   INLINE void set_direction(const LVector3 &direction);
 
 
   virtual int get_class_priority() const;
   virtual int get_class_priority() const;
-  
+
 public:
 public:
   virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,
   virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,
                     int light_id);
                     int light_id);

+ 2 - 2
panda/src/pgraphnodes/pointLight.I

@@ -41,7 +41,7 @@ CData(const PointLight::CData &copy) :
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PointLight::get_specular_color
 //     Function: PointLight::get_specular_color
-//       Access: Public
+//       Access: Public, Final
 //  Description: Returns the color of specular highlights generated by
 //  Description: Returns the color of specular highlights generated by
 //               the light.
 //               the light.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -65,7 +65,7 @@ set_specular_color(const LColor &color) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PointLight::get_attenuation
 //     Function: PointLight::get_attenuation
-//       Access: Public
+//       Access: Public, Final
 //  Description: Returns the terms of the attenuation equation for the
 //  Description: Returns the terms of the attenuation equation for the
 //               light.  These are, in order, the constant, linear,
 //               light.  These are, in order, the constant, linear,
 //               and quadratic terms based on the distance from the
 //               and quadratic terms based on the distance from the

+ 6 - 6
panda/src/pgraphnodes/pointLight.h

@@ -37,21 +37,21 @@ public:
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
 
 
   virtual bool get_vector_to_light(LVector3 &result,
   virtual bool get_vector_to_light(LVector3 &result,
-                                   const LPoint3 &from_object_point, 
+                                   const LPoint3 &from_object_point,
                                    const LMatrix4 &to_object_space);
                                    const LMatrix4 &to_object_space);
 
 
 PUBLISHED:
 PUBLISHED:
-  INLINE const LColor &get_specular_color() const;
+  INLINE const LColor &get_specular_color() const FINAL;
   INLINE void set_specular_color(const LColor &color);
   INLINE void set_specular_color(const LColor &color);
-  
-  INLINE const LVecBase3 &get_attenuation() const;
+
+  INLINE const LVecBase3 &get_attenuation() const FINAL;
   INLINE void set_attenuation(const LVecBase3 &attenuation);
   INLINE void set_attenuation(const LVecBase3 &attenuation);
-  
+
   INLINE const LPoint3 &get_point() const;
   INLINE const LPoint3 &get_point() const;
   INLINE void set_point(const LPoint3 &point);
   INLINE void set_point(const LPoint3 &point);
 
 
   virtual int get_class_priority() const;
   virtual int get_class_priority() const;
-  
+
 public:
 public:
   virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,
   virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,
                     int light_id);
                     int light_id);

+ 3 - 3
panda/src/pgraphnodes/spotlight.I

@@ -41,7 +41,7 @@ CData(const Spotlight::CData &copy) :
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Spotlight::get_exponent
 //     Function: Spotlight::get_exponent
-//       Access: Public
+//       Access: Public, Final
 //  Description: Returns the exponent that controls the amount of
 //  Description: Returns the exponent that controls the amount of
 //               light falloff from the center of the spotlight.  See
 //               light falloff from the center of the spotlight.  See
 //               set_exponent().
 //               set_exponent().
@@ -71,7 +71,7 @@ set_exponent(PN_stdfloat exponent) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Spotlight::get_specular_color
 //     Function: Spotlight::get_specular_color
-//       Access: Public
+//       Access: Public, Final
 //  Description: Returns the color of specular highlights generated by
 //  Description: Returns the color of specular highlights generated by
 //               the light.
 //               the light.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -95,7 +95,7 @@ set_specular_color(const LColor &color) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Spotlight::get_attenuation
 //     Function: Spotlight::get_attenuation
-//       Access: Public
+//       Access: Public, Final
 //  Description: Returns the terms of the attenuation equation for the
 //  Description: Returns the terms of the attenuation equation for the
 //               light.  These are, in order, the constant, linear,
 //               light.  These are, in order, the constant, linear,
 //               and quadratic terms based on the distance from the
 //               and quadratic terms based on the distance from the

+ 7 - 7
panda/src/pgraphnodes/spotlight.h

@@ -47,24 +47,24 @@ public:
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
 
 
   virtual bool get_vector_to_light(LVector3 &result,
   virtual bool get_vector_to_light(LVector3 &result,
-                                   const LPoint3 &from_object_point, 
+                                   const LPoint3 &from_object_point,
                                    const LMatrix4 &to_object_space);
                                    const LMatrix4 &to_object_space);
 
 
 PUBLISHED:
 PUBLISHED:
-  INLINE PN_stdfloat get_exponent() const;
+  INLINE PN_stdfloat get_exponent() const FINAL;
   INLINE void set_exponent(PN_stdfloat exponent);
   INLINE void set_exponent(PN_stdfloat exponent);
-  
-  INLINE const LColor &get_specular_color() const;
+
+  INLINE const LColor &get_specular_color() const FINAL;
   INLINE void set_specular_color(const LColor &color);
   INLINE void set_specular_color(const LColor &color);
-  
-  INLINE const LVecBase3 &get_attenuation() const;
+
+  INLINE const LVecBase3 &get_attenuation() const FINAL;
   INLINE void set_attenuation(const LVecBase3 &attenuation);
   INLINE void set_attenuation(const LVecBase3 &attenuation);
 
 
   virtual int get_class_priority() const;
   virtual int get_class_priority() const;
 
 
   static PT(Texture) make_spot(int pixel_width, PN_stdfloat full_radius,
   static PT(Texture) make_spot(int pixel_width, PN_stdfloat full_radius,
                                LColor &fg, LColor &bg);
                                LColor &fg, LColor &bg);
-  
+
 public:
 public:
   virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,
   virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,
                     int light_id);
                     int light_id);