Browse Source

Improve shadow system, add point light shadows, GLSL shadow inputs

rdb 10 years ago
parent
commit
25451feb87

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

@@ -445,6 +445,12 @@ ConfigVariableDouble pixel_zoom
 ("pixel-zoom", 1.0,
  PRC_DESC("The default pixel_zoom factor for new windows."));
 
+ConfigVariableInt shadow_depth_bits
+("shadow-depth-bits", 24,
+ PRC_DESC("The minimum number of depth buffer bits requested when rendering "
+          "shadow maps.  Set this to 32 for more depth resolution in shadow "
+          "maps."));
+
 ConfigVariableColor background_color
 ("background-color", "0.41 0.41 0.41 0.0",
  PRC_DESC("Specifies the rgb(a) value of the default background color for a "

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

@@ -102,6 +102,7 @@ extern EXPCL_PANDA_DISPLAY ConfigVariableInt stencil_bits;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt accum_bits;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt multisamples;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt back_buffers;
+extern EXPCL_PANDA_DISPLAY ConfigVariableInt shadow_depth_bits;
 
 extern EXPCL_PANDA_DISPLAY ConfigVariableDouble pixel_zoom;
 

+ 5 - 2
panda/src/display/graphicsEngine.cxx

@@ -1480,7 +1480,8 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
 
   // Keep track of the cameras we have already used in this thread to
   // render DisplayRegions.
-  typedef pmap<NodePath, DisplayRegion *> AlreadyCulled;
+  typedef pair<NodePath, int> CullKey;
+  typedef pmap<CullKey, DisplayRegion *> AlreadyCulled;
   AlreadyCulled already_culled;
 
   size_t wlist_size = wlist.size();
@@ -1495,7 +1496,9 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
           DisplayRegionPipelineReader *dr_reader =
             new DisplayRegionPipelineReader(dr, current_thread);
           NodePath camera = dr_reader->get_camera();
-          AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(camera, (DisplayRegion *)NULL)).first;
+          int lens_index = dr_reader->get_lens_index();
+
+          AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(CullKey(camera, lens_index), (DisplayRegion *)NULL)).first;
           if ((*aci).second == NULL) {
             // We have not used this camera already in this thread.
             // Perform the cull operation.

+ 420 - 193
panda/src/display/graphicsStateGuardian.cxx

@@ -967,9 +967,15 @@ fetch_specified_value(Shader::ShaderMatSpec &spec, int altered) {
     spec._value.set_row(3, v);
     return &spec._value;
   case Shader::SMF_transform_plight:
-    spec._value = spec._cache[0];
-    spec._value.set_row(2, spec._cache[1].xform_point(spec._cache[0].get_row3(2)));
-    return &spec._value;
+    {
+      // Careful not to touch the w component, which contains the near value.
+      spec._value = spec._cache[0];
+      LPoint3 point = spec._cache[1].xform_point(spec._cache[0].get_row3(2));
+      spec._value(2, 0) = point[0];
+      spec._value(2, 1) = point[1];
+      spec._value(2, 2) = point[2];
+      return &spec._value;
+    }
   case Shader::SMF_transform_slight:
     spec._value = spec._cache[0];
     spec._value.set_row(2, spec._cache[1].xform_point(spec._cache[0].get_row3(2)));
@@ -1152,7 +1158,9 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
       get_scene()->get_world_transform()->get_mat();
     LVecBase3 p = (t.xform_point(lt->get_point()));
     LVecBase3 a = lt->get_attenuation();
-    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,a[0],a[1],a[2],0);
+    PN_stdfloat near = lt->get_lens(0)->get_near();
+    PN_stdfloat far = lt->get_lens(0)->get_far();
+    t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],near,a[0],a[1],a[2],far);
     return &t;
   }
   case Shader::SMO_slight_x: {
@@ -1405,8 +1413,19 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
       calc_projection_mat(lens)->get_mat();
     return &t;
   }
+  case Shader::SMO_mat_constant_x_attrib: {
+    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.
+      return &_target_shader->get_shader_input_matrix(name, t);
+    }
+
+    const NodePath &np = _target_shader->get_shader_input_nodepath(name->get_parent());
+    nassertr(!np.is_empty(), &LMatrix4::ident_mat());
+
+    return fetch_specified_member(np, name->get_basename(), 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.
@@ -1421,210 +1440,378 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     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_halfVector("halfVector");
-    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) {
-      Light *light = np.node()->as_light();
-      nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
-      if (np.node()->is_of_type(AmbientLight::get_class_type())) {
-        LColor c = light->get_color();
-        c.componentwise_mult(_light_color_scale);
-        t.set_row(3, c);
-      } else {
-        // Non-ambient lights don't currently have an ambient color in Panda3D.
-        t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f));
-      }
-      return &t;
+    return fetch_specified_member(np, name->get_basename(), t);
+  }
+  case Shader::SMO_light_source_i_attrib: {
+    const LightAttrib *target_light;
+    _target_rs->get_attrib_def(target_light);
 
-    } else if (attrib == IN_diffuse) {
-      Light *light = np.node()->as_light();
-      nassertr(light != (Light *)NULL, &LMatrix4::ones_mat());
-      if (np.node()->is_of_type(AmbientLight::get_class_type())) {
-        // Ambient light has no diffuse color.
-        t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f));
-      } else {
-        LColor c = light->get_color();
-        c.componentwise_mult(_light_color_scale);
-        t.set_row(3, c);
-      }
-      return &t;
+    // We want to ignore ambient lights.  To that effect, iterate through
+    // the list of lights.  In the future, we will improve this system, by
+    // also filtering down to the number of lights specified by the shader.
+    int i = 0;
 
-    } 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;
+    int num_on_lights = target_light->get_num_on_lights();
+    for (int li = 0; li < num_on_lights; li++) {
+      NodePath light = target_light->get_on_light(li);
+      nassertr(!light.is_empty(), &LMatrix4::ident_mat());
+      Light *light_obj = light.node()->as_light();
+      nassertr(light_obj != (Light *)NULL, &LMatrix4::ident_mat());
 
-    } else if (attrib == IN_position) {
-      if (np.node()->is_of_type(AmbientLight::get_class_type())) {
-        // Ambient light has no position.
-        t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
-        return &t;
-      } else 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;
+      if (light_obj->get_type() != AmbientLight::get_class_type()) {
+        if (i++ == index) {
+          return fetch_specified_member(light, name, t);
+        }
       }
+    }
 
-    } else if (attrib == IN_halfVector) {
-      if (np.node()->is_of_type(AmbientLight::get_class_type())) {
-        // Ambient light has no half-vector.
-        t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
-        return &t;
-      } else 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();
-        dir.normalize();
-        dir += LVector3(0, 0, 1);
-        dir.normalize();
-        t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],1);
-        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;
-        pos.normalize();
-        pos += LVector3(0, 0, 1);
-        pos.normalize();
-        t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,pos[0],pos[1],pos[2],1);
-        return &t;
-      }
+    // TODO: dummy light
+    nassertr(false, &LMatrix4::ident_mat());
+  }
+  default:
+    nassertr(false /*should never get here*/, &LMatrix4::ident_mat());
+    return &LMatrix4::ident_mat();
+  }
+}
 
-    } else if (attrib == IN_spotDirection) {
-      if (np.node()->is_of_type(AmbientLight::get_class_type())) {
-        // Ambient light has no spot direction.
-        t.set_row(3, LVector3(0.0f, 0.0f, 0.0f));
-        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();
-        LVector3 dir = lens->get_view_vector() * light_mat;
-        t.set_row(3, dir);
-        return &t;
-      }
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::fetch_specified_member
+//       Access: Public
+//  Description: Given a NodePath passed into a shader input that is
+//               a structure, fetches the value for the given member.
+////////////////////////////////////////////////////////////////////
+const LMatrix4 *GraphicsStateGuardian::
+fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) {
+  // This system is not ideal.  It will be improved in the future.
+  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_halfVector("halfVector");
+  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_attenuation("attenuation");
+  static const CPT_InternalName IN_constantAttenuation("constantAttenuation");
+  static const CPT_InternalName IN_linearAttenuation("linearAttenuation");
+  static const CPT_InternalName IN_quadraticAttenuation("quadraticAttenuation");
+  static const CPT_InternalName IN_shadowMatrix("shadowMatrix");
+
+  if (attrib == IN_ambient) {
+    Light *light = np.node()->as_light();
+    nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
+    if (np.node()->is_of_type(AmbientLight::get_class_type())) {
+      LColor c = light->get_color();
+      c.componentwise_mult(_light_color_scale);
+      t.set_row(3, c);
+    } else {
+      // Non-ambient lights don't currently have an ambient color in Panda3D.
+      t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f));
+    }
+    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());
+  } else if (attrib == IN_diffuse) {
+    Light *light = np.node()->as_light();
+    nassertr(light != (Light *)NULL, &LMatrix4::ones_mat());
+    if (np.node()->is_of_type(AmbientLight::get_class_type())) {
+      // Ambient light has no diffuse color.
+      t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f));
+    } else {
+      LColor c = light->get_color();
+      c.componentwise_mult(_light_color_scale);
+      t.set_row(3, c);
+    }
+    return &t;
 
