Browse Source

Added shadow mapping support to Panda

rdb 16 years ago
parent
commit
159026571b

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

@@ -46,6 +46,7 @@
 #include "depthWriteAttrib.h"
 #include "depthWriteAttrib.h"
 #include "lightAttrib.h"
 #include "lightAttrib.h"
 #include "texGenAttrib.h"
 #include "texGenAttrib.h"
+#include "shaderGenerator.h"
 
 
 #include <algorithm>
 #include <algorithm>
 #include <limits.h>
 #include <limits.h>
@@ -231,6 +232,8 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   
   
   _gamma = 1.0f;
   _gamma = 1.0f;
   _texture_quality_override = Texture::QL_default;
   _texture_quality_override = Texture::QL_default;
+  
+  _shader_generator = NULL;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -246,6 +249,11 @@ GraphicsStateGuardian::
     delete _stencil_render_states;
     delete _stencil_render_states;
     _stencil_render_states = 0;
     _stencil_render_states = 0;
   }
   }
+  
+  if (_shader_generator) {
+    delete _shader_generator;
+    _shader_generator = 0;
+  }
 
 
   GeomMunger::unregister_mungers_for_gsg(this);
   GeomMunger::unregister_mungers_for_gsg(this);
 }
 }

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

@@ -50,6 +50,7 @@
 
 
 class DrawableRegion;
 class DrawableRegion;
 class GraphicsEngine;
 class GraphicsEngine;
+class ShaderGenerator;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : GraphicsStateGuardian
 //       Class : GraphicsStateGuardian
@@ -483,6 +484,8 @@ protected:
 
 
   float _gamma;
   float _gamma;
   Texture::QualityLevel _texture_quality_override;
   Texture::QualityLevel _texture_quality_override;
+  
+  ShaderGenerator* _shader_generator;
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
   PT(Texture) _flash_texture;
   PT(Texture) _flash_texture;

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

@@ -60,6 +60,7 @@
 #include "lightAttrib.h"
 #include "lightAttrib.h"
 #include "scissorAttrib.h"
 #include "scissorAttrib.h"
 #include "graphicsEngine.h"
 #include "graphicsEngine.h"
+#include "shaderGenerator.h"
 
 
 #ifdef HAVE_CG
 #ifdef HAVE_CG
 #include "Cg/cgGL.h"
 #include "Cg/cgGL.h"
@@ -6275,7 +6276,14 @@ set_state_and_transform(const RenderState *target,
 
 
   _target_shader = DCAST(ShaderAttrib, _target_rs->get_attrib_def(ShaderAttrib::get_class_slot()));
   _target_shader = DCAST(ShaderAttrib, _target_rs->get_attrib_def(ShaderAttrib::get_class_slot()));
   if (_target_shader->auto_shader()) {
   if (_target_shader->auto_shader()) {
-    _target_shader = _target_rs->get_generated_shader();
+    // If we don't have a generated shader, make sure we have a ShaderGenerator, then generate the shader.
+    if (_target_rs->_generated_shader == NULL) {
+      if (_shader_generator == NULL) {
+        _shader_generator = new ShaderGenerator(this, _scene_setup->get_display_region()->get_window());
+      }
+      const_cast<RenderState*>(_target_rs.p())->_generated_shader = DCAST(ShaderAttrib, _shader_generator->synthesize_shader(_target_rs));
+    }
+    _target_shader = DCAST(ShaderAttrib, _target_rs->_generated_shader);
   }
   }
 
 
   int alpha_test_slot = AlphaTestAttrib::get_class_slot();
   int alpha_test_slot = AlphaTestAttrib::get_class_slot();

+ 10 - 24
panda/src/pgraph/renderState.cxx

@@ -1366,29 +1366,6 @@ get_geom_rendering(int geom_rendering) const {
   return geom_rendering;
   return geom_rendering;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: RenderState::get_generated_shader
-//       Access: Public
-//  Description: Generate a ShaderAttrib for this RenderState.  This
-//               generated ShaderAttrib can be thought of as a
-//               replacement for the regular ShaderAttrib that is a
-//               standard part of the RenderState.
-////////////////////////////////////////////////////////////////////
-const ShaderAttrib *RenderState::
-get_generated_shader() const {
-  // This method cannot be declared inline, because of the circular
-  // dependency on shaderAttrib.h.
-
-  if (_generated_shader != (RenderAttrib*)NULL) {
-    return DCAST(ShaderAttrib, _generated_shader);
-  }
-  ShaderGeneratorBase *gen = ShaderGeneratorBase::get_default();
-  ((RenderState*)this)->_generated_shader =
-    gen->synthesize_shader(this);
-  return DCAST(ShaderAttrib, _generated_shader);
-}
-
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::bin_removed
 //     Function: RenderState::bin_removed
 //       Access: Public, Static
 //       Access: Public, Static
@@ -1598,7 +1575,16 @@ do_compose(const RenderState *other) const {
     mask.clear_bit(slot);
     mask.clear_bit(slot);
     slot = mask.get_lowest_on_bit();
     slot = mask.get_lowest_on_bit();
   }
   }
-
+  
+  // If we have any ShaderAttrib with auto-shader enabled,
+  // remove any shader inputs on it. This is a workaround for an
+  // issue that makes the shader-generator regenerate the shader
+  // every time a shader input changes.
+  CPT(ShaderAttrib) sattrib = DCAST(ShaderAttrib, new_state->get_attrib_def(ShaderAttrib::get_class_slot()));
+  if (sattrib->auto_shader()) {
+    sattrib = DCAST(ShaderAttrib, sattrib->clear_all_shader_inputs());
+  }
+  
   return return_new(new_state);
   return return_new(new_state);
 }
 }
 
 

+ 6 - 7
panda/src/pgraph/renderState.h

@@ -153,7 +153,6 @@ PUBLISHED:
   INLINE int get_draw_order() const;
   INLINE int get_draw_order() const;
   INLINE int get_bin_index() const;
   INLINE int get_bin_index() const;
   int get_geom_rendering(int geom_rendering) const;
   int get_geom_rendering(int geom_rendering) const;
-  const ShaderAttrib *get_generated_shader() const;
   
   
 public:
 public:
   static void bin_removed(int bin_index);
   static void bin_removed(int bin_index);
@@ -206,6 +205,12 @@ private:
 public:
 public:
   static void init_states();
   static void init_states();
 
 
+  // If this state contains an "auto" ShaderAttrib, then an explicit
+  // ShaderAttrib will be synthesized by the runtime and stored here.
+  // I can't declare this as a ShaderAttrib because that would create
+  // a circular include-file dependency problem.  Aaargh.
+  CPT(RenderAttrib) _generated_shader;
+
 private:
 private:
   // This mutex protects _states.  It also protects any modification
   // This mutex protects _states.  It also protects any modification
   // to the cache, which is encoded in _composition_cache and
   // to the cache, which is encoded in _composition_cache and
@@ -291,12 +296,6 @@ private:
   int _bin_index;
   int _bin_index;
   int _draw_order;
   int _draw_order;
 
 
-  // If this state contains an "auto" ShaderAttrib, then an explicit
-  // ShaderAttrib will be synthesized by the runtime and stored here.
-  // I can't declare this as a ShaderAttrib because that would create
-  // a circular include-file dependency problem.  Aaargh.
-  CPT(RenderAttrib) _generated_shader;
-
   enum Flags {
   enum Flags {
     F_checked_bin_index     = 0x000001,
     F_checked_bin_index     = 0x000001,
     F_checked_cull_callback = 0x000002,
     F_checked_cull_callback = 0x000002,

+ 0 - 29
panda/src/pgraph/shaderGeneratorBase.cxx

@@ -15,7 +15,6 @@
 #include "shaderGeneratorBase.h"
 #include "shaderGeneratorBase.h"
 
 
 TypeHandle ShaderGeneratorBase::_type_handle;
 TypeHandle ShaderGeneratorBase::_type_handle;
-ShaderGeneratorBase *ShaderGeneratorBase::_default_generator = NULL;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ShaderGeneratorBase::Constructor
 //     Function: ShaderGeneratorBase::Constructor
@@ -34,31 +33,3 @@ ShaderGeneratorBase() {
 ShaderGeneratorBase::
 ShaderGeneratorBase::
 ~ShaderGeneratorBase() {
 ~ShaderGeneratorBase() {
 }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: ShaderGeneratorBase::get_default
-//       Access: Published, Static
-//  Description: Get a pointer to the default shader generator.
-////////////////////////////////////////////////////////////////////
-ShaderGeneratorBase *ShaderGeneratorBase::
-get_default() {
-  return _default_generator;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ShaderGeneratorBase::set_default
-//       Access: Published, Static
-//  Description: Set the default shader generator.
-////////////////////////////////////////////////////////////////////
-void ShaderGeneratorBase::
-set_default(ShaderGeneratorBase *generator) {
-  if (generator != _default_generator) {
-    if (_default_generator != (ShaderGeneratorBase *)NULL) {
-      unref_delete(_default_generator);
-    }
-    _default_generator = generator;
-    if (_default_generator != (ShaderGeneratorBase *)NULL) {
-      _default_generator->ref();
-    }
-  }
-}

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

@@ -23,16 +23,11 @@
 // Description : This is the abstract base class for ShaderGenerator.
 // Description : This is the abstract base class for ShaderGenerator.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_PGRAPH ShaderGeneratorBase : public TypedWritableReferenceCount {
 class EXPCL_PANDA_PGRAPH ShaderGeneratorBase : public TypedWritableReferenceCount {
-private:
-  static ShaderGeneratorBase *_default_generator;
-
 protected:
 protected:
   ShaderGeneratorBase();
   ShaderGeneratorBase();
 
 
 PUBLISHED:
 PUBLISHED:
   virtual ~ShaderGeneratorBase();
   virtual ~ShaderGeneratorBase();
-  static ShaderGeneratorBase *get_default();
-  static void set_default(ShaderGeneratorBase *generator);
   virtual CPT(RenderAttrib) synthesize_shader(const RenderState *rs)=0;
   virtual CPT(RenderAttrib) synthesize_shader(const RenderState *rs)=0;
   
   
 public:
 public:

+ 0 - 2
panda/src/pgraphnodes/config_pgraphnodes.cxx

@@ -79,6 +79,4 @@ init_libpgraphnodes() {
   SequenceNode::register_with_read_factory();
   SequenceNode::register_with_read_factory();
   Spotlight::register_with_read_factory();
   Spotlight::register_with_read_factory();
   SwitchNode::register_with_read_factory();
   SwitchNode::register_with_read_factory();
-
-  ShaderGenerator::set_default(new ShaderGenerator());
 }
 }

+ 244 - 66
panda/src/pgraphnodes/shaderGenerator.cxx

@@ -33,6 +33,9 @@
 #include "directionalLight.h"
 #include "directionalLight.h"
 #include "pointLight.h"
 #include "pointLight.h"
 #include "spotlight.h"
 #include "spotlight.h"
+#include "lightLensNode.h"
+#include "graphicsEngine.h"
+#include "lvector4.h"
 
 
 TypeHandle ShaderGenerator::_type_handle;
 TypeHandle ShaderGenerator::_type_handle;
 
 
@@ -41,9 +44,12 @@ TypeHandle ShaderGenerator::_type_handle;
 //       Access: Published
 //       Access: Published
 //  Description: Create a ShaderGenerator.  This has no state,
 //  Description: Create a ShaderGenerator.  This has no state,
 //               except possibly to cache certain results.
 //               except possibly to cache certain results.
+//               The parameter that must be passed is the GSG to
+//               which the shader generator belongs.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 ShaderGenerator::
 ShaderGenerator::
-ShaderGenerator() {
+ShaderGenerator(PT(GraphicsStateGuardian) gsg, PT(GraphicsOutput) host) :
+  _gsg (gsg), _host (host) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -73,7 +79,7 @@ reset_register_allocator() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ShaderGenerator::alloc_vreg
 //     Function: ShaderGenerator::alloc_vreg
 //       Access: Protected
 //       Access: Protected
-//  Description: Allocate a vreg.  
+//  Description: Allocate a vreg.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE char *ShaderGenerator::
 INLINE char *ShaderGenerator::
 alloc_vreg() {
 alloc_vreg() {
@@ -135,7 +141,7 @@ analyze_renderstate(const RenderState *rs) {
   int outputs = aux_bitplane->get_outputs();
   int outputs = aux_bitplane->get_outputs();
 
 
   // Decide whether or not we need alpha testing or alpha blending.
   // 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 = DCAST(AlphaTestAttrib, rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
   if ((alpha_test->get_mode() != RenderAttrib::M_none)&&
   if ((alpha_test->get_mode() != RenderAttrib::M_none)&&
       (alpha_test->get_mode() != RenderAttrib::M_always)) {
       (alpha_test->get_mode() != RenderAttrib::M_always)) {
@@ -150,9 +156,9 @@ analyze_renderstate(const RenderState *rs) {
       (transparency->get_mode() == TransparencyAttrib::M_dual)) {
       (transparency->get_mode() == TransparencyAttrib::M_dual)) {
     _have_alpha_blend = true;
     _have_alpha_blend = true;
   }
   }
-  
+
   // Decide what to send to the framebuffer alpha, if anything.
   // Decide what to send to the framebuffer alpha, if anything.
-  
+
   if (outputs & AuxBitplaneAttrib::ABO_glow) {
   if (outputs & AuxBitplaneAttrib::ABO_glow) {
     if (_have_alpha_blend) {
     if (_have_alpha_blend) {
       _calc_primary_alpha = true;
       _calc_primary_alpha = true;
@@ -171,18 +177,18 @@ analyze_renderstate(const RenderState *rs) {
       _calc_primary_alpha = true;
       _calc_primary_alpha = true;
     }
     }
   }
   }
-  
+
   // Determine what to put into the aux bitplane.
   // Determine what to put into the aux bitplane.
 
 
   _out_aux_normal = (outputs & AuxBitplaneAttrib::ABO_aux_normal) ? true:false;
   _out_aux_normal = (outputs & AuxBitplaneAttrib::ABO_aux_normal) ? true:false;
   _out_aux_glow = (outputs & AuxBitplaneAttrib::ABO_aux_glow) ? true:false;
   _out_aux_glow = (outputs & AuxBitplaneAttrib::ABO_aux_glow) ? true:false;
   _out_aux_any = (_out_aux_normal || _out_aux_glow);
   _out_aux_any = (_out_aux_normal || _out_aux_glow);
-  
+
   // Count number of textures.
   // Count number of textures.
 
 
   const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot()));
   const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot()));
   _num_textures = texture->get_num_on_stages();
   _num_textures = texture->get_num_on_stages();
-  
+
   // Determine whether or not vertex colors or flat colors are present.
   // 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 = DCAST(ColorAttrib, rs->get_attrib_def(ColorAttrib::get_class_slot()));
@@ -194,13 +200,14 @@ analyze_renderstate(const RenderState *rs) {
 
 
   // Break out the lights by type.
   // Break out the lights by type.
 
 
+  _shadows = false;
   const LightAttrib *la = DCAST(LightAttrib, rs->get_attrib_def(LightAttrib::get_class_slot()));
   const LightAttrib *la = DCAST(LightAttrib, rs->get_attrib_def(LightAttrib::get_class_slot()));
   for (int i=0; i<la->get_num_on_lights(); i++) {
   for (int i=0; i<la->get_num_on_lights(); i++) {
     NodePath light = la->get_on_light(i);
     NodePath light = la->get_on_light(i);
     nassertv(!light.is_empty());
     nassertv(!light.is_empty());
     PandaNode *light_obj = light.node();
     PandaNode *light_obj = light.node();
     nassertv(light_obj != (PandaNode *)NULL);
     nassertv(light_obj != (PandaNode *)NULL);
-    
+
     if (light_obj->get_type() == AmbientLight::get_class_type()) {
     if (light_obj->get_type() == AmbientLight::get_class_type()) {
       _alights_np.push_back(light);
       _alights_np.push_back(light);
       _alights.push_back((AmbientLight*)light_obj);
       _alights.push_back((AmbientLight*)light_obj);
@@ -208,6 +215,9 @@ analyze_renderstate(const RenderState *rs) {
     else if (light_obj->get_type() == DirectionalLight::get_class_type()) {
     else if (light_obj->get_type() == DirectionalLight::get_class_type()) {
       _dlights_np.push_back(light);
       _dlights_np.push_back(light);
       _dlights.push_back((DirectionalLight*)light_obj);
       _dlights.push_back((DirectionalLight*)light_obj);
+      if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) {
+        _shadows = true;
+      }
     }
     }
     else if (light_obj->get_type() == PointLight::get_class_type()) {
     else if (light_obj->get_type() == PointLight::get_class_type()) {
       _plights_np.push_back(light);
       _plights_np.push_back(light);
@@ -216,11 +226,14 @@ analyze_renderstate(const RenderState *rs) {
     else if (light_obj->get_type() == Spotlight::get_class_type()) {
     else if (light_obj->get_type() == Spotlight::get_class_type()) {
       _slights_np.push_back(light);
       _slights_np.push_back(light);
       _slights.push_back((Spotlight*)light_obj);
       _slights.push_back((Spotlight*)light_obj);
+      if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) {
+        _shadows = true;
+      }
     }
     }
   }
   }
 
 
   // See if there is a normal map, height map, gloss map, or glow map.
   // See if there is a normal map, height map, gloss map, or glow map.
-  
+
   for (int i=0; i<_num_textures; i++) {
   for (int i=0; i<_num_textures; i++) {
     TextureStage *stage = texture->get_on_stage(i);
     TextureStage *stage = texture->get_on_stage(i);
     TextureStage::Mode mode = stage->get_mode();
     TextureStage::Mode mode = stage->get_mode();
@@ -237,25 +250,25 @@ analyze_renderstate(const RenderState *rs) {
       _map_index_gloss = i;
       _map_index_gloss = i;
     }
     }
   }
   }
-  
+
   // Determine whether lighting is needed.
   // Determine whether lighting is needed.
 
 
   if (la->get_num_on_lights() > 0) {
   if (la->get_num_on_lights() > 0) {
     _lighting = true;
     _lighting = true;
   }
   }
-  
+
   // Find the material.
   // Find the material.
 
 
   const MaterialAttrib *material = DCAST(MaterialAttrib, rs->get_attrib_def(MaterialAttrib::get_class_slot()));
   const MaterialAttrib *material = DCAST(MaterialAttrib, rs->get_attrib_def(MaterialAttrib::get_class_slot()));
-  
+
   if (!material->is_off()) {
   if (!material->is_off()) {
     _material = material->get_material();
     _material = material->get_material();
   } else {
   } else {
     _material = Material::get_default();
     _material = Material::get_default();
   }
   }
-  
+
   // Decide which material modes need to be calculated.
   // Decide which material modes need to be calculated.
-  
+
   if (_lighting && (_alights.size() > 0)) {
   if (_lighting && (_alights.size() > 0)) {
     if (_material->has_ambient()) {
     if (_material->has_ambient()) {
       Colorf a = _material->get_ambient();
       Colorf a = _material->get_ambient();
@@ -277,14 +290,14 @@ analyze_renderstate(const RenderState *rs) {
       _have_diffuse = true;
       _have_diffuse = true;
     }
     }
   }
   }
-  
+
   if (_lighting && (_material->has_emission())) {
   if (_lighting && (_material->has_emission())) {
     Colorf e = _material->get_emission();
     Colorf e = _material->get_emission();
     if ((e[0]!=0.0)||(e[1]!=0.0)||(e[2]!=0.0)) {
     if ((e[0]!=0.0)||(e[1]!=0.0)||(e[2]!=0.0)) {
       _have_emission = true;
       _have_emission = true;
     }
     }
   }
   }
-  
+
   if (_lighting && (_dlights.size() + _plights.size() + _slights.size())) {
   if (_lighting && (_dlights.size() + _plights.size() + _slights.size())) {
     if (_material->has_specular()) {
     if (_material->has_specular()) {
       Colorf s = _material->get_specular();
       Colorf s = _material->get_specular();
@@ -295,7 +308,7 @@ analyze_renderstate(const RenderState *rs) {
       _have_specular = true;
       _have_specular = true;
     }
     }
   }
   }
-  
+
   // Decide whether to separate ambient and diffuse calculations.
   // Decide whether to separate ambient and diffuse calculations.
 
 
   if (_have_ambient && _have_diffuse) {
   if (_have_ambient && _have_diffuse) {
@@ -315,14 +328,19 @@ analyze_renderstate(const RenderState *rs) {
   }
   }
 
 
   const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
   const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
-  if (_lighting && 
+  if (_lighting &&
       (light_ramp->get_mode() != LightRampAttrib::LRT_identity)) {
       (light_ramp->get_mode() != LightRampAttrib::LRT_identity)) {
     _separate_ambient_diffuse = true;
     _separate_ambient_diffuse = true;
   }
   }
-  
+
+  // Do we want to use the ARB_shadow extension?
+  // This also allows us to use hardware shadows / PCF.
+
+  _use_shadow_filter = _gsg->get_supports_shadow_filter();
+
   // Does the shader need material properties as input?
   // Does the shader need material properties as input?
-  
-  _need_material_props = 
+
+  _need_material_props =
     (_have_ambient  && (_material->has_ambient()))||
     (_have_ambient  && (_material->has_ambient()))||
     (_have_diffuse  && (_material->has_diffuse()))||
     (_have_diffuse  && (_material->has_diffuse()))||
     (_have_emission && (_material->has_emission()))||
     (_have_emission && (_material->has_emission()))||
@@ -349,8 +367,6 @@ analyze_renderstate(const RenderState *rs) {
   }
   }
 }
 }
 
 
-
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ShaderGenerator::clear_analysis
 //     Function: ShaderGenerator::clear_analysis
 //       Access: Protected
 //       Access: Protected
@@ -363,6 +379,7 @@ clear_analysis() {
   _vertex_colors = false;
   _vertex_colors = false;
   _flat_colors = false;
   _flat_colors = false;
   _lighting = false;
   _lighting = false;
+  _shadows = false;
   _have_ambient = false;
   _have_ambient = false;
   _have_diffuse = false;
   _have_diffuse = false;
   _have_emission = false;
   _have_emission = false;
@@ -378,10 +395,11 @@ clear_analysis() {
   _subsume_alpha_test = false;
   _subsume_alpha_test = false;
   _disable_alpha_write = false;
   _disable_alpha_write = false;
   _num_clip_planes = 0;
   _num_clip_planes = 0;
+  _use_shadow_filter = false;
   _out_primary_glow  = false;
   _out_primary_glow  = false;
-  _out_aux_normal = false;
-  _out_aux_glow   = false;
-  _out_aux_any    = false;
+  _out_aux_normal   = false;
+  _out_aux_glow     = false;
+  _out_aux_any      = false;
   _material = (Material*)NULL;
   _material = (Material*)NULL;
   _need_material_props = false;
   _need_material_props = false;
   _alights.clear();
   _alights.clear();
@@ -412,22 +430,110 @@ create_shader_attrib(const string &txt) {
     }
     }
     for (int i=0; i<(int)_dlights.size(); i++) {
     for (int i=0; i<(int)_dlights.size(); i++) {
       shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("dlight", i), _dlights_np[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) {
+          pgraph_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++) {
     for (int i=0; i<(int)_plights.size(); i++) {
       shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("plight", i), _plights_np[i]);
       shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("plight", i), _plights_np[i]);
     }
     }
     for (int i=0; i<(int)_slights.size(); i++) {
     for (int i=0; i<(int)_slights.size(); i++) {
       shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("slight", i), _slights_np[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) {
+          pgraph_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;
   return shattr;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     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.
+  PT(GraphicsOutput) sbuffer;
+  PT(Texture) tex;
+  if (light->_sbuffers.count(DCAST(GraphicsStateGuardianBase, _gsg)) == 0) {
+
+    // Nope, the light doesn't have a buffer for our GSG.
+    FrameBufferProperties fbp;
+    fbp.set_depth_bits(1); // We only need depth
+    pgraph_cat.debug() << "Constructing shadow buffer for light '" << light->get_name()
+      << "', size=" << light->_sb_xsize << "x" << light->_sb_ysize
+      << ", sort=" << light->_sb_sort << "\n";
+    sbuffer = _gsg->get_engine()->make_output(_gsg->get_pipe(), light->get_name(),
+      light->_sb_sort, fbp, WindowProperties::size(light->_sb_xsize, light->_sb_ysize),
+      GraphicsPipe::BF_refuse_window, _gsg, _host);
+    nassertr(sbuffer != NULL, NULL);
+
+    // Create a texture and fill it in with some data to workaround an OpenGL error
+    tex = new Texture(light->get_name());
+    tex->setup_2d_texture(light->_sb_xsize, light->_sb_ysize, Texture::T_float, Texture::F_depth_stencil);
+    tex->make_ram_image();
+    sbuffer->add_render_texture(tex, GraphicsOutput::RTM_bind_or_copy,
+                                     DrawableRegion::RTP_depth_stencil);
+    // Set the wrap mode to BORDER_COLOR
+    tex->set_wrap_u(Texture::WM_border_color);
+    tex->set_wrap_v(Texture::WM_border_color);
+    tex->set_border_color(LVecBase4f(1, 1, 1, 1));
+
+    if (_use_shadow_filter) {
+      // If we have the ARB_shadow extension, enable shadow filtering.
+      tex->set_minfilter(Texture::FT_shadow);
+      tex->set_magfilter(Texture::FT_shadow);
+    } else {
+      // We only accept linear - this tells the GPU to use hardware PCF.
+      tex->set_minfilter(Texture::FT_linear);
+      tex->set_magfilter(Texture::FT_linear);
+    }
+    sbuffer->make_display_region(0, 1, 0, 1)->set_camera(light_np);
+    light->_sbuffers[DCAST(GraphicsStateGuardianBase, _gsg)] = DCAST(GraphicsOutputBase, sbuffer);
+
+  } else {
+
+    // There's already a buffer - use that.
+    sbuffer = DCAST(GraphicsOutput, light->_sbuffers[DCAST(GraphicsStateGuardianBase, _gsg)]);
+    tex = sbuffer->get_texture();
+    nassertr(tex != NULL, NULL);
+  }
+
+  return tex;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ShaderGenerator::synthesize_shader
 //     Function: ShaderGenerator::synthesize_shader
 //       Access: Published, Virtual
 //       Access: Published, Virtual
 //  Description: This is the routine that implements the next-gen
 //  Description: This is the routine that implements the next-gen
 //               fixed function pipeline by synthesizing a shader.
 //               fixed function pipeline by synthesizing a shader.
+//               It also takes care of setting up any buffers
+//               needed to produce the requested effects.
 //
 //
 //               Currently supports:
 //               Currently supports:
 //               - flat colors
 //               - flat colors
@@ -441,6 +547,7 @@ create_shader_attrib(const string &txt) {
 //               - all texture stage modes, including combine modes
 //               - all texture stage modes, including combine modes
 //               - color scale attrib
 //               - color scale attrib
 //               - light ramps (for cartoon shading)
 //               - light ramps (for cartoon shading)
+//               - shadow mapping
 //
 //
 //               Not yet supported:
 //               Not yet supported:
 //               - 3D textures, cube textures
 //               - 3D textures, cube textures
@@ -458,6 +565,8 @@ synthesize_shader(const RenderState *rs) {
   analyze_renderstate(rs);
   analyze_renderstate(rs);
   reset_register_allocator();
   reset_register_allocator();
 
 
+  pgraph_cat.info() << "Generating shader for render state " << rs << "\n";
+
   // These variables will hold the results of register allocation.
   // These variables will hold the results of register allocation.
 
 
   char *pos_freg = 0;
   char *pos_freg = 0;
@@ -470,7 +579,7 @@ synthesize_shader(const RenderState *rs) {
   pvector<char *> texcoord_vreg;
   pvector<char *> texcoord_vreg;
   pvector<char *> texcoord_freg;
   pvector<char *> texcoord_freg;
   pvector<char *> tslightvec_freg;
   pvector<char *> tslightvec_freg;
-  
+
   if (_vertex_colors) {
   if (_vertex_colors) {
     _vcregs_used = 1;
     _vcregs_used = 1;
     _fcregs_used = 1;
     _fcregs_used = 1;
@@ -479,7 +588,7 @@ synthesize_shader(const RenderState *rs) {
   // Generate the shader's text.
   // Generate the shader's text.
 
 
   ostringstream text;
   ostringstream text;
-  
+
   text << "//Cg\n";
   text << "//Cg\n";
 
 
   text << "void vshader(\n";
   text << "void vshader(\n";
@@ -516,6 +625,20 @@ synthesize_shader(const RenderState *rs) {
       text << "\t out float4 l_tangent : " << tangent_freg << ",\n";
       text << "\t out float4 l_tangent : " << tangent_freg << ",\n";
       text << "\t out float4 l_binormal : " << binormal_freg << ",\n";
       text << "\t out float4 l_binormal : " << binormal_freg << ",\n";
     }
     }
+    if (_shadows) {
+      for (int i=0; i<(int)_dlights.size(); i++) {
+        if (_dlights[i]->_shadow_caster) {
+          text << "\t uniform float4x4 trans_model_to_clip_of_dlight" << i << ",\n";
+          text << "\t out float4 l_dlightcoord" << i << ",\n";
+        }
+      }
+      for (int i=0; i<(int)_slights.size(); i++) {
+        if (_slights[i]->_shadow_caster) {
+          text << "\t uniform float4x4 trans_model_to_clip_of_slight" << i << ",\n";
+          text << "\t out float4 l_slightcoord" << i << ",\n";
+        }
+      }
+    }
   } else if (_out_aux_normal) {
   } else if (_out_aux_normal) {
     normal_vreg = alloc_vreg();
     normal_vreg = alloc_vreg();
     normal_freg = alloc_freg();
     normal_freg = alloc_freg();
@@ -523,12 +646,12 @@ synthesize_shader(const RenderState *rs) {
     text << "\t in float4 vtx_normal : " << normal_vreg << ",\n";
     text << "\t in float4 vtx_normal : " << normal_vreg << ",\n";
     text << "\t out float4 l_normal : " << normal_freg << ",\n";
     text << "\t out float4 l_normal : " << normal_freg << ",\n";
   }
   }
-  
+
   text << "\t float4 vtx_position : POSITION,\n";
   text << "\t float4 vtx_position : POSITION,\n";
   text << "\t out float4 l_position : POSITION,\n";
   text << "\t out float4 l_position : POSITION,\n";
   text << "\t uniform float4x4 mat_modelproj\n";
   text << "\t uniform float4x4 mat_modelproj\n";
   text << ") {\n";
   text << ") {\n";
-  
+
   text << "\t l_position = mul(mat_modelproj, vtx_position);\n";
   text << "\t l_position = mul(mat_modelproj, vtx_position);\n";
   if (_num_clip_planes > 0) {
   if (_num_clip_planes > 0) {
     text << "\t l_worldpos = mul(trans_model_to_world, vtx_position);\n";
     text << "\t l_worldpos = mul(trans_model_to_world, vtx_position);\n";
@@ -552,8 +675,23 @@ synthesize_shader(const RenderState *rs) {
     text << "\t l_binormal.xyz = mul((float3x3)tpose_view_to_model, -vtx_binormal" << _map_index_normal << ".xyz);\n";
     text << "\t l_binormal.xyz = mul((float3x3)tpose_view_to_model, -vtx_binormal" << _map_index_normal << ".xyz);\n";
     text << "\t l_binormal.w = 0;\n";
     text << "\t l_binormal.w = 0;\n";
   }
   }
+  if (_shadows) {
+    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 + " << _dlights[i]->_push_bias << " * vtx_normal));\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 + " << _slights[i]->_push_bias << " * vtx_normal));\n";
+      }
+    }
+  }
   text << "}\n\n";
   text << "}\n\n";
-  
+
   text << "void fshader(\n";
   text << "void fshader(\n";
   if (_num_clip_planes > 0) {
   if (_num_clip_planes > 0) {
     text << "\t in float4 l_worldpos,\n";
     text << "\t in float4 l_worldpos,\n";
@@ -571,11 +709,22 @@ synthesize_shader(const RenderState *rs) {
   }
   }
   if (_lighting) {
   if (_lighting) {
     text << "\t in float4 l_pos : " << pos_freg << ",\n";
     text << "\t in float4 l_pos : " << pos_freg << ",\n";
+    if (_shadows) {
+      text << "\t in float4 l_position : " << alloc_freg() << ",\n";
+    }
     for (int i=0; i<(int)_alights.size(); i++) {
     for (int i=0; i<(int)_alights.size(); i++) {
       text << "\t uniform float4 alight_alight" << i << ",\n";
       text << "\t uniform float4 alight_alight" << i << ",\n";
     }
     }
     for (int i=0; i<(int)_dlights.size(); i++) {
     for (int i=0; i<(int)_dlights.size(); i++) {
       text << "\t uniform float4x4 dlight_dlight" << i << "_rel_view,\n";
       text << "\t uniform float4x4 dlight_dlight" << i << "_rel_view,\n";
+      if (_shadows && _dlights[i]->_shadow_caster) {
+        if (_use_shadow_filter) {
+          text << "\t uniform sampler2DShadow k_dlighttex" << i << ",\n";
+        } else {
+          text << "\t uniform sampler2D k_dlighttex" << i << ",\n";
+        }
+        text << "\t float4 l_dlightcoord" << i << ",\n";
+      }
     }
     }
     for (int i=0; i<(int)_plights.size(); i++) {
     for (int i=0; i<(int)_plights.size(); i++) {
       text << "\t uniform float4x4 plight_plight" << i << "_rel_view,\n";
       text << "\t uniform float4x4 plight_plight" << i << "_rel_view,\n";
@@ -583,6 +732,14 @@ synthesize_shader(const RenderState *rs) {
     for (int i=0; i<(int)_slights.size(); i++) {
     for (int i=0; i<(int)_slights.size(); i++) {
       text << "\t uniform float4x4 slight_slight" << i << "_rel_view,\n";
       text << "\t uniform float4x4 slight_slight" << i << "_rel_view,\n";
       text << "\t uniform float4   satten_slight" << i << ",\n";
       text << "\t uniform float4   satten_slight" << i << ",\n";
+      if (_shadows && _slights[i]->_shadow_caster) {
+        if (_use_shadow_filter) {
+          text << "\t uniform sampler2DShadow k_slighttex" << i << ",\n";
+        } else {
+          text << "\t uniform sampler2D k_slighttex" << i << ",\n";
+        }
+        text << "\t float4 l_slightcoord" << i << ",\n";
+      }
     }
     }
     if (_need_material_props) {
     if (_need_material_props) {
       text << "\t uniform float4x4 attr_material,\n";
       text << "\t uniform float4x4 attr_material,\n";
@@ -644,7 +801,10 @@ synthesize_shader(const RenderState *rs) {
   if (_lighting) {
   if (_lighting) {
     text << "\t // Begin view-space light calculations\n";
     text << "\t // Begin view-space light calculations\n";
     text << "\t float ldist,lattenv,langle;\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,lvec,lpoint,latten,ldir,leye,lhalf;";
+    if (_shadows) {
+      text << "\t float lshad;\n";
+    }
     if (_separate_ambient_diffuse) {
     if (_separate_ambient_diffuse) {
       if (_have_ambient) {
       if (_have_ambient) {
         text << "\t float4 tot_ambient = float4(0,0,0,0);\n";
         text << "\t float4 tot_ambient = float4(0,0,0,0);\n";
@@ -680,6 +840,15 @@ synthesize_shader(const RenderState *rs) {
       text << "\t lspec  = dlight_dlight" << i << "_rel_view[1];\n";
       text << "\t lspec  = dlight_dlight" << i << "_rel_view[1];\n";
       text << "\t lvec   = dlight_dlight" << i << "_rel_view[2];\n";
       text << "\t lvec   = dlight_dlight" << i << "_rel_view[2];\n";
       text << "\t lcolor *= saturate(dot(l_normal, lvec.xyz));\n";
       text << "\t lcolor *= saturate(dot(l_normal, lvec.xyz));\n";
+      if (_shadows && _dlights[i]->_shadow_caster) {
+        if (_use_shadow_filter) {
+          text << "\t lshad = shadow2DProj(k_dlighttex" << i << ", l_dlightcoord" << 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 lcolor *= lshad;\n";
+        text << "\t lspec *= lshad;\n";
+      }
       if (_have_diffuse) {
       if (_have_diffuse) {
         text << "\t tot_diffuse += lcolor;\n";
         text << "\t tot_diffuse += lcolor;\n";
       }
       }
@@ -733,6 +902,16 @@ synthesize_shader(const RenderState *rs) {
       text << "\t lattenv *= pow(langle, latten.w);\n";
       text << "\t lattenv *= pow(langle, latten.w);\n";
       text << "\t if (langle < ldir.w) lattenv = 0;\n";
       text << "\t if (langle < ldir.w) lattenv = 0;\n";
       text << "\t lcolor *= lattenv * saturate(dot(l_normal, lvec.xyz));\n";
       text << "\t lcolor *= lattenv * saturate(dot(l_normal, lvec.xyz));\n";
+      if (_shadows && _slights[i]->_shadow_caster) {
+        if (_use_shadow_filter) {
+          text << "\t lshad = shadow2DProj(k_slighttex" << i << ", l_slightcoord" << 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 lcolor *= lshad;\n";
+        text << "\t lspec *= lshad;\n";
+      }
+
       if (_have_diffuse) {
       if (_have_diffuse) {
         text << "\t tot_diffuse += lcolor;\n";
         text << "\t tot_diffuse += lcolor;\n";
       }
       }
@@ -837,9 +1016,8 @@ synthesize_shader(const RenderState *rs) {
       text << "\t result = float4(1,1,1,1);\n";
       text << "\t result = float4(1,1,1,1);\n";
     }
     }
   }
   }
-  
+
   text << "\t float4 primary_color = result;\n";
   text << "\t float4 primary_color = result;\n";
-  text << "\t float4 last_saved_result = result;\n";
   const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot()));
   const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot()));
   bool have_saved_result = false;
   bool have_saved_result = false;
   for (int i=0; i<_num_textures; i++) {
   for (int i=0; i<_num_textures; i++) {
@@ -869,14 +1047,14 @@ synthesize_shader(const RenderState *rs) {
       break;
       break;
     case TextureStage::M_combine:
     case TextureStage::M_combine:
       text << "\t result.rgb = ";
       text << "\t result.rgb = ";
-      text << combine_mode_as_string(stage, stage->get_combine_rgb_mode(), false, i, rs);
-      text << "\n\t result.a = ";
-      text << combine_mode_as_string(stage, stage->get_combine_alpha_mode(), true, i, rs);
-      text << "\n";
+      text << combine_mode_as_string(stage, stage->get_combine_rgb_mode(), false, i);
+      text << ";\n\t result.a = ";
+      text << combine_mode_as_string(stage, stage->get_combine_alpha_mode(), true, i);
+      text << ";\n";
       break;
       break;
-    case TextureStage::M_blend_color_scale: {
+    case TextureStage::M_blend_color_scale:
       text << "\t result.rgb = lerp(result, tex" << i << " * attr_colorscale, tex" << i << ".r).rgb;\n";
       text << "\t result.rgb = lerp(result, tex" << i << " * attr_colorscale, tex" << i << ".r).rgb;\n";
-      break; }
+      break;
     default:
     default:
       break;
       break;
     }
     }
@@ -906,7 +1084,7 @@ synthesize_shader(const RenderState *rs) {
     case RenderAttrib::M_greater_equal:  text<<"\t if (result.a <  "<<ref<<") discard;\n";
     case RenderAttrib::M_greater_equal:  text<<"\t if (result.a <  "<<ref<<") discard;\n";
     }
     }
   }
   }
-  
+
   if (_out_primary_glow) {
   if (_out_primary_glow) {
     if (_map_index_glow >= 0) {
     if (_map_index_glow >= 0) {
       text << "\t result.a = tex" << _map_index_glow << ".a;\n";
       text << "\t result.a = tex" << _map_index_glow << ".a;\n";
@@ -921,7 +1099,7 @@ synthesize_shader(const RenderState *rs) {
       text << "\t o_aux.a = 0.5;\n";
       text << "\t o_aux.a = 0.5;\n";
     }
     }
   }
   }
-  
+
   if (_lighting) {
   if (_lighting) {
     if (_have_specular) {
     if (_have_specular) {
       if (_material->has_specular()) {
       if (_material->has_specular()) {
@@ -933,7 +1111,7 @@ synthesize_shader(const RenderState *rs) {
       text << "\t result.rgb = result.rgb + tot_specular.rgb;\n";
       text << "\t result.rgb = result.rgb + tot_specular.rgb;\n";
     }
     }
   }
   }
-  
+
   const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
   const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
   switch (light_ramp->get_mode()) {
   switch (light_ramp->get_mode()) {
   case LightRampAttrib::LRT_hdr0:
   case LightRampAttrib::LRT_hdr0:
@@ -947,10 +1125,10 @@ synthesize_shader(const RenderState *rs) {
     break;
     break;
   default: break;
   default: break;
   }
   }
-   
+
   // The multiply is a workaround for a radeon driver bug.
   // The multiply is a workaround for a radeon driver bug.
   // It's annoying as heck, since it produces an extra instruction.
   // It's annoying as heck, since it produces an extra instruction.
-  text << "\t o_color = result * 1.000001;\n"; 
+  text << "\t o_color = result * 1.000001;\n";
   if (_subsume_alpha_test) {
   if (_subsume_alpha_test) {
     text << "\t // Shader subsumes normal alpha test.\n";
     text << "\t // Shader subsumes normal alpha test.\n";
   }
   }
@@ -958,7 +1136,7 @@ synthesize_shader(const RenderState *rs) {
     text << "\t // Shader disables alpha write.\n";
     text << "\t // Shader disables alpha write.\n";
   }
   }
   text << "}\n";
   text << "}\n";
-  
+
   // Insert the shader into the shader attrib.
   // Insert the shader into the shader attrib.
   CPT(RenderAttrib) shattr = create_shader_attrib(text.str());
   CPT(RenderAttrib) shattr = create_shader_attrib(text.str());
   if (_subsume_alpha_test) {
   if (_subsume_alpha_test) {
@@ -978,38 +1156,35 @@ synthesize_shader(const RenderState *rs) {
 //  Description: This 'synthesizes' a combine mode into a string.
 //  Description: This 'synthesizes' a combine mode into a string.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 const string ShaderGenerator::
 const string ShaderGenerator::
-combine_mode_as_string(CPT(TextureStage) stage, TextureStage::CombineMode c_mode, bool single_value, short texindex, const RenderState *rs) {
+combine_mode_as_string(CPT(TextureStage) stage, TextureStage::CombineMode c_mode, bool single_value, short texindex) {
   ostringstream text;
   ostringstream text;
   switch (c_mode) {
   switch (c_mode) {
-    case TextureStage::CM_replace:
-      text << combine_source_as_string(stage, 0, single_value, texindex, rs);
-      break;
     case TextureStage::CM_modulate:
     case TextureStage::CM_modulate:
-      text << combine_source_as_string(stage, 0, single_value, texindex, rs);
+      text << combine_source_as_string(stage, 0, single_value, texindex);
       text << " * ";
       text << " * ";
-      text << combine_source_as_string(stage, 1, single_value, texindex, rs);
+      text << combine_source_as_string(stage, 1, single_value, texindex);
       break;
       break;
     case TextureStage::CM_add:
     case TextureStage::CM_add:
-      text << combine_source_as_string(stage, 0, single_value, texindex, rs);
+      text << combine_source_as_string(stage, 0, single_value, texindex);
       text << " + ";
       text << " + ";
-      text << combine_source_as_string(stage, 1, single_value, texindex, rs);
+      text << combine_source_as_string(stage, 1, single_value, texindex);
       break;
       break;
     case TextureStage::CM_add_signed:
     case TextureStage::CM_add_signed:
       pgraph_cat.error() << "TextureStage::CombineMode ADD_SIGNED not yet supported in per-pixel mode.\n";
       pgraph_cat.error() << "TextureStage::CombineMode ADD_SIGNED not yet supported in per-pixel mode.\n";
       break;
       break;
     case TextureStage::CM_interpolate:
     case TextureStage::CM_interpolate:
       text << "lerp(";
       text << "lerp(";
-      text << combine_source_as_string(stage, 0, single_value, texindex, rs);
+      text << combine_source_as_string(stage, 1, single_value, texindex);
       text << ", ";
       text << ", ";
-      text << combine_source_as_string(stage, 1, single_value, texindex, rs);
+      text << combine_source_as_string(stage, 0, single_value, texindex);
       text << ", ";
       text << ", ";
-      text << combine_source_as_string(stage, 2, true, texindex, rs);
+      text << combine_source_as_string(stage, 2, true, texindex);
       text << ")";
       text << ")";
       break;
       break;
     case TextureStage::CM_subtract:
     case TextureStage::CM_subtract:
-      text << combine_source_as_string(stage, 0, single_value, texindex, rs);
+      text << combine_source_as_string(stage, 0, single_value, texindex);
       text << " + ";
       text << " + ";
-      text << combine_source_as_string(stage, 1, single_value, texindex, rs);
+      text << combine_source_as_string(stage, 1, single_value, texindex);
       break;
       break;
     case TextureStage::CM_dot3_rgb:
     case TextureStage::CM_dot3_rgb:
       pgraph_cat.error() << "TextureStage::CombineMode DOT3_RGB not yet supported in per-pixel mode.\n";
       pgraph_cat.error() << "TextureStage::CombineMode DOT3_RGB not yet supported in per-pixel mode.\n";
@@ -1017,6 +1192,10 @@ combine_mode_as_string(CPT(TextureStage) stage, TextureStage::CombineMode c_mode
     case TextureStage::CM_dot3_rgba:
     case TextureStage::CM_dot3_rgba:
       pgraph_cat.error() << "TextureStage::CombineMode DOT3_RGBA not yet supported in per-pixel mode.\n";
       pgraph_cat.error() << "TextureStage::CombineMode DOT3_RGBA not yet supported in per-pixel mode.\n";
       break;
       break;
+    case TextureStage::CM_replace:
+    default: // Not sure if this is correct as default value.
+      text << combine_source_as_string(stage, 0, single_value, texindex);
+      break;
   }
   }
   return text.str();
   return text.str();
 }
 }
@@ -1027,7 +1206,7 @@ combine_mode_as_string(CPT(TextureStage) stage, TextureStage::CombineMode c_mode
 //  Description: This 'synthesizes' a combine source into a string.
 //  Description: This 'synthesizes' a combine source into a string.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 const string ShaderGenerator::
 const string ShaderGenerator::
-combine_source_as_string(CPT(TextureStage) stage, short num, bool single_value, short texindex, const RenderState *rs) {
+combine_source_as_string(CPT(TextureStage) stage, short num, bool single_value, short texindex) {
   TextureStage::CombineSource c_src = TextureStage::CS_undefined;
   TextureStage::CombineSource c_src = TextureStage::CS_undefined;
   TextureStage::CombineOperand c_op = TextureStage::CO_undefined;
   TextureStage::CombineOperand c_op = TextureStage::CO_undefined;
   switch (num) {
   switch (num) {
@@ -1063,11 +1242,9 @@ combine_source_as_string(CPT(TextureStage) stage, short num, bool single_value,
     case TextureStage::CS_previous:
     case TextureStage::CS_previous:
       csource << "result";
       csource << "result";
       break;
       break;
-    case TextureStage::CS_constant_color_scale: {
-      const ColorScaleAttrib *color_scale = DCAST(ColorScaleAttrib, rs->get_attrib_def(ColorScaleAttrib::get_class_slot()));
-      LVecBase4f s = color_scale->get_scale();
-      csource << "float4(" << s[0] << ", " << s[1] << ", " << s[2] << ", " << s[3] << ")";
-      break; }
+    case TextureStage::CS_constant_color_scale:
+      csource << "attr_colorscale";
+      break;
     case TextureStage::CS_last_saved_result:
     case TextureStage::CS_last_saved_result:
       csource << "last_saved_result";
       csource << "last_saved_result";
       break;
       break;
@@ -1088,3 +1265,4 @@ combine_source_as_string(CPT(TextureStage) stage, short num, bool single_value,
   }
   }
   return csource.str();
   return csource.str();
 }
 }
+

+ 33 - 22
panda/src/pgraphnodes/shaderGenerator.h

@@ -16,6 +16,8 @@
 #define SHADERGENERATOR_H
 #define SHADERGENERATOR_H
 
 
 #include "pandabase.h"
 #include "pandabase.h"
+#include "graphicsStateGuardian.h"
+#include "graphicsWindow.h"
 #include "shaderGeneratorBase.h"
 #include "shaderGeneratorBase.h"
 #include "nodePath.h"
 #include "nodePath.h"
 
 
@@ -31,22 +33,23 @@ class ShaderAttrib;
 // Description : The ShaderGenerator is a device that effectively
 // Description : The ShaderGenerator is a device that effectively
 //               replaces the classic fixed function pipeline with
 //               replaces the classic fixed function pipeline with
 //               a 'next-gen' fixed function pipeline.  The next-gen
 //               a 'next-gen' fixed function pipeline.  The next-gen
-//               fixed function pipeline supports features like 
+//               fixed function pipeline supports features like
 //               normal mapping, gloss mapping, cartoon lighting,
 //               normal mapping, gloss mapping, cartoon lighting,
 //               and so forth.  It works by automatically generating
 //               and so forth.  It works by automatically generating
 //               a shader from a given RenderState.
 //               a shader from a given RenderState.
 //
 //
-//               Currently, there is a single default ShaderGenerator
-//               object.  It is our intent that in time, people will
-//               write classes that derive from ShaderGenerator but
-//               which yield slightly different results.
+//               Currently, there is one ShaderGenerator object per
+//               GraphicsStateGuardian.  It is our intent that in
+//               time, people will write classes that derive from
+//               ShaderGenerator but which yield slightly different
+//               results.
 //
 //
-//               The ShaderGenerator owes its existence to the 
+//               The ShaderGenerator owes its existence to the
 //               'Bamboo Team' at Carnegie Mellon's Entertainment
 //               'Bamboo Team' at Carnegie Mellon's Entertainment
 //               Technology Center.  This is a group of students
 //               Technology Center.  This is a group of students
 //               who, as a semester project, decided that next-gen
 //               who, as a semester project, decided that next-gen
 //               graphics should be accessible to everyone, even if
 //               graphics should be accessible to everyone, even if
-//               they don't know shader programming.  The group 
+//               they don't know shader programming.  The group
 //               consisted of:
 //               consisted of:
 //
 //
 //               Aaron Lo, Programmer
 //               Aaron Lo, Programmer
@@ -59,18 +62,19 @@ class ShaderAttrib;
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
-class EXPCL_PANDA_PGRAPHNODES ShaderGenerator : public ShaderGeneratorBase {
+class EXPCL_PANDA_PGRAPHNODES ShaderGenerator : public TypedObject {
 PUBLISHED:
 PUBLISHED:
-  ShaderGenerator();
+  ShaderGenerator(PT(GraphicsStateGuardian) gsg, PT(GraphicsOutput) host);
   virtual ~ShaderGenerator();
   virtual ~ShaderGenerator();
   virtual CPT(RenderAttrib) synthesize_shader(const RenderState *rs);
   virtual CPT(RenderAttrib) synthesize_shader(const RenderState *rs);
-  
+
 protected:
 protected:
   CPT(RenderAttrib) create_shader_attrib(const string &txt);
   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,
   static const string combine_mode_as_string(CPT(TextureStage) stage,
-                TextureStage::CombineMode c_mode, bool single_value, short texindex, const RenderState *rs);
+               TextureStage::CombineMode c_mode, bool single_value, short texindex);
   static const string combine_source_as_string(CPT(TextureStage) stage,
   static const string combine_source_as_string(CPT(TextureStage) stage,
-                short num, bool single_value, short texindex, const RenderState *rs);
+                                      short num, bool single_value, short texindex);
 
 
   // Shader register allocation:
   // Shader register allocation:
 
 
@@ -87,7 +91,7 @@ protected:
   CPT(RenderState) _state;
   CPT(RenderState) _state;
   Material *_material;
   Material *_material;
   int _num_textures;
   int _num_textures;
-  
+
   pvector <AmbientLight *>     _alights;
   pvector <AmbientLight *>     _alights;
   pvector <DirectionalLight *> _dlights;
   pvector <DirectionalLight *> _dlights;
   pvector <PointLight *>       _plights;
   pvector <PointLight *>       _plights;
@@ -96,19 +100,20 @@ protected:
   pvector <NodePath>           _dlights_np;
   pvector <NodePath>           _dlights_np;
   pvector <NodePath>           _plights_np;
   pvector <NodePath>           _plights_np;
   pvector <NodePath>           _slights_np;
   pvector <NodePath>           _slights_np;
-  
+
   bool _vertex_colors;
   bool _vertex_colors;
   bool _flat_colors;
   bool _flat_colors;
-  
+
   bool _lighting;
   bool _lighting;
+  bool _shadows;
 
 
   bool _have_ambient;
   bool _have_ambient;
   bool _have_diffuse;
   bool _have_diffuse;
   bool _have_emission;
   bool _have_emission;
   bool _have_specular;
   bool _have_specular;
-  
+
   bool _separate_ambient_diffuse;
   bool _separate_ambient_diffuse;
-  
+
   int _map_index_normal;
   int _map_index_normal;
   int _map_index_height;
   int _map_index_height;
   int _map_index_glow;
   int _map_index_glow;
@@ -124,21 +129,27 @@ protected:
   bool _calc_primary_alpha;
   bool _calc_primary_alpha;
   bool _subsume_alpha_test;
   bool _subsume_alpha_test;
   bool _disable_alpha_write;
   bool _disable_alpha_write;
+
   int _num_clip_planes;
   int _num_clip_planes;
-  
+  bool _use_shadow_filter;
+
   bool _need_material_props;
   bool _need_material_props;
-  
+
   void analyze_renderstate(const RenderState *rs);
   void analyze_renderstate(const RenderState *rs);
   void clear_analysis();
   void clear_analysis();
-  
+
+  PT(GraphicsStateGuardian) _gsg;
+  PT(GraphicsOutput) _host;
+  pmap<WCPT(RenderState), CPT(ShaderAttrib)> _generated_shaders;
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;
   }
   }
   static void init_type() {
   static void init_type() {
-    ShaderGeneratorBase::init_type();
+    TypedObject::init_type();
     register_type(_type_handle, "ShaderGenerator",
     register_type(_type_handle, "ShaderGenerator",
-                  ShaderGeneratorBase::get_class_type());
+                  TypedObject::get_class_type());
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();