Browse Source

Much progress implementing shader generator

Josh Yelon 18 năm trước cách đây
mục cha
commit
1d44682463

+ 1 - 0
panda/src/pgraph/renderState.I

@@ -651,3 +651,4 @@ CompositionCycleDescEntry(const RenderState *obj,
   _inverted(inverted)
   _inverted(inverted)
 {
 {
 }
 }
+

+ 3 - 1
panda/src/pgraph/renderState.cxx

@@ -39,6 +39,7 @@
 #include "mutexHolder.h"
 #include "mutexHolder.h"
 #include "thread.h"
 #include "thread.h"
 #include "attribSlots.h"
 #include "attribSlots.h"
+#include "shaderGenerator.h"
   
   
 ReMutex *RenderState::_states_lock = NULL;
 ReMutex *RenderState::_states_lock = NULL;
 RenderState::States *RenderState::_states = NULL;
 RenderState::States *RenderState::_states = NULL;
@@ -1142,8 +1143,9 @@ get_generated_shader() const {
   if (_generated_shader != (RenderAttrib*)NULL) {
   if (_generated_shader != (RenderAttrib*)NULL) {
     return DCAST(ShaderAttrib, _generated_shader);
     return DCAST(ShaderAttrib, _generated_shader);
   }
   }
+  ShaderGenerator *gen = ShaderGenerator::get_default();
   ((RenderState*)this)->_generated_shader =
   ((RenderState*)this)->_generated_shader =
-    ShaderGenerator::synthesize_shader(this);
+    gen->synthesize_shader(this);
   return DCAST(ShaderAttrib, _generated_shader);
   return DCAST(ShaderAttrib, _generated_shader);
 }
 }
 
 

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

@@ -36,7 +36,6 @@
 #include "deletedChain.h"
 #include "deletedChain.h"
 #include "simpleHashMap.h"
 #include "simpleHashMap.h"
 #include "cacheStats.h"
 #include "cacheStats.h"
-#include "shaderGenerator.h"
 
 
 class GraphicsStateGuardianBase;
 class GraphicsStateGuardianBase;
 class FogAttrib;
 class FogAttrib;

+ 0 - 17
panda/src/pgraph/shaderGenerator.I

@@ -16,20 +16,3 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: ShaderGenerator::Constructor
-//       Access: Private
-//  Description: This class is never constructed.
-////////////////////////////////////////////////////////////////////
-ShaderGenerator::
-ShaderGenerator() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ShaderGenerator::Destructor
-//       Access: Private
-//  Description: This class is never constructed.
-////////////////////////////////////////////////////////////////////
-ShaderGenerator::
-~ShaderGenerator() {
-}

+ 549 - 28
panda/src/pgraph/shaderGenerator.cxx

@@ -15,50 +15,407 @@
 // [email protected] .
 // [email protected] .
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
+//
+// Lighting calculations. These can be done either in tangent space
+// or model space.  Doing them in tangent space is necessary for
+// normal mapping.  However, it is only possible if tangents have
+// been computed.  If not, then model space is the only option.
+// The parameters needed for lighting are:
+//
+// Model Space:
+//
+//   vshader:
+//       model-space normal - varying
+//       model-space vertex position - varying
+//   fshader:
+//       model-space normal - varying
+//       model-space vertex position - varying
+//       model-space light position (spot or point) - uniform
+//       model-space light vector (directional) - uniform
+//       model-space eye position - uniform
+//
+// Tangent Space:
+//
+//   vshader:
+//       model-space normal - varying
+//       model-space tangent - varying
+//       model-space binormal - varying
+//       model-space light position (spot or point) - uniform
+//       model-space light vector (directional) - uniform
+//       model-space eye position - uniform
+//   fshader:
+//       model-space vertex position - varying
+//       tangent-space light vector, one per light - varying
+//       tangent-space eye vector - varying
+//       model-space light position (spot) - uniform
+//
+/////////////////////////////////////////////////////////////////////
+
 
 
 #include "renderState.h"
 #include "renderState.h"
 #include "shaderAttrib.h"
 #include "shaderAttrib.h"
 #include "shaderGenerator.h"
 #include "shaderGenerator.h"