-        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_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_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());
+  } else if (attrib == IN_position) {
+    if (np.node()->is_of_type(AmbientLight::get_class_type())) {
+      // Ambient light has no position.
+      t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+      return &t;
+    } else 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;
+    }
 
-        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());
+  } else if (attrib == IN_halfVector) {
+    if (np.node()->is_of_type(AmbientLight::get_class_type())) {
+      // Ambient light has no half-vector.
+      t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+      return &t;
+    } else 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();
+      dir.normalize();
+      dir += LVector3(0, 0, 1);
+      dir.normalize();
+      t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],1);
+      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;
+      pos.normalize();
+      pos += LVector3(0, 0, 1);
+      pos.normalize();
+      t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,pos[0],pos[1],pos[2],1);
+      return &t;
+    }
 
-      t.set_row(3, LVecBase4(light->get_exponent()));
+  } else if (attrib == IN_spotDirection) {
+    if (np.node()->is_of_type(AmbientLight::get_class_type())) {
+      // Ambient light has no spot direction.
+      t.set_row(3, LVector3(0.0f, 0.0f, 0.0f));
       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();
+      LVector3 dir = lens->get_view_vector() * light_mat;
+      t.set_row(3, dir);
+      return &t;
+    }
 
-    } else if (attrib == IN_constantAttenuation) {
-      Light *light = np.node()->as_light();
-      nassertr(light != (Light *)NULL, &LMatrix4::ones_mat());
+  } 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());
 
-      t.set_row(3, LVecBase4(light->get_attenuation()[0]));
+      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_linearAttenuation) {
-      Light *light = np.node()->as_light();
-      nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
+  } 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());
 
-      t.set_row(3, LVecBase4(light->get_attenuation()[1]));
+      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());
 
-    } 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_exponent()));
+    return &t;
 
-      t.set_row(3, LVecBase4(light->get_attenuation()[2]));
-      return &t;
+  } else if (attrib == IN_attenuation) {
+    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_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 if (attrib == IN_shadowMatrix) {
+    LensNode *lnode;
+    DCAST_INTO_R(lnode, np.node(), &LMatrix4::ident_mat());
+    Lens *lens = lnode->get_lens();
+
+    static const LMatrix4 biasmat(0.5f, 0.0f, 0.0f, 0.0f,
+                                  0.0f, 0.5f, 0.0f, 0.0f,
+                                  0.0f, 0.0f, 0.5f, 0.0f,
+                                  0.5f, 0.5f, 0.5f, 1.0f);
+
+    t = get_external_transform()->get_mat() *
+      get_scene()->get_camera_transform()->get_mat() *
+      np.get_net_transform()->get_inverse()->get_mat() *
+      LMatrix4::convert_mat(_coordinate_system, lens->get_coordinate_system()) *
+      lens->get_projection_mat() * biasmat;
+    return &t;
+
+  } else {
+    display_cat.error()
+      << "Shader input requests invalid attribute " << *attrib
+      << " from node " << np << "\n";
+    return &LMatrix4::ident_mat();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::fetch_specified_texture
+//       Access: Public
+//  Description: Like fetch_specified_value, but for texture inputs.
+////////////////////////////////////////////////////////////////////
+PT(Texture) GraphicsStateGuardian::
+fetch_specified_texture(Shader::ShaderTexSpec &spec, SamplerState &sampler,
+                        int &view) {
+  switch (spec._part) {
+  case Shader::STO_named_input:
+    // Named texture input.
+    if (!_target_shader->has_shader_input(spec._name)) {
+      // Is this a member of something, like a node?
+      const InternalName *parent = spec._name->get_parent();
+      if (parent != InternalName::get_root() &&
+          _target_shader->has_shader_input(parent)) {
+
+        // Yes, grab the node.
+        const string &basename = spec._name->get_basename();
+        NodePath np = _target_shader->get_shader_input_nodepath(parent);
+
+        if (basename == "shadowMap") {
+          PT(Texture) tex = get_shadow_map(np);
+          if (tex != (Texture *)NULL) {
+            sampler = tex->get_default_sampler();
+          }
+          return tex;
+
+        } else {
+          if (spec._stage == 0) {
+            display_cat.error()
+              << "Shader input " << *parent
+              << " has no member named " << basename << ".\n";
+            spec._stage = -1;
+          }
+        }
+      } else {
+        // This used to be legal for some reason, so don't trigger the assert.
+        // Prevent flood, though, so abuse the _stage flag to indicate whether
+        // we've already errored about this.
+        if (spec._stage == 0) {
+          display_cat.error()
+            << "Shader input " << *spec._name << " is not present.\n";
+          spec._stage = -1;
+        }
+      }
     } else {
-      display_cat.error()
-        << "Shader input requests invalid attribute " << *name
-        << " from node " << np << "\n";
-      return &LMatrix4::ident_mat();
+      // Just a regular texture input.
+      return _target_shader->get_shader_input_texture(spec._name, &sampler);
     }
-  }
+    break;
+
+  case Shader::STO_stage_i:
+    {
+      // We get the TextureAttrib directly from the _target_rs, not the
+      // filtered TextureAttrib in _target_texture.
+      const TextureAttrib *texattrib;
+      _target_rs->get_attrib_def(texattrib);
+
+      if (spec._stage < texattrib->get_num_on_stages()) {
+        TextureStage *stage = texattrib->get_on_stage(spec._stage);
+        sampler = texattrib->get_on_sampler(stage);
+        view += stage->get_tex_view_offset();
+        return texattrib->get_on_texture(stage);
+      }
+    }
+    break;
+
+  case Shader::STO_light_i_shadow_map:
+    {
+      const LightAttrib *target_light;
+      _target_rs->get_attrib_def(target_light);
+
+      // We want to ignore ambient lights.  To that effect, iterate through
+      // the list of lights.  In the future, we will improve this system, by
+      // also filtering down to the number of lights specified by the shader.
+      int i = 0;
+
+      int num_on_lights = target_light->get_num_on_lights();
+      for (int li = 0; li < num_on_lights; li++) {
+        NodePath light = target_light->get_on_light(li);
+        nassertr(!light.is_empty(), NULL);
+        Light *light_obj = light.node()->as_light();
+        nassertr(light_obj != (Light *)NULL, NULL);
+
+        if (light_obj->get_type() != AmbientLight::get_class_type()) {
+          if (i++ == spec._stage) {
+            PT(Texture) tex = get_shadow_map(light);
+            if (tex != (Texture *)NULL) {
+              sampler = tex->get_default_sampler();
+            }
+            return tex;
+          }
+        }
+      }
+    }
+    break;
+
   default:
-    nassertr(false /*should never get here*/, &LMatrix4::ident_mat());
-    return &LMatrix4::ident_mat();
+    nassertr(false, NULL);
+    break;
   }
+
+  return NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2579,8 +2766,8 @@ do_issue_light() {
   int num_enabled = 0;
   int num_on_lights = 0;
 
-  const LightAttrib *target_light = (const LightAttrib *)
-    _target_rs->get_attrib_def(LightAttrib::get_class_slot());
+  const LightAttrib *target_light;
+  _target_rs->get_attrib_def(target_light);
 
   if (display_cat.is_spam()) {
     display_cat.spam()
@@ -3161,6 +3348,42 @@ async_reload_texture(TextureContext *tc) {
   _loader->load_async(request);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_shadow_map
+//       Access: Protected
+//  Description: Returns a shadow map for the given light source.
+//               If none exists, it is created, using the given host
+//               window to create the buffer, or the current window
+//               if that is set to NULL.
+////////////////////////////////////////////////////////////////////
+PT(Texture) GraphicsStateGuardian::
+get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host) {
+  nassertr(light_np.node()->is_of_type(DirectionalLight::get_class_type()) ||
+           light_np.node()->is_of_type(PointLight::get_class_type()) ||
+           light_np.node()->is_of_type(Spotlight::get_class_type()), NULL);
+
+  PT(LightLensNode) light = DCAST(LightLensNode, light_np.node());
+  if (light == NULL || !light->_shadow_caster) {
+    //TODO: return dummy shadow map (all white).
+    return NULL;
+  }
+
+  // See if we already have a buffer. If not, create one.
+  if (light->_sbuffers.count(this) == 0) {
+    if (host == (GraphicsOutputBase *)NULL) {
+      host = _current_display_region->get_window();
+    }
+    nassertr(host != NULL, NULL);
+
+    // Nope, the light doesn't have a buffer for our GSG. Make one.
+    return make_shadow_buffer(light_np, host);
+
+  } else {
+    // There's already a buffer - use that.
+    return light->_sbuffers[this]->get_texture();
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::make_shadow_buffer
 //       Access: Protected
@@ -3186,13 +3409,17 @@ make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) {
 
   nassertr(light->_sbuffers.count(this) == 0, NULL);
 
-  display_cat.debug() << "Constructing shadow buffer for light '" << light->get_name()
-    << "', size=" << light->_sb_xsize << "x" << light->_sb_ysize
-    << ", sort=" << light->_sb_sort << "\n";
+  if (display_cat.is_debug()) {
+    display_cat.debug()
+      << "Constructing shadow buffer for light '" << light->get_name()
+      << "', size=" << light->_sb_xsize << "x" << light->_sb_ysize
+      << ", sort=" << light->_sb_sort << "\n";
+  }
 
-  // Setup some flags and properties
+  // Determine the properties for creating the depth buffer.
   FrameBufferProperties fbp;
-  fbp.set_depth_bits(1); // We only need depth
+  fbp.set_depth_bits(shadow_depth_bits);
+
   WindowProperties props = WindowProperties::size(light->_sb_xsize, light->_sb_ysize);
   int flags = GraphicsPipe::BF_refuse_window;
   if (is_point) {
@@ -3228,12 +3455,12 @@ make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) {
     tex->set_border_color(LVecBase4(1, 1, 1, 1));
   }
 
-  if (get_supports_shadow_filter()) {
+  // Note: cube map shadow filtering doesn't seem to work in Cg.
+  if (get_supports_shadow_filter() && !is_point) {
     // If we have the ARB_shadow extension, enable shadow filtering.
     tex->set_minfilter(SamplerState::FT_shadow);
     tex->set_magfilter(SamplerState::FT_shadow);
   } else {
-    // We only accept linear - this tells the GPU to use hardware PCF.
     tex->set_minfilter(SamplerState::FT_linear);
     tex->set_magfilter(SamplerState::FT_linear);
   }

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

@@ -263,6 +263,9 @@ public:
   const LMatrix4 *fetch_specified_value(Shader::ShaderMatSpec &spec, int altered);
   const LMatrix4 *fetch_specified_part(Shader::ShaderMatInput input, InternalName *name,
                                        LMatrix4 &t, int index);
+  const LMatrix4 *fetch_specified_member(const NodePath &np, CPT_InternalName member, LMatrix4 &t);
+  PT(Texture) fetch_specified_texture(Shader::ShaderTexSpec &spec,
+                                      SamplerState &sampler, int &view);
   const Shader::ShaderPtrData *fetch_ptr_parameter(const Shader::ShaderPtrSpec& spec);
 
   virtual void prepare_display_region(DisplayRegionPipelineReader *dr);
@@ -348,7 +351,8 @@ public:
 
   static void create_gamma_table (PN_stdfloat gamma, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table);
 
-  virtual PT(Texture) make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host);
+  PT(Texture) get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host=NULL);
+  PT(Texture) make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host);
 
 #ifdef DO_PSTATS
   static void init_frame_pstats();

+ 7 - 17
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -1090,26 +1090,16 @@ update_shader_texture_bindings(ShaderContext *prev) {
       continue;
     }
     int texunit = cgGetParameterResourceIndex(p);
-
-    Texture *tex = NULL;
     int view = _glgsg->get_current_tex_view_offset();
     SamplerState sampler;
 
-    if (id != NULL) {
-      tex = _glgsg->_target_shader->get_shader_input_texture(id, &sampler);
-
-    } else {
-      if (spec._stage >= texattrib->get_num_on_stages()) {
-        // Apply a white texture in order to make it easier to use a shader
-        // that takes a texture on a model that doesn't have a texture applied.
-        _glgsg->_glActiveTexture(GL_TEXTURE0 + texunit);
-        _glgsg->apply_white_texture();
-        continue;
-      }
-      TextureStage *stage = texattrib->get_on_stage(spec._stage);
-      tex = texattrib->get_on_texture(stage);
-      sampler = texattrib->get_on_sampler(stage);
-      view += stage->get_tex_view_offset();
+    PT(Texture) tex = _glgsg->fetch_specified_texture(spec, sampler, view);
+    if (tex.is_null()) {
+      // Apply a white texture in order to make it easier to use a shader
+      // that takes a texture on a model that doesn't have a texture applied.
+      _glgsg->_glActiveTexture(GL_TEXTURE0 + i);
+      _glgsg->apply_white_texture();
+      continue;
     }
 
     if (spec._suffix != 0) {

+ 1 - 1
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -6841,7 +6841,7 @@ bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
   call_glLightfv(id, GL_POSITION, fpos);
   call_glLightfv(id, GL_SPOT_DIRECTION, dir);
 
-  glLightf(id, GL_SPOT_EXPONENT, light_obj->get_exponent());
+  glLightf(id, GL_SPOT_EXPONENT, max(min(light_obj->get_exponent(), (PN_stdfloat)128), (PN_stdfloat)0));
   glLightf(id, GL_SPOT_CUTOFF, lens->get_hfov() * 0.5f);
 
   const LVecBase3 &att = light_obj->get_attenuation();

+ 115 - 36
panda/src/glstuff/glShaderContext_src.cxx

@@ -25,6 +25,7 @@
 #include "fogAttrib.h"
 #include "lightAttrib.h"
 #include "clipPlaneAttrib.h"
+#include "ambientLight.h"
 
 TypeHandle CLP(ShaderContext)::_type_handle;
 
@@ -799,8 +800,29 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         for (bind._index = 0; bind._index < param_size; ++bind._index) {
           _shader->_mat_spec.push_back(bind);
         }
+        _shader->_mat_deps |= bind._dep[0];
         return;
 
+      } else if (matrix_name.size() > 15 &&
+                 matrix_name.substr(0, 12) == "LightSource[" &&
+                 sscanf(matrix_name.c_str(), "LightSource[%d].%s", &bind._index, name_buffer) == 2) {
+        // A matrix member of a p3d_LightSource struct.
+        if (strncmp(name_buffer, "shadowMatrix", 127) == 0) {
+          if (inverse) {
+            // Tack inverse back onto the end.
+            strcpy(name_buffer + strlen(name_buffer), "Inverse");
+          }
+
+          bind._func = Shader::SMF_first;
+          bind._part[0] = Shader::SMO_light_source_i_attrib;
+          bind._arg[0] = InternalName::make(name_buffer);
+          bind._part[1] = Shader::SMO_identity;
+
+        } else {
+          GLCAT.error() << "p3d_LightSource struct does not provide a matrix named " << matrix_name << "!\n";
+          return;
+        }
+
       } else {
         GLCAT.error() << "Unrecognized uniform matrix name '" << matrix_name << "'!\n";
         return;
@@ -813,6 +835,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
     if (size > 7 && noprefix.substr(0, 7) == "Texture") {
       Shader::ShaderTexSpec bind;
       bind._id = arg_id;
+      bind._part = Shader::STO_stage_i;
       bind._name = 0;
 
       string tail;
@@ -991,6 +1014,78 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       _shader->_mat_deps |= bind._dep[0];
       return;
     }
+    if (size > 15 && noprefix.substr(0, 12) == "LightSource[") {
+      int index;
+      if (sscanf(noprefix.c_str(), "LightSource[%d].%s", &index, name_buffer) == 2) {
+        // A member of a p3d_LightSource struct.
+        string member_name(name_buffer);
+        if (member_name == "shadowMap") {
+          switch (param_type) {
+#ifndef OPENGLES
+          case GL_SAMPLER_CUBE_SHADOW:
+#endif  // !OPENGLES
+          case GL_SAMPLER_2D:
+          case GL_SAMPLER_2D_SHADOW:
+          case GL_SAMPLER_CUBE:
+            {
+              Shader::ShaderTexSpec bind;
+              bind._id = arg_id;
+              bind._part = Shader::STO_light_i_shadow_map;
+              bind._name = 0;
+              bind._desired_type = Texture::TT_2d_texture;
+              bind._stage = index;
+              if (get_sampler_texture_type(bind._desired_type, param_type)) {
+                _glgsg->_glUniform1i(p, _shader->_tex_spec.size());
+                _shader->_tex_spec.push_back(bind);
+              }
+              return;
+            }
+          default:
+            GLCAT.error()
+              << "Invalid type for p3d_LightSource[].shadowMap input!\n";
+            return;
+          }
+        } else {
+          // A non-sampler attribute of a numbered light source.
+          Shader::ShaderMatSpec bind;
+          bind._id = arg_id;
+          bind._func = Shader::SMF_first;
+          bind._index = index;
+          bind._part[0] = Shader::SMO_light_source_i_attrib;
+          bind._arg[0] = InternalName::make(member_name);
+          bind._dep[0] = Shader::SSD_general | Shader::SSD_light | Shader::SSD_frame | Shader::SSD_transform;
+          bind._part[1] = Shader::SMO_identity;
+          bind._arg[1] = NULL;
+          bind._dep[1] = Shader::SSD_NONE;
+
+          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;
+
+          case GL_FLOAT_VEC4:
+            bind._piece = Shader::SMP_row3;
+            break;
+
+          default:
+            GLCAT.error()
+              << "p3d_LightSource[]." << member_name << " should be float or vec\n";
+            return;
+          }
+          _shader->_mat_spec.push_back(bind);
+          _shader->_mat_deps |= bind._dep[0] | bind._dep[1];
+          return;
+        }
+      }
+    }
     if (noprefix == "TransformTable") {
       if (param_type != GL_FLOAT_MAT4) {
         GLCAT.error()
@@ -1119,6 +1214,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       case GL_SAMPLER_CUBE: {
         Shader::ShaderTexSpec bind;
         bind._id = arg_id;
+        bind._part = Shader::STO_named_input;
         bind._name = InternalName::make(param_name);
         bind._desired_type = Texture::TT_2d_texture;
         bind._stage = 0;
@@ -1159,9 +1255,19 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         bind._id = arg_id;
         bind._piece = Shader::SMP_whole;
         bind._func = Shader::SMF_first;
-        bind._part[0] = Shader::SMO_mat_constant_x;
-        bind._arg[0] = InternalName::make(param_name);
-        bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
+        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.
+          bind._part[0] = Shader::SMO_mat_constant_x_attrib;
+          bind._arg[0] = InternalName::make(param_name);
+          bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_transform;
+        } else {
+          bind._part[0] = Shader::SMO_mat_constant_x;
+          bind._arg[0] = InternalName::make(param_name);
+          bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
+        }
         bind._part[1] = Shader::SMO_identity;
         bind._arg[1] = NULL;
         bind._dep[1] = Shader::SSD_NONE;
@@ -2260,46 +2366,19 @@ update_shader_texture_bindings(ShaderContext *prev) {
   }
 #endif
 
-  // We get the TextureAttrib directly from the _target_rs, not the
-  // filtered TextureAttrib in _target_texture.
-  const TextureAttrib *texattrib;
-  _glgsg->_target_rs->get_attrib_def(texattrib);
-  //const TextureAttrib *texattrib;
-  //_state_rs->get_attrib_def(TextureAttrib::get_class_slot());
-
   for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
     Shader::ShaderTexSpec &spec = _shader->_tex_spec[i];
     const InternalName *id = spec._name;
 
-    Texture *tex = NULL;
     int view = _glgsg->get_current_tex_view_offset();
     SamplerState sampler;
 
-    if (id != NULL) {
-      // Named texture input.
-      if (!_glgsg->_target_shader->has_shader_input(id)) {
-        // This used to be legal for some reason, so don't trigger the assert.
-        GLCAT.error()
-          << "Shader input " << *id << " is not present.\n";
-        continue;
-      }
-      tex = _glgsg->_target_shader->get_shader_input_texture(id, &sampler);
-
-    } else {
-      if (spec._stage >= texattrib->get_num_on_stages()) {
-        // Apply a white texture in order to make it easier to use a shader
-        // that takes a texture on a model that doesn't have a texture applied.
-        _glgsg->_glActiveTexture(GL_TEXTURE0 + i);
-        _glgsg->apply_white_texture();
-        continue;
-      }
-      TextureStage *stage = texattrib->get_on_stage(spec._stage);
-      tex = texattrib->get_on_texture(stage);
-      sampler = texattrib->get_on_sampler(stage);
-      view += stage->get_tex_view_offset();
-    }
-
-    if (tex == NULL) {
+    PT(Texture) tex = _glgsg->fetch_specified_texture(spec, sampler, view);
+    if (tex.is_null()) {
+      // Apply a white texture in order to make it easier to use a shader
+      // that takes a texture on a model that doesn't have a texture applied.
+      _glgsg->_glActiveTexture(GL_TEXTURE0 + i);
+      _glgsg->apply_white_texture();
       continue;
     }
 

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

@@ -478,6 +478,9 @@ cp_dependency(ShaderMatInput inp) {
   if ((inp == SMO_light_ambient) ||
       (inp == SMO_light_source_i_attrib)) {
     dep |= SSD_light;
+    if (inp == SMO_light_source_i_attrib) {
+      dep |= SSD_transform;
+    }
   }
   if ((inp == SMO_light_product_i_ambient) ||
       (inp == SMO_light_product_i_diffuse) ||
@@ -976,6 +979,17 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
       bind._arg[0] = NULL;
       bind._part[1] = SMO_identity;
       bind._arg[1] = NULL;
+    } else if (pieces[1] == "ambient") {
+      if (!cp_errchk_parameter_float(p,3,4)) {
+        return false;
+      }
+      bind._id = p._id;
+      bind._piece = SMP_row3;
+      bind._func = SMF_first;
+      bind._part[0] = SMO_light_ambient;
+      bind._arg[0] = NULL;
+      bind._part[1] = SMO_identity;
+      bind._arg[1] = NULL;
     } else {
       cp_report_error(p,"Unknown attr parameter.");
       return false;
@@ -1218,6 +1232,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._id = p._id;
     bind._name = 0;
     bind._stage = atoi(pieces[1].c_str());
+    bind._part = STO_stage_i;
     switch (p._type) {
     case SAT_sampler1d:      bind._desired_type = Texture::TT_1d_texture; break;
     case SAT_sampler2d:      bind._desired_type = Texture::TT_2d_texture; break;
@@ -1239,6 +1254,31 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     return true;
   }
 
+  if (pieces[0] == "shadow") {
+    if ((!cp_errchk_parameter_in(p)) ||
+        (!cp_errchk_parameter_uniform(p)) ||
+        (!cp_errchk_parameter_sampler(p)))
+      return false;
+    if (pieces.size() != 2) {
+      cp_report_error(p, "Invalid parameter name");
+      return false;
+    }
+    ShaderTexSpec bind;
+    bind._id = p._id;
+    bind._name = InternalName::make(pieces[1])->append("shadowMap");
+    bind._stage = -1;
+    bind._part = STO_named_input;
+    switch (p._type) {
+    case SAT_sampler2d:      bind._desired_type = Texture::TT_2d_texture; break;
+    case SAT_sampler_cube:   bind._desired_type = Texture::TT_cube_map; break;
+    default:
+      cp_report_error(p, "Invalid type for a shadow-parameter");
+      return false;
+    }
+    _tex_spec.push_back(bind);
+    return true;
+  }
+
   // Keywords to fetch texture parameter data.
 
   if (pieces[0] == "texpad") {
@@ -1347,6 +1387,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
       ShaderTexSpec bind;
       bind._id = p._id;
       bind._name = kinputname;
+      bind._part = STO_named_input;
       bind._desired_type = Texture::TT_1d_texture;
       _tex_spec.push_back(bind);
       return true;
@@ -1355,6 +1396,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
       ShaderTexSpec bind;
       bind._id = p._id;
       bind._name = kinputname;
+      bind._part = STO_named_input;
       bind._desired_type = Texture::TT_2d_texture;
       _tex_spec.push_back(bind);
       return true;
@@ -1363,6 +1405,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
       ShaderTexSpec bind;
       bind._id = p._id;
       bind._name = kinputname;
+      bind._part = STO_named_input;
       bind._desired_type = Texture::TT_3d_texture;
       _tex_spec.push_back(bind);
       return true;
@@ -1371,6 +1414,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
       ShaderTexSpec bind;
       bind._id = p._id;
       bind._name = kinputname;
+      bind._part = STO_named_input;
       bind._desired_type = Texture::TT_2d_texture_array;
       _tex_spec.push_back(bind);
       return true;
@@ -1379,6 +1423,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
       ShaderTexSpec bind;
       bind._id = p._id;
       bind._name = kinputname;
+      bind._part = STO_named_input;
       bind._desired_type = Texture::TT_cube_map;
       _tex_spec.push_back(bind);
       return true;
@@ -1387,6 +1432,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
       ShaderTexSpec bind;
       bind._id = p._id;
       bind._name = kinputname;
+      bind._part = STO_named_input;
       bind._desired_type = Texture::TT_buffer_texture;
       _tex_spec.push_back(bind);
       return true;
@@ -1395,6 +1441,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
       ShaderTexSpec bind;
       bind._id = p._id;
       bind._name = kinputname;
+      bind._part = STO_named_input;
       bind._desired_type = Texture::TT_cube_map_array;
       _tex_spec.push_back(bind);
       return true;

+ 11 - 0
panda/src/gobj/shader.h

@@ -197,6 +197,16 @@ public:
     SMO_INVALID
   };
 
+  enum ShaderTexInput {
+    STO_INVALID,
+
+    STO_named_input,
+    STO_named_stage,
+
+    STO_stage_i,
+    STO_light_i_shadow_map,
+  };
+
   enum ShaderArgClass {
     SAC_scalar,
     SAC_vector,
@@ -380,6 +390,7 @@ public:
   struct ShaderTexSpec {
     ShaderArgId       _id;
     PT(InternalName)  _name;
+    ShaderTexInput    _part;
     int               _stage;
     int               _desired_type;
     PT(InternalName)  _suffix;

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

@@ -227,10 +227,6 @@ public:
   virtual void bind_light(Spotlight *light_obj, const NodePath &light,
                           int light_id) { }
 
-  // This function creates a shadow mapping buffer. This is not put in ShaderGenerator
-  // because that would cause circular dependencies.
-  virtual PT(Texture) make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host)=0;
-
 PUBLISHED:
   static GraphicsStateGuardianBase *get_default_gsg();
   static void set_default_gsg(GraphicsStateGuardianBase *default_gsg);

+ 7 - 0
panda/src/pgraphnodes/lightLensNode.cxx

@@ -81,6 +81,13 @@ void LightLensNode::
 clear_shadow_buffers() {
   ShadowBuffers::iterator it;
   for(it = _sbuffers.begin(); it != _sbuffers.end(); ++it) {
+    PT(Texture) tex = (*it).second->get_texture();
+    if (tex) {
+      // Clear it to all ones, so that any shaders that might still
+      // be using it will see the shadows being disabled.
+      tex->set_clear_color(LColor(1));
+      tex->clear_image();
+    }
     (*it).first->remove_window((*it).second);
   }
   _sbuffers.clear();

+ 152 - 240
panda/src/pgraphnodes/shaderGenerator.cxx

@@ -204,21 +204,25 @@ analyze_renderstate(const RenderState *rs) {
 
   //  verify_enforce_attrib_lock();
   _state = rs;
-  const AuxBitplaneAttrib *aux_bitplane = DCAST(AuxBitplaneAttrib, rs->get_attrib_def(AuxBitplaneAttrib::get_class_slot()));
+  const AuxBitplaneAttrib *aux_bitplane;
+  rs->get_attrib_def(aux_bitplane);
   int outputs = aux_bitplane->get_outputs();
 
   // Decide whether or not we need alpha testing or alpha blending.
 
-  const AlphaTestAttrib *alpha_test = DCAST(AlphaTestAttrib, rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
+  const AlphaTestAttrib *alpha_test;
+  rs->get_attrib_def(alpha_test);
   if ((alpha_test->get_mode() != RenderAttrib::M_none)&&
       (alpha_test->get_mode() != RenderAttrib::M_always)) {
     _have_alpha_test = true;
   }
-  const ColorBlendAttrib *color_blend = DCAST(ColorBlendAttrib, rs->get_attrib_def(ColorBlendAttrib::get_class_slot()));
+  const ColorBlendAttrib *color_blend;
+  rs->get_attrib_def(color_blend);
   if (color_blend->get_mode() != ColorBlendAttrib::M_none) {
     _have_alpha_blend = true;
   }
-  const TransparencyAttrib *transparency = DCAST(TransparencyAttrib, rs->get_attrib_def(TransparencyAttrib::get_class_slot()));
+  const TransparencyAttrib *transparency;
+  rs->get_attrib_def(transparency);
   if ((transparency->get_mode() == TransparencyAttrib::M_alpha)||
       (transparency->get_mode() == TransparencyAttrib::M_dual)) {
     _have_alpha_blend = true;
@@ -257,57 +261,71 @@ analyze_renderstate(const RenderState *rs) {
 
   // Count number of textures.
 
-  const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot()));
+  const TextureAttrib *texture;
+  rs->get_attrib_def(texture);
   _num_textures = texture->get_num_on_stages();
 
   // Determine whether or not vertex colors or flat colors are present.
 
-  const ColorAttrib *color = DCAST(ColorAttrib, rs->get_attrib_def(ColorAttrib::get_class_slot()));
+  const ColorAttrib *color;
+  rs->get_attrib_def(color);
   if (color->get_color_type() == ColorAttrib::T_vertex) {
     _vertex_colors = true;
   } else if (color->get_color_type() == ColorAttrib::T_flat) {
     _flat_colors = true;
   }
 
+  // Find the material.
+
+  const MaterialAttrib *material;
+  rs->get_attrib_def(material);
+
+  if (!material->is_off()) {
+    _material = material->get_material();
+  } else {
+    _material = Material::get_default();
+  }
+
   // Break out the lights by type.
 
   _shadows = false;
-  const LightAttrib *la = DCAST(LightAttrib, rs->get_attrib_def(LightAttrib::get_class_slot()));
-  for (int i=0; i<la->get_num_on_lights(); i++) {
+  const LightAttrib *la;
+  rs->get_attrib_def(la);
+
+  for (int i = 0; i < la->get_num_on_lights(); ++i) {
     NodePath light = la->get_on_light(i);
     nassertv(!light.is_empty());
     PandaNode *light_obj = light.node();
     nassertv(light_obj != (PandaNode *)NULL);
 
     if (light_obj->get_type() == AmbientLight::get_class_type()) {
-      _alights_np.push_back(light);
-      _alights.push_back((AmbientLight*)light_obj);
-    }
-    else if (light_obj->get_type() == DirectionalLight::get_class_type()) {
-      _dlights_np.push_back(light);
-      _dlights.push_back((DirectionalLight*)light_obj);
-      if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) {
-        _shadows = true;
+      if (_material->has_ambient()) {
+        LColor a = _material->get_ambient();
+        if ((a[0]!=0.0)||(a[1]!=0.0)||(a[2]!=0.0)) {
+          _have_ambient = true;
+        }
+      } else {
+        _have_ambient = true;
       }
-    }
-    else if (light_obj->get_type() == PointLight::get_class_type()) {
-      _plights_np.push_back(light);
-      _plights.push_back((PointLight*)light_obj);
-    }
-    else if (light_obj->get_type() == Spotlight::get_class_type()) {
-      _slights_np.push_back(light);
-      _slights.push_back((Spotlight*)light_obj);
+      _lighting = true;
+
+    } else if (light_obj->is_of_type(LightLensNode::get_class_type())) {
+      _lights_np.push_back(light);
+      _lights.push_back((LightLensNode *)light_obj);
       if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) {
         _shadows = true;
       }
+      _lighting = true;
+      _need_eye_normal = true;
     }
   }
 
   // See if there is a normal map, height map, gloss map, or glow map.
   // Also check if anything has TexGen.
 
-  const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, rs->get_attrib_def(TexGenAttrib::get_class_slot()));
-  for (int i=0; i<_num_textures; i++) {
+  const TexGenAttrib *tex_gen;
+  rs->get_attrib_def(tex_gen);
+  for (int i = 0; i < _num_textures; ++i) {
     TextureStage *stage = texture->get_on_stage(i);
     TextureStage::Mode mode = stage->get_mode();
     if ((mode == TextureStage::M_normal)||
@@ -352,43 +370,15 @@ analyze_renderstate(const RenderState *rs) {
     }
   }
 
-  // Determine whether lighting is needed.
-
-  if (la->get_num_on_lights() > 0) {
-    _lighting = true;
-    _need_eye_normal = true;
-  }
-
   // Determine whether we should normalize the normals.
   const RescaleNormalAttrib *rescale;
   rs->get_attrib_def(rescale);
 
   _normalize_normals = (rescale->get_mode() != RescaleNormalAttrib::M_none);
 
-  // Find the material.
-
-  const MaterialAttrib *material = DCAST(MaterialAttrib, rs->get_attrib_def(MaterialAttrib::get_class_slot()));
-
-  if (!material->is_off()) {
-    _material = material->get_material();
-  } else {
-    _material = Material::get_default();
-  }
-
   // Decide which material modes need to be calculated.
 
-  if (_lighting && (_alights.size() > 0)) {
-    if (_material->has_ambient()) {
-      LColor a = _material->get_ambient();
-      if ((a[0]!=0.0)||(a[1]!=0.0)||(a[2]!=0.0)) {
-        _have_ambient = true;
-      }
-    } else {
-      _have_ambient = true;
-    }
-  }
-
-  if (_lighting && (_dlights.size() + _plights.size() + _slights.size())) {
+  if (_lighting) {
     if (_material->has_diffuse()) {
       LColor d = _material->get_diffuse();
       if ((d[0]!=0.0)||(d[1]!=0.0)||(d[2]!=0.0)) {
@@ -406,7 +396,7 @@ analyze_renderstate(const RenderState *rs) {
     }
   }
 
-  if (_lighting && (_dlights.size() + _plights.size() + _slights.size())) {
+  if (_lighting) {
     if (_material->has_specular()) {
       LColor s = _material->get_specular();
       if ((s[0]!=0.0)||(s[1]!=0.0)||(s[2]!=0.0)) {
@@ -416,12 +406,7 @@ analyze_renderstate(const RenderState *rs) {
       _have_specular = true;
     }
 
-    if (_plights.size() + _slights.size() > 0) {
-      _need_eye_position = true;
-
-    } else if (_have_specular && _material->get_local()) {
-      _need_eye_position = true;
-    }
+    _need_eye_position = true;
   }
 
   // Decide whether to separate ambient and diffuse calculations.
@@ -442,8 +427,8 @@ analyze_renderstate(const RenderState *rs) {
     }
   }
 
-  const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
-  if (_lighting &&
+  const LightRampAttrib *light_ramp;
+  if (_lighting && rs->get_attrib(light_ramp) &&
       (light_ramp->get_mode() != LightRampAttrib::LRT_identity)) {
     _separate_ambient_diffuse = true;
   }
@@ -463,13 +448,15 @@ analyze_renderstate(const RenderState *rs) {
 
   // Check for clip planes.
 
-  const ClipPlaneAttrib *clip_plane = DCAST(ClipPlaneAttrib, rs->get_attrib_def(ClipPlaneAttrib::get_class_slot()));
+  const ClipPlaneAttrib *clip_plane;
+  rs->get_attrib_def(clip_plane);
   _num_clip_planes = clip_plane->get_num_on_planes();
   if (_num_clip_planes > 0) {
     _need_world_position = true;
   }
 
-  const ShaderAttrib *shader_attrib = DCAST(ShaderAttrib, rs->get_attrib_def(ShaderAttrib::get_class_slot()));
+  const ShaderAttrib *shader_attrib;
+  rs->get_attrib_def(shader_attrib);
   if (shader_attrib->auto_shader()) {
     _auto_normal_on = shader_attrib->auto_normal_on();
     _auto_glow_on   = shader_attrib->auto_glow_on();
@@ -479,8 +466,8 @@ analyze_renderstate(const RenderState *rs) {
   }
 
   // Check for fog.
-  const FogAttrib *fog = DCAST(FogAttrib, rs->get_attrib_def(FogAttrib::get_class_slot()));
-  if (!fog->is_off()) {
+  const FogAttrib *fog;
+  if (rs->get_attrib(fog) && !fog->is_off()) {
     _fog = true;
   }
 }
@@ -533,14 +520,8 @@ clear_analysis() {
   _auto_ramp_on   = false;
   _auto_shadow_on = false;
 
-  _alights.clear();
-  _dlights.clear();
-  _plights.clear();
-  _slights.clear();
-  _alights_np.clear();
-  _dlights_np.clear();
-  _plights_np.clear();
-  _slights_np.clear();
+  _lights.clear();
+  _lights_np.clear();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -553,73 +534,12 @@ clear_analysis() {
 CPT(RenderAttrib) ShaderGenerator::
 create_shader_attrib(const string &txt) {
   PT(Shader) shader = Shader::make(txt, Shader::SL_Cg);
-  CPT(RenderAttrib) shattr = ShaderAttrib::make();
-  shattr = DCAST(ShaderAttrib, shattr)->set_shader(shader);
-  if (_lighting) {
-    for (int i=0; i < (int)_alights.size(); i++) {
-      shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("alight", i), _alights_np[i]);
-    }
-    for (int i=0; i < (int)_dlights.size(); i++) {
-      shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("dlight", i), _dlights_np[i]);
-      if (_shadows && _dlights[i]->_shadow_caster) {
-        PT(Texture) tex = update_shadow_buffer(_dlights_np[i]);
-        if (tex == NULL) {
-          pgraphnodes_cat.error() << "Failed to create shadow buffer for DirectionalLight '" << _dlights[i]->get_name() << "'!\n";
-        }
-        shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("dlighttex", i), tex);
-      } else {
-        _dlights[i]->clear_shadow_buffers();
-      }
-    }
-    for (int i=0; i < (int)_plights.size(); i++) {
-      shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("plight", i), _plights_np[i]);
-    }
-    for (int i=0; i < (int)_slights.size(); i++) {
-      shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("slight", i), _slights_np[i]);
-      if (_shadows && _slights[i]->_shadow_caster) {
-        PT(Texture) tex = update_shadow_buffer(_slights_np[i]);
-        if (tex == NULL) {
-          pgraphnodes_cat.error() << "Failed to create shadow buffer for Spotlight '" << _slights[i]->get_name() << "'!\n";
-        }
-        shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("slighttex", i), tex);
-      } else {
-        _slights[i]->clear_shadow_buffers();
-      }
-    }
-  }
-  return shattr;
-}
+  CPT(RenderAttrib) shattr = ShaderAttrib::make(shader);
 
-////////////////////////////////////////////////////////////////////
-//     Function: ShaderGenerator::update_shadow_buffer
-//       Access: Protected, Virtual
-//  Description: Updates the depth buffer of the specified light,
-//               if it is configured to cast shadows.
-//               Only call this function for DirectionalLights
-//               and Spotlights. Returns the depth texture.
-////////////////////////////////////////////////////////////////////
-PT(Texture) ShaderGenerator::
-update_shadow_buffer(NodePath light_np) {
-  // Make sure everything is valid.
-  nassertr(light_np.node()->is_of_type(DirectionalLight::get_class_type()) ||
-           light_np.node()->is_of_type(Spotlight::get_class_type()), NULL);
-  PT(LightLensNode) light = DCAST(LightLensNode, light_np.node());
-  if (light == NULL || !light->_shadow_caster) {
-    return NULL;
-  }
-
-  // See if we already have a buffer. If not, create one.
-  Texture *tex;
-  if (light->_sbuffers.count(_gsg) == 0) {
-    // Nope, the light doesn't have a buffer for our GSG. Make one.
-    tex = _gsg->make_shadow_buffer(light_np, _host);
-  } else {
-    // There's already a buffer - use that.
-    tex = light->_sbuffers[_gsg]->get_texture();
+  for (size_t i = 0; i < _lights.size(); ++i) {
+    shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("light", i), _lights_np[i]);
   }
-  nassertr(tex != NULL, NULL);
-
-  return tex;
+  return shattr;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -674,8 +594,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   string tangent_input;
   string binormal_input;
   pmap<const InternalName *, const char *> texcoord_fregs;
-  pvector<const char *> dlightcoord_fregs;
-  pvector<const char *> slightcoord_fregs;
+  pvector<const char *> lightcoord_fregs;
   const char *world_position_freg = 0;
   const char *world_normal_freg = 0;
   const char *eye_position_freg = 0;
@@ -790,25 +709,18 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
     text << "\t uniform float4 mspos_view,\n";
     text << "\t out float3 l_eyevec,\n";
   }
-  if (_lighting) {
-    if (_shadows && _auto_shadow_on) {
-      for (int i=0; i < (int)_dlights.size(); i++) {
-        if (_dlights[i]->_shadow_caster) {
-          dlightcoord_fregs.push_back(alloc_freg());
-          text << "\t uniform float4x4 trans_model_to_clip_of_dlight" << i << ",\n";
-          text << "\t out float4 l_dlightcoord" << i << " : " << dlightcoord_fregs[i] << ",\n";
-        } else {
-          dlightcoord_fregs.push_back(NULL);
-        }
-      }
-      for (int i=0; i < (int)_slights.size(); i++) {
-        if (_slights[i]->_shadow_caster) {
-          slightcoord_fregs.push_back(alloc_freg());
-          text << "\t uniform float4x4 trans_model_to_clip_of_slight" << i << ",\n";
-          text << "\t out float4 l_slightcoord" << i << " : " << slightcoord_fregs[i] << ",\n";
+  if (_lighting && _shadows && _auto_shadow_on) {
+    for (size_t i = 0; i < _lights.size(); ++i) {
+      if (_lights[i]->_shadow_caster) {
+        lightcoord_fregs.push_back(alloc_freg());
+        if (_lights[i]->is_of_type(PointLight::get_class_type())) {
+          text << "\t uniform float4x4 trans_model_to_light" << i << ",\n";
         } else {
-          slightcoord_fregs.push_back(NULL);
+          text << "\t uniform float4x4 trans_model_to_clip_of_light" << i << ",\n";
         }
+        text << "\t out float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n";
+      } else {
+        lightcoord_fregs.push_back(NULL);
       }
     }
   }
@@ -904,14 +816,13 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   }
   if (_shadows && _auto_shadow_on) {
     text << "\t float4x4 biasmat = {0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f};\n";
-    for (int i=0; i < (int)_dlights.size(); i++) {
-      if (_dlights[i]->_shadow_caster) {
-        text << "\t l_dlightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_dlight" << i << ", vtx_position));\n";
-      }
-    }
-    for (int i=0; i < (int)_slights.size(); i++) {
-      if (_slights[i]->_shadow_caster) {
-        text << "\t l_slightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_slight" << i << ", vtx_position));\n";
+    for (size_t i = 0; i < _lights.size(); ++i) {
+      if (_lights[i]->_shadow_caster) {
+        if (_lights[i]->is_of_type(PointLight::get_class_type())) {
+          text << "\t l_lightcoord" << i << " = mul(trans_model_to_light" << i << ", vtx_position);\n";
+        } else {
+          text << "\t l_lightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_light" << i << ", vtx_position));\n";
+        }
       }
     }
   }
@@ -962,33 +873,27 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
     text << "\t in float3 l_binormal : " << binormal_freg << ",\n";
   }
   if (_lighting) {
-    for (int i=0; i < (int)_alights.size(); i++) {
-      text << "\t uniform float4 alight_alight" << i << ",\n";
-    }
-    for (int i=0; i < (int)_dlights.size(); i++) {
-      text << "\t uniform float4x4 dlight_dlight" << i << "_rel_view,\n";
-      if (_shadows && _dlights[i]->_shadow_caster && _auto_shadow_on) {
-        if (_use_shadow_filter) {
-          text << "\t uniform sampler2DShadow k_dlighttex" << i << ",\n";
-        } else {
-          text << "\t uniform sampler2D k_dlighttex" << i << ",\n";
-        }
-        text << "\t in float4 l_dlightcoord" << i << " : " << dlightcoord_fregs[i] << ",\n";
+    for (size_t i = 0; i < _lights.size(); ++i) {
+      if (_lights[i]->is_of_type(DirectionalLight::get_class_type())) {
+        text << "\t uniform float4x4 dlight_light" << i << "_rel_view,\n";
+
+      } else if (_lights[i]->is_of_type(PointLight::get_class_type())) {
+        text << "\t uniform float4x4 plight_light" << i << "_rel_view,\n";
+
+      } else if (_lights[i]->is_of_type(Spotlight::get_class_type())) {
+        text << "\t uniform float4x4 slight_light" << i << "_rel_view,\n";
+        text << "\t uniform float4   satten_light" << i << ",\n";
       }
-    }
-    for (int i=0; i < (int)_plights.size(); i++) {
-      text << "\t uniform float4x4 plight_plight" << i << "_rel_view,\n";
-    }
-    for (int i=0; i < (int)_slights.size(); i++) {
-      text << "\t uniform float4x4 slight_slight" << i << "_rel_view,\n";
-      text << "\t uniform float4   satten_slight" << i << ",\n";
-      if (_shadows && _slights[i]->_shadow_caster && _auto_shadow_on) {
-        if (_use_shadow_filter) {
-          text << "\t uniform sampler2DShadow k_slighttex" << i << ",\n";
+
+      if (_shadows && _lights[i]->_shadow_caster && _auto_shadow_on) {
+        if (_lights[i]->is_of_type(PointLight::get_class_type())) {
+          text << "\t uniform samplerCUBE shadow_light" << i << ",\n";
+        } else if (_use_shadow_filter) {
+          text << "\t uniform sampler2DShadow shadow_light" << i << ",\n";
         } else {
-          text << "\t uniform sampler2D k_slighttex" << i << ",\n";
+          text << "\t uniform sampler2D shadow_light" << i << ",\n";
         }
-        text << "\t in float4 l_slightcoord" << i << " : " << slightcoord_fregs[i] << ",\n";
+        text << "\t in float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n";
       }
     }
     if (_need_material_props) {
@@ -1017,6 +922,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   for (int i=0; i<_num_clip_planes; ++i) {
     text << "\t uniform float4 clipplane_" << i << ",\n";
   }
+  text << "\t uniform float4 attr_ambient,\n";
   text << "\t uniform float4 attr_colorscale\n";
   text << ") {\n";
   // Clipping first!
@@ -1149,7 +1055,8 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   if (_lighting) {
     text << "\t // Begin view-space light calculations\n";
     text << "\t float ldist,lattenv,langle;\n";
-    text << "\t float4 lcolor,lspec,lvec,lpoint,latten,ldir,leye,lhalf;\n";
+    text << "\t float4 lcolor,lspec,lpoint,latten,ldir,leye;\n";
+    text << "\t float3 lvec,lhalf;\n";
     if (_shadows && _auto_shadow_on) {
       text << "\t float lshad;\n";
     }
@@ -1173,26 +1080,24 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
         text << "\t float shininess = 50; // no shininess specified, using default\n";
       }
     }
-    for (int i=0; i < (int)_alights.size(); i++) {
-      text << "\t // Ambient Light " << i << "\n";
-      text << "\t lcolor = alight_alight" << i << ";\n";
-      if (_separate_ambient_diffuse && _have_ambient) {
-        text << "\t tot_ambient += lcolor;\n";
-      } else if(_have_diffuse) {
-        text << "\t tot_diffuse += lcolor;\n";
-      }
+    if (_separate_ambient_diffuse && _have_ambient) {
+      text << "\t tot_ambient += attr_ambient;\n";
+    } else if(_have_diffuse) {
+      text << "\t tot_diffuse += attr_ambient;\n";
     }
-    for (int i=0; i < (int)_dlights.size(); i++) {
+  }
+  for (size_t i = 0; i < _lights.size(); ++i) {
+    if (_lights[i]->is_of_type(DirectionalLight::get_class_type())) {
       text << "\t // Directional Light " << i << "\n";
-      text << "\t lcolor = dlight_dlight" << i << "_rel_view[0];\n";
-      text << "\t lspec  = dlight_dlight" << i << "_rel_view[1];\n";
-      text << "\t lvec   = dlight_dlight" << i << "_rel_view[2];\n";
+      text << "\t lcolor = dlight_light" << i << "_rel_view[0];\n";
+      text << "\t lspec  = dlight_light" << i << "_rel_view[1];\n";
+      text << "\t lvec   = dlight_light" << i << "_rel_view[2].xyz;\n";
       text << "\t lcolor *= saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
-      if (_shadows && _dlights[i]->_shadow_caster && _auto_shadow_on) {
+      if (_shadows && _lights[i]->_shadow_caster && _auto_shadow_on) {
         if (_use_shadow_filter) {
-          text << "\t lshad = shadow2DProj(k_dlighttex" << i << ", l_dlightcoord" << i << ").r;\n";
+          text << "\t lshad = shadow2DProj(shadow_light" << i << ", l_lightcoord" << i << ").r;\n";
         } else {
-          text << "\t lshad = tex2Dproj(k_dlighttex" << i << ", l_dlightcoord" << i << ").r > l_dlightcoord" << i << ".z / l_dlightcoord" << i << ".w;\n";
+          text << "\t lshad = tex2Dproj(shadow_light" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n";
         }
         text << "\t lcolor *= lshad;\n";
         text << "\t lspec *= lshad;\n";
@@ -1202,59 +1107,64 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
       }
       if (_have_specular) {
         if (_material->get_local()) {
-          text << "\t lhalf  = normalize(lvec - normalize(l_eye_position));\n";
+          text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
         } else {
-          text << "\t lhalf = dlight_dlight" << i << "_rel_view[3];\n";
+          text << "\t lhalf = dlight_light" << i << "_rel_view[3].xyz;\n";
         }
-        text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
+        text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf)), shininess);\n";
         text << "\t tot_specular += lspec;\n";
       }
-    }
-    for (int i=0; i < (int)_plights.size(); i++) {
+    } else if (_lights[i]->is_of_type(PointLight::get_class_type())) {
       text << "\t // Point Light " << i << "\n";
-      text << "\t lcolor = plight_plight" << i << "_rel_view[0];\n";
-      text << "\t lspec  = plight_plight" << i << "_rel_view[1];\n";
-      text << "\t lpoint = plight_plight" << i << "_rel_view[2];\n";
-      text << "\t latten = plight_plight" << i << "_rel_view[3];\n";
-      text << "\t lvec   = lpoint - l_eye_position;\n";
-      text << "\t ldist = length(float3(lvec));\n";
+      text << "\t lcolor = plight_light" << i << "_rel_view[0];\n";
+      text << "\t lspec  = plight_light" << i << "_rel_view[1];\n";
+      text << "\t lpoint = plight_light" << i << "_rel_view[2];\n";
+      text << "\t latten = plight_light" << i << "_rel_view[3];\n";
+      text << "\t lvec   = lpoint.xyz - l_eye_position.xyz;\n";
+      text << "\t ldist = length(lvec);\n";
       text << "\t lvec /= ldist;\n";
       text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
-      text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
+      text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec));\n";
+      if (_shadows && _lights[i]->_shadow_caster && _auto_shadow_on) {
+        text << "\t ldist = max(abs(l_lightcoord" << i << ".x), max(abs(l_lightcoord" << i << ".y), abs(l_lightcoord" << i << ".z)));\n";
+        text << "\t ldist = ((latten.w+lpoint.w)/(latten.w-lpoint.w))+((-2*latten.w*lpoint.w)/(ldist * (latten.w-lpoint.w)));\n";
+        text << "\t lshad = texCUBE(shadow_light" << i << ", l_lightcoord" << i << ".xyz).r >= ldist * 0.5 + 0.5;\n";
+        text << "\t lcolor *= lshad;\n";
+        text << "\t lspec *= lshad;\n";
+      }
       if (_have_diffuse) {
         text << "\t tot_diffuse += lcolor;\n";
       }
       if (_have_specular) {
         if (_material->get_local()) {
-          text << "\t lhalf  = normalize(lvec - normalize(l_eye_position));\n";
+          text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
         } else {
-          text << "\t lhalf = normalize(lvec - float4(0, 1, 0, 0));\n";
+          text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
         }
         text << "\t lspec *= lattenv;\n";
-        text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
+        text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf)), shininess);\n";
         text << "\t tot_specular += lspec;\n";
       }
-    }
-    for (int i=0; i < (int)_slights.size(); i++) {
+    } else if (_lights[i]->is_of_type(Spotlight::get_class_type())) {
       text << "\t // Spot Light " << i << "\n";
-      text << "\t lcolor = slight_slight" << i << "_rel_view[0];\n";
-      text << "\t lspec  = slight_slight" << i << "_rel_view[1];\n";
-      text << "\t lpoint = slight_slight" << i << "_rel_view[2];\n";
-      text << "\t ldir   = slight_slight" << i << "_rel_view[3];\n";
-      text << "\t latten = satten_slight" << i << ";\n";
-      text << "\t lvec   = lpoint - l_eye_position;\n";
-      text << "\t ldist  = length(float3(lvec));\n";
+      text << "\t lcolor = slight_light" << i << "_rel_view[0];\n";
+      text << "\t lspec  = slight_light" << i << "_rel_view[1];\n";
+      text << "\t lpoint = slight_light" << i << "_rel_view[2];\n";
+      text << "\t ldir   = slight_light" << i << "_rel_view[3];\n";
+      text << "\t latten = satten_light" << i << ";\n";
+      text << "\t lvec   = lpoint.xyz - l_eye_position.xyz;\n";
+      text << "\t ldist  = length(lvec);\n";
       text << "\t lvec /= ldist;\n";
-      text << "\t langle = saturate(dot(ldir.xyz, lvec.xyz));\n";
+      text << "\t langle = saturate(dot(ldir.xyz, lvec));\n";
       text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
       text << "\t lattenv *= pow(langle, latten.w);\n";
       text << "\t if (langle < ldir.w) lattenv = 0;\n";
-      text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
-      if (_shadows && _slights[i]->_shadow_caster && _auto_shadow_on) {
+      text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec));\n";
+      if (_shadows && _lights[i]->_shadow_caster && _auto_shadow_on) {
         if (_use_shadow_filter) {
-          text << "\t lshad = shadow2DProj(k_slighttex" << i << ", l_slightcoord" << i << ").r;\n";
+          text << "\t lshad = shadow2DProj(shadow_light" << i << ", l_lightcoord" << i << ").r;\n";
         } else {
-          text << "\t lshad = tex2Dproj(k_slighttex" << i << ", l_slightcoord" << i << ").r > l_slightcoord" << i << ".z / l_slightcoord" << i << ".w;\n";
+          text << "\t lshad = tex2Dproj(shadow_light" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n";
         }
         text << "\t lcolor *= lshad;\n";
         text << "\t lspec *= lshad;\n";
@@ -1265,15 +1175,17 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
       }
       if (_have_specular) {
         if (_material->get_local()) {
-          text << "\t lhalf  = normalize(lvec - normalize(l_eye_position));\n";
+          text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
         } else {
-          text << "\t lhalf = normalize(lvec - float4(0,1,0,0));\n";
+          text << "\t lhalf = normalize(lvec - float3(0,1,0));\n";
         }
         text << "\t lspec *= lattenv;\n";
-        text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
+        text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf)), shininess);\n";
         text << "\t tot_specular += lspec;\n";
       }
     }
+  }
+  if (_lighting) {
     const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
     if (_auto_ramp_on && _have_diffuse) {
       switch (light_ramp->get_mode()) {

+ 2 - 9
panda/src/pgraphnodes/shaderGenerator.h

@@ -77,7 +77,6 @@ PUBLISHED:
 
 protected:
   CPT(RenderAttrib) create_shader_attrib(const string &txt);
-  PT(Texture) update_shadow_buffer(NodePath light_np);
   static const string combine_mode_as_string(CPT(TextureStage) stage,
                       TextureStage::CombineMode c_mode, bool alpha, short texindex);
   static const string combine_source_as_string(CPT(TextureStage) stage,
@@ -101,14 +100,8 @@ protected:
   Material *_material;
   int _num_textures;
 
-  pvector <AmbientLight *>     _alights;
-  pvector <DirectionalLight *> _dlights;
-  pvector <PointLight *>       _plights;
-  pvector <Spotlight *>        _slights;
-  pvector <NodePath>           _alights_np;
-  pvector <NodePath>           _dlights_np;
-  pvector <NodePath>           _plights_np;
-  pvector <NodePath>           _slights_np;
+  pvector<LightLensNode *> _lights;
+  pvector<NodePath> _lights_np;
 
   bool _vertex_colors;
   bool _flat_colors;