+#include "ambientLight.h"
+#include "directionalLight.h"
+#include "pointLight.h"
+#include "spotLight.h"
+
+TypeHandle ShaderGenerator::_type_handle;
+PT(ShaderGenerator) ShaderGenerator::_default_generator;
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderGenerator::Constructor
+//       Access: Published
+//  Description: Create a ShaderGenerator.  This has no state,
+//               except possibly to cache certain results.
+////////////////////////////////////////////////////////////////////
+ShaderGenerator::
+ShaderGenerator() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderGenerator::Destructor
+//       Access: Published, Virtual
+//  Description: Destroy a ShaderGenerator.
+////////////////////////////////////////////////////////////////////
+ShaderGenerator::
+~ShaderGenerator() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderGenerator::reset_register_allocator
+//       Access: Protected
+//  Description: Clears the register allocator.  Initially, the pool
+//               of available registers is empty.  You have to add
+//               some if you want there to be any.
+////////////////////////////////////////////////////////////////////
+void ShaderGenerator::
+reset_register_allocator() {
+  _vtregs_used = 0;
+  _vcregs_used = 0;
+  _ftregs_used = 0;
+  _fcregs_used = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderGenerator::alloc_vreg
+//       Access: Protected
+//  Description: Allocate a vreg.  
+////////////////////////////////////////////////////////////////////
+INLINE char *ShaderGenerator::
+alloc_vreg() {
+  switch (_vtregs_used) {
+  case 0: _vtregs_used += 1; return "TEXCOORD0";
+  case 1: _vtregs_used += 1; return "TEXCOORD1";
+  case 2: _vtregs_used += 1; return "TEXCOORD2";
+  case 3: _vtregs_used += 1; return "TEXCOORD3";
+  case 4: _vtregs_used += 1; return "TEXCOORD4";
+  case 5: _vtregs_used += 1; return "TEXCOORD5";
+  case 6: _vtregs_used += 1; return "TEXCOORD6";
+  case 7: _vtregs_used += 1; return "TEXCOORD7";
+  }
+  switch (_vcregs_used) {
+  case 0: _vcregs_used += 1; return "COLOR0";
+  case 1: _vcregs_used += 1; return "COLOR1";
+  }
+  return "UNKNOWN";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderGenerator::alloc_freg
+//       Access: Protected
+//  Description: Allocate a freg.
+////////////////////////////////////////////////////////////////////
+INLINE char *ShaderGenerator::
+alloc_freg() {
+  switch (_ftregs_used) {
+  case 0: _ftregs_used += 1; return "TEXCOORD0";
+  case 1: _ftregs_used += 1; return "TEXCOORD1";
+  case 2: _ftregs_used += 1; return "TEXCOORD2";
+  case 3: _ftregs_used += 1; return "TEXCOORD3";
+  case 4: _ftregs_used += 1; return "TEXCOORD4";
+  case 5: _ftregs_used += 1; return "TEXCOORD5";
+  case 6: _ftregs_used += 1; return "TEXCOORD6";
+  case 7: _ftregs_used += 1; return "TEXCOORD7";
+  }
+  switch (_fcregs_used) {
+  case 0: _fcregs_used += 1; return "COLOR0";
+  case 1: _fcregs_used += 1; return "COLOR1";
+  }
+  return "UNKNOWN";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderGenerator::get_default
+//       Access: Published, Static
+//  Description: Get a pointer to the default shader generator.
+////////////////////////////////////////////////////////////////////
+ShaderGenerator *ShaderGenerator::
+get_default() {
+  if (_default_generator == (ShaderGenerator *)NULL) {
+    _default_generator = new ShaderGenerator;
+  }
+  return _default_generator;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderGenerator::set_default
+//       Access: Published, Static
+//  Description: Set the default shader generator.
+////////////////////////////////////////////////////////////////////
+void ShaderGenerator::
+set_default(ShaderGenerator *generator) {
+  _default_generator = generator;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderGenerator::analyze_renderstate
+//       Access: Protected
+//  Description: Analyzes the RenderState prior to shader generation.
+//               The results of the analysis are stored in instance
+//               variables of the Shader Generator.
+////////////////////////////////////////////////////////////////////
+void ShaderGenerator::
+analyze_renderstate(const RenderState *rs) {
+  clear_analysis();
+
+  rs->store_into_slots(&_attribs);
+
+  // Count number of textures.
+  _num_textures = 0;
+  if (_attribs._texture) {
+    _num_textures = _attribs._texture->get_num_on_stages();
+  }
+
+  // Determine whether or not vertex colors or flat colors are present.
+  if (_attribs._color != 0) {
+    if (_attribs._color->get_color_type() == ColorAttrib::T_vertex) {
+      _vertex_colors = true;
+    } else if (_attribs._color->get_color_type() == ColorAttrib::T_flat) {
+      _flat_colors = true;
+    }
+  }
+
+  // Break out the lights by type.
+
+  const LightAttrib *la = _attribs._light;
+  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);
+    }
+    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);
+    }
+  }
+
+  // Determine whether model-space or tangent-space lighting is recommended.
+
+  if (_attribs._light->get_num_on_lights() > 0) {
+    _ms_lighting = true;
+  }
+
+  // Find the material.
+
+  if (!_attribs._material->is_off()) {
+    _material = _attribs._material->get_material();
+  } else {
+    _material = Material::get_default();
+  }
+  
+  // Decide which material modes need to be calculated.
+  
+  if (_alights.size() > 0) {
+    if (_material->has_ambient()) {
+      Colorf 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 (_dlights.size() + _plights.size() + _slights.size()) {
+    if (_material->has_diffuse()) {
+      Colorf d = _material->get_diffuse();
+      if ((d[0]!=0.0)||(d[1]!=0.0)||(d[2]!=0.0)) {
+        _have_diffuse = true;
+      }
+    } else {
+      _have_diffuse = true;
+    }
+  }
+  
+  if (_material->has_emission()) {
+    Colorf e = _material->get_emission();
+    if ((e[0]!=0.0)||(e[1]!=0.0)||(e[2]!=0.0)) {
+      _have_emission = true;
+    }
+  }
+  
+  if (_dlights.size() + _plights.size() + _slights.size()) {
+    if (_material->has_specular()) {
+      Colorf s = _material->get_specular();
+      if ((s[0]!=0.0)||(s[1]!=0.0)||(s[2]!=0.0)) {
+        _have_specular = true;
+      }
+    }
+  }
+  
+  // Does the shader need material properties as input?
+  
+  _need_material_props = 
+    (_have_ambient  && (_material->has_ambient()))||
+    (_have_diffuse  && (_material->has_diffuse()))||
+    (_have_emission && (_material->has_emission()))||
+    (_have_specular && (_material->has_specular()));
+}
+
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderGenerator::clear_analysis
+//       Access: Protected
+//  Description: Called after analyze_renderstate to discard all
+//               the results of the analysis.  This is generally done
+//               after shader generation is complete.
+////////////////////////////////////////////////////////////////////
+void ShaderGenerator::
+clear_analysis() {
+  _vertex_colors = false;
+  _flat_colors = false;
+  _ms_lighting = false;
+  _ts_lighting = false;
+  _have_ambient = false;
+  _have_diffuse = false;
+  _have_emission = false;
+  _have_specular = false;
+  _attribs.clear_to_defaults();
+  _material = (Material*)NULL;
+  _alights.clear();
+  _dlights.clear();
+  _plights.clear();
+  _slights.clear();
+  _alights_np.clear();
+  _dlights_np.clear();
+  _plights_np.clear();
+  _slights_np.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderGenerator::create_shader_attrib
+//       Access: Protected
+//  Description: Creates a ShaderAttrib given a generated shader's
+//               body.  Also inserts the lights into the shader
+//               attrib.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) ShaderGenerator::
+create_shader_attrib(const string &txt) {
+  PT(Shader) shader = Shader::make(txt);
+  CPT(RenderAttrib) shattr = ShaderAttrib::make();
+  shattr=DCAST(ShaderAttrib, shattr)->set_shader(shader);
+  if (_ms_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]);
+    }
+    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]);
+    }
+  }
+  return shattr;
+}
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ShaderGenerator::synthesize_shader
 //     Function: ShaderGenerator::synthesize_shader
-//       Access: Public, Static
+//       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.
 //
 //
 //               Currently supports:
 //               Currently supports:
-//               - textures
-//               - materials
+//               - 2D textures
 //               - lights
 //               - lights
+//               - vertex colors
+//               - flat colors
+//               - materials
 //
 //
 //               Not yet supported:
 //               Not yet supported:
-//               - vertex colors
+//               - 3D textures, cube textures
+//               - color scale attrib
 //               - texgen
 //               - texgen
 //               - texmatrix
 //               - texmatrix
-//               - separate normal and gloss
+//               - normal and gloss
 //               - lots of other things
 //               - lots of other things
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) ShaderGenerator::
 CPT(RenderAttrib) ShaderGenerator::
 synthesize_shader(const RenderState *rs) {
 synthesize_shader(const RenderState *rs) {
-  AttribSlots attribs;
-  rs->store_into_slots(&attribs);
-  
-  int num_textures = 0;
-  if (attribs._texture) {
-    num_textures = attribs._texture->get_num_on_stages();
+  analyze_renderstate(rs);
+  reset_register_allocator();
+
+  // These variables will hold the results of register allocation.
+
+  char *pos_freg = 0;
+  char *normal_vreg = 0;
+  char *tangent_vreg = 0;
+  char *binormal_vreg = 0;
+  char *normal_freg = 0;
+  char *eyevec_freg = 0;
+  pvector<char *> texcoord_vreg;
+  pvector<char *> texcoord_freg;
+  pvector<char *> tslightvec_freg;
+
+  if (_vertex_colors) {
+    _vcregs_used = 1;
+    _fcregs_used = 1;
   }
   }
   
   
-  ostringstream text;
-  CPT(RenderAttrib) rattrib = ShaderAttrib::make();
+  // Generate the shader's text.
 
 
+  ostringstream text;
+  
   text << "//Cg\n";
   text << "//Cg\n";
 
 
   text << "void vshader(\n";
   text << "void vshader(\n";
-  for (int i=0; i<num_textures; i++) {
-    text << "\t float2 vtx_texcoord" << i << " : TEXCOORD" << i << ",\n";
-    text << "\t out float2 l_texcoord" << i << " : TEXCOORD" << i << ",\n";
+  for (int i=0; i<_num_textures; i++) {
+    texcoord_vreg.push_back(alloc_vreg());
+    texcoord_freg.push_back(alloc_freg());
+    text << "\t in float4 vtx_texcoord" << i << " : " << texcoord_vreg[i] << ",\n";
+    text << "\t out float4 l_texcoord" << i << " : " << texcoord_freg[i] << ",\n";
+  }
+  if (_vertex_colors) {
+    text << "\t in float4 vtx_color : COLOR,\n";
+    text << "\t out float4 l_color : COLOR,\n";
   }
   }
+  if (_ms_lighting) {
+    pos_freg = alloc_freg();
+    normal_vreg = alloc_vreg();
+    normal_freg = alloc_freg();
+    text << "\t in float4 vtx_normal : " << normal_vreg << ",\n";
+    text << "\t out float4 l_normal : " << normal_freg << ",\n";
+    text << "\t out float4 l_pos : " << pos_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";
@@ -66,31 +423,195 @@ synthesize_shader(const RenderState *rs) {
   
   
   text << "\t l_position = mul(mat_modelproj, vtx_position);\n";
   text << "\t l_position = mul(mat_modelproj, vtx_position);\n";
 
 
-  for (int i=0; i<num_textures; i++) {
+  for (int i=0; i<_num_textures; i++) {
     text << "\t l_texcoord" << i << " = vtx_texcoord" << i << ";\n";
     text << "\t l_texcoord" << i << " = vtx_texcoord" << i << ";\n";
   }
   }
-  
+  if (_vertex_colors) {
+    text << "\t l_color = vtx_color;\n";
+  }
+  if (_ms_lighting) {
+    text << "\t l_normal = vtx_normal;\n";
+    text << "\t l_pos = vtx_position;\n";
+  }
   text << "}\n\n";
   text << "}\n\n";
 
 
   text << "void fshader(\n";
   text << "void fshader(\n";
   
   
-  for (int i=0; i<num_textures; i++) {
-    text << "\t in float2 l_texcoord" << i << " : TEXCOORD" << i << ",\n";
+  for (int i=0; i<_num_textures; i++) {
+    text << "\t in float4 l_texcoord" << i << " : " << texcoord_freg[i] << ",\n";
     text << "\t uniform sampler2D tex_" << i << ",\n";
     text << "\t uniform sampler2D tex_" << i << ",\n";
   }
   }
+  if (_vertex_colors) {
+    text << "\t in float4 l_color : COLOR,\n";
+  } else {
+    text << "\t uniform float4 attr_color,\n";
+  }
+  if (_ms_lighting) {
+    text << "\t in float3 l_normal : " << normal_freg << ",\n";
+    text << "\t in float4 l_pos : " << pos_freg << ",\n";
+    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_model,\n";
+    }
+    for (int i=0; i<(int)_plights.size(); i++) {
+      text << "\t uniform float4x4 plight_plight" << i << "_rel_model,\n";
+    }
+    for (int i=0; i<(int)_slights.size(); i++) {
+      text << "\t uniform float4x4 slight_slight" << i << "_rel_model,\n";
+      text << "\t uniform float4   satten_slight" << i << ",\n";
+    }
+    if (_need_material_props) {
+      text << "\t uniform float4x4 attr_material,\n";
+    }
+    if (_have_specular) {
+      if (_material->get_local()) {
+        text << "\t uniform float4 mspos_view,\n";
+      } else {
+        text << "\t uniform float4 row1_view_to_model,\n";
+      }
+    }
+  }
   text << "\t out float4 o_color : COLOR\n";
   text << "\t out float4 o_color : COLOR\n";
   text << ") {\n";
   text << ") {\n";
   
   
-  text << "\t o_color = float4(1,1,1,1);\n";
-  for (int i=0; i<num_textures; i++) {
-    text << "\t o_color *= tex2D(tex_" << i << ", l_texcoord" << i << ");\n";
+  if (_ms_lighting) {
+    if (_have_ambient) {
+      text << "\t float4 tot_ambient = float4(0,0,0,0);\n";
+    }
+    if (_have_diffuse) {
+      text << "\t float4 tot_diffuse = float4(0,0,0,0);\n";
+    }
+    if (_have_specular) {
+      text << "\t float4 tot_specular = float4(0,0,0,0);\n";
+    }
+    text << "\t l_normal = normalize(l_normal);\n";
+    text << "\t float ldist,lattenv,langle;\n";
+    text << "\t float4 lcolor,lspec,lvec,lpoint,latten,ldir,leye,lhalf;\n";
+    for (int i=0; i<(int)_alights.size(); i++) {
+      text << "\t // Ambient Light " << i << "\n";
+      text << "\t lcolor = alight_alight" << i << ";\n";
+      text << "\t tot_ambient += lcolor;\n";
+    }
+    for (int i=0; i<(int)_dlights.size(); i++) {
+      text << "\t // Directional Light " << i << "\n";
+      text << "\t lcolor = dlight_dlight" << i << "_rel_model[0];\n";
+      text << "\t lspec  = dlight_dlight" << i << "_rel_model[1];\n";
+      text << "\t lvec   = dlight_dlight" << i << "_rel_model[2];\n";
+      text << "\t lcolor *= saturate(dot(l_normal, lvec.xyz));\n";
+      text << "\t tot_diffuse += lcolor;\n";
+      if (_have_specular) {
+        if (_material->get_local()) {
+          text << "\t lhalf  = normalize(normalize(mspos_view - l_pos) + lvec);\n";
+        } else {
+          text << "\t lhalf = dlight_dlight" << i << "_rel_model[3];\n";
+        }
+        text << "\t lspec *= pow(saturate(dot(l_normal, lhalf.xyz)), attr_material[3].w);\n";
+        text << "\t tot_specular += lspec;\n";
+      }
+    }
+    for (int i=0; i<(int)_plights.size(); i++) {
+      text << "\t // Point Light " << i << "\n";
+      text << "\t lcolor = plight_plight" << i << "_rel_model[0];\n";
+      text << "\t lspec  = plight_plight" << i << "_rel_model[1];\n";
+      text << "\t lpoint = plight_plight" << i << "_rel_model[2];\n";
+      text << "\t latten = plight_plight" << i << "_rel_model[3];\n";
+      text << "\t lvec   = lpoint - l_pos;\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_normal, lvec.xyz));\n";
+      text << "\t tot_diffuse += lcolor;\n";
+      if (_have_specular) {
+        if (_material->get_local()) {
+          text << "\t lhalf  = normalize(normalize(mspos_view - l_pos) + lvec);\n";
+        } else {
+          text << "\t lhalf = normalize(lvec - row1_view_to_model);\n";
+        }
+        text << "\t lspec *= lattenv;\n";
+        text << "\t lspec *= pow(saturate(dot(l_normal, lhalf.xyz)), attr_material[3].w);\n";
+        text << "\t tot_specular += lspec;\n";
+      }
+    }
+    for (int i=0; i<(int)_slights.size(); i++) {
+      text << "\t // Spot Light " << i << "\n";
+      text << "\t lcolor = slight_slight" << i << "_rel_model[0];\n";
+      text << "\t lspec  = slight_slight" << i << "_rel_model[1];\n";
+      text << "\t lpoint = slight_slight" << i << "_rel_model[2];\n";
+      text << "\t ldir   = slight_slight" << i << "_rel_model[3];\n";
+      text << "\t latten = satten_slight" << i << ";\n";
+      text << "\t lvec   = lpoint - l_pos;\n";
+      text << "\t ldist  = length(lvec);\n";
+      text << "\t lvec /= ldist;\n";
+      text << "\t langle = saturate(dot(ldir.xyz, lvec.xyz));\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_normal, lvec.xyz));\n";
+      text << "\t tot_diffuse += lcolor;\n";
+      if (_have_specular) {
+        if (_material->get_local()) {
+          text << "\t lhalf  = normalize(normalize(mspos_view - l_pos) + lvec);\n";
+        } else {
+          text << "\t lhalf = normalize(lvec - row1_view_to_model);\n";
+        }
+        text << "\t lspec *= lattenv;\n";
+        text << "\t lspec *= pow(saturate(dot(l_normal, lhalf.xyz)), attr_material[3].w);\n";
+        text << "\t tot_specular += lspec;\n";
+      }
+    }
+
+    if (_have_emission) {
+      text << "\t o_color = attr_material[2];\n";
+    } else {
+      text << "\t o_color = float4(0,0,0,1);\n";
+    }
+    if (_have_ambient) {
+      if (_material->has_ambient()) {
+        text << "\t o_color += tot_ambient * attr_material[0];\n";
+      } else if (_vertex_colors) {
+        text << "\t o_color += tot_ambient * l_color;\n";
+      } else if (_flat_colors) {
+        text << "\t o_color += tot_ambient * attr_color;\n";
+      } else {
+        text << "\t o_color += tot_ambient;\n";
+      }
+    }
+    if (_have_diffuse) {
+      if (_material->has_diffuse()) {
+        text << "\t o_color += tot_diffuse * attr_material[1];\n";
+      } else if (_vertex_colors) {
+        text << "\t o_color += tot_diffuse * l_color;\n";
+      } else if (_flat_colors) {
+        text << "\t o_color += tot_diffuse * attr_color;\n";
+      } else {
+        text << "\t o_color += tot_diffuse;\n";
+      }
+    }
+  } else {
+    if (_vertex_colors) {
+      text << "\t o_color = l_color;\n";
+    } else if (_flat_colors) {
+      text << "\t o_color = attr_color;\n";
+    } else {
+      text << "\t o_color = float4(1,1,1,1);\n";
+    }
+  }
+  for (int i=0; i<_num_textures; i++) {
+    text << "\t o_color *= tex2D(tex_" << i << ", float2(l_texcoord" << i << "));\n";
+  }
+  if (_ms_lighting) {
+    if (_have_specular) {
+      text << "\t o_color += tot_specular;\n";
+    }
   }
   }
-  
   text << "}\n";
   text << "}\n";
-
+  
   // Insert the shader into the shader attrib.
   // Insert the shader into the shader attrib.
-  PT(Shader) shader = Shader::make(text.str());
-  rattrib = DCAST(ShaderAttrib, rattrib)->set_shader(shader);
-  return rattrib;
+  CPT(RenderAttrib) shattr = create_shader_attrib(text.str());
+  clear_analysis();
+  reset_register_allocator();
+  return shattr;
 }
 }
 
 

+ 81 - 4
panda/src/pgraph/shaderGenerator.h

@@ -20,6 +20,14 @@
 #define SHADERGENERATOR_H
 #define SHADERGENERATOR_H
 
 
 #include "pandabase.h"
 #include "pandabase.h"
+#include "typedWritableReferenceCount.h"
+#include "nodePath.h"
+class AmbientLight;
+class DirectionalLight;
+class PointLight;
+class Spotlight;
+class LightAttrib;
+class ShaderAttrib;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : ShaderGenerator
 //       Class : ShaderGenerator
@@ -31,6 +39,11 @@
 //               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.
+//
 //               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
@@ -49,13 +62,77 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
-class EXPCL_PANDA_PGRAPH ShaderGenerator {
+class EXPCL_PANDA_PGRAPH ShaderGenerator : public TypedWritableReferenceCount {
 private:
 private:
-  INLINE ShaderGenerator();
-  INLINE ~ShaderGenerator();
+  static PT(ShaderGenerator) _default_generator;
+
+PUBLISHED:
+  ShaderGenerator();
+  virtual ~ShaderGenerator();
+  static ShaderGenerator *get_default();
+  static void set_default(ShaderGenerator *generator);
+  virtual CPT(RenderAttrib) synthesize_shader(const RenderState *rs);
+  
+protected:
+  CPT(RenderAttrib) create_shader_attrib(const string &txt);
+
+  // Shader register allocation:
+
+  int _vcregs_used;
+  int _fcregs_used;
+  int _vtregs_used;
+  int _ftregs_used;
+  void reset_register_allocator();
+  INLINE char *alloc_vreg();
+  INLINE char *alloc_freg();
+
+  // RenderState analysis information.  Created by analyze_renderstate:
+
+  AttribSlots _attribs;
+  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;
+  
+  bool _vertex_colors;
+  bool _flat_colors;
+  
+  bool _ms_lighting;
+  bool _ts_lighting;
+
+  bool _have_ambient;
+  bool _have_diffuse;
+  bool _have_emission;
+  bool _have_specular;
+
+  bool _need_material_props;
+  
+  void analyze_renderstate(const RenderState *rs);
+  void clear_analysis();
   
   
 public:
 public:
-  static CPT(RenderAttrib) synthesize_shader(const RenderState *rs);
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedReferenceCount::init_type();
+    register_type(_type_handle, "ShaderGenerator",
+                  TypedReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+ private:
+  static TypeHandle _type_handle;
 };
 };
 
 
 #include "shaderGenerator.I"
 #include "shaderGenerator.I"