Browse Source

Added several new shader-parameter keywords, esp for lights and materials

Josh Yelon 18 years ago
parent
commit
aee0c904ca
3 changed files with 433 additions and 81 deletions
  1. 132 0
      panda/src/display/graphicsStateGuardian.cxx
  2. 273 73
      panda/src/gobj/shader.cxx
  3. 28 8
      panda/src/gobj/shader.h

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

@@ -40,6 +40,10 @@
 #include "graphicsOutput.h"
 #include "texturePool.h"
 #include "geomMunger.h"
+#include "ambientLight.h"
+#include "directionalLight.h"
+#include "pointLight.h"
+#include "spotLight.h"
 
 #include <algorithm>
 #include <limits.h>
@@ -825,6 +829,7 @@ fetch_specified_value(Shader::ShaderMatSpec &spec, bool altered) {
   const LMatrix4f *val2;
   static LMatrix4f t1;
   static LMatrix4f t2;
+  LVecBase3f v;
 
   switch(spec._func) {
   case Shader::SMF_compose:
@@ -846,6 +851,38 @@ fetch_specified_value(Shader::ShaderMatSpec &spec, bool altered) {
     val1 = fetch_specified_part(spec._part[0], spec._arg[0], t1);
     acc.multiply(*val1, spec._cache);
     return &acc;
+  case Shader::SMF_transform_dlight:
+    if (altered) {
+      spec._cache = *fetch_specified_part(spec._part[0], spec._arg[0], t1);
+    }
+    val2 = fetch_specified_part(spec._part[1], spec._arg[1], t2);
+    acc = spec._cache;
+    v = val2->xform_vec(spec._cache.get_row3(2));
+    v.normalize();
+    acc.set_row(2, v);
+    v = val2->xform_vec(spec._cache.get_row3(3));
+    v.normalize();
+    acc.set_row(3, v);
+    return &acc;
+  case Shader::SMF_transform_plight:
+    if (altered) {
+      spec._cache = *fetch_specified_part(spec._part[0], spec._arg[0], t1);
+    }
+    val2 = fetch_specified_part(spec._part[1], spec._arg[1], t2);
+    acc = spec._cache;
+    acc.set_row(2, val2->xform_point(spec._cache.get_row3(2)));
+    return &acc;
+  case Shader::SMF_transform_slight:
+    if (altered) {
+      spec._cache = *fetch_specified_part(spec._part[0], spec._arg[0], t1);
+    }
+    val2 = fetch_specified_part(spec._part[1], spec._arg[1], t2);
+    acc = spec._cache;
+    acc.set_row(2, val2->xform_point(spec._cache.get_row3(2)));
+    v = val2->xform_vec(spec._cache.get_row3(3));
+    v.normalize();
+    acc.set_row(3, v);
+    return &acc;
   case Shader::SMF_first:
     return fetch_specified_part(spec._part[0], spec._arg[0], t1);
   default:
@@ -885,6 +922,101 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LMatrix4f
                                  0.0);
     return &t;
   }
+  case Shader::SMO_attr_material: {
+    // Material matrix contains AMBIENT, DIFFUSE, EMISSION, SPECULAR+SHININESS
+    if (_target._material->is_off()) {
+      t = LMatrix4f(1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0);
+      return &t;
+    }
+    Material *m = _target._material->get_material();
+    LVecBase4f const &amb = m->get_ambient();
+    LVecBase4f const &dif = m->get_diffuse();
+    LVecBase4f const &emm = m->get_emission();
+    LVecBase4f spc = m->get_specular();
+    spc[3] = m->get_shininess();
+    t = LMatrix4f(amb[0],amb[1],amb[2],amb[3],
+                  dif[0],dif[1],dif[2],dif[3],
+                  emm[0],emm[1],emm[2],emm[3],
+                  spc[0],spc[1],spc[2],spc[3]);
+    return &t;
+  }
+  case Shader::SMO_attr_color: {
+    if (_target._color->get_color_type() != ColorAttrib::T_flat) {
+      return &LMatrix4f::ones_mat();
+    }
+    LVecBase4f c = _target._color->get_color();
+    t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]);
+    return &t;
+  }
+  case Shader::SMO_alight_x: {
+    const NodePath &np = _target._shader->get_shader_input_nodepath(name);
+    nassertr(!np.is_empty(), &LMatrix4f::zeros_mat());
+    AmbientLight *lt;
+    DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat());
+    Colorf const &c = lt->get_color();
+    t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]);
+    return &t;
+  }
+  case Shader::SMO_satten_x: {
+    const NodePath &np = _target._shader->get_shader_input_nodepath(name);
+    nassertr(!np.is_empty(), &LMatrix4f::ones_mat());
+    Spotlight *lt;
+    DCAST_INTO_R(lt, np.node(), &LMatrix4f::ones_mat());
+    LVecBase3f const &a = lt->get_attenuation();
+    float x = lt->get_exponent();
+    t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,a[0],a[1],a[2],x);
+    return &t;
+  }
+  case Shader::SMO_dlight_x: {
+    // The dlight matrix contains COLOR, SPECULAR, DIRECTION, PSEUDOHALFANGLE
+    const NodePath &np = _target._shader->get_shader_input_nodepath(name);
+    nassertr(!np.is_empty(), &LMatrix4f::zeros_mat());
+    DirectionalLight *lt;
+    DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat());
+    Colorf const &c = lt->get_color();
+    Colorf const &s = lt->get_specular_color();
+    t = np.get_net_transform()->get_mat() *
+      get_scene()->get_world_transform()->get_mat();
+    LVecBase3f d = -(t.xform_vec(lt->get_direction()));
+    d.normalize();
+    LVecBase3f h = d + LVecBase3f(0,-1,0);
+    h.normalize();
+    t = LMatrix4f(c[0],c[1],c[2],c[3],s[0],s[1],s[2],c[3],d[0],d[1],d[2],0,h[0],h[1],h[2],0);
+    return &t;
+  }
+  case Shader::SMO_plight_x: {
+    // The plight matrix contains COLOR, SPECULAR, POINT, ATTENUATION
+    const NodePath &np = _target._shader->get_shader_input_nodepath(name);
+    nassertr(!np.is_empty(), &LMatrix4f::ones_mat());
+    PointLight *lt;
+    DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat());
+    Colorf const &c = lt->get_color();
+    Colorf const &s = lt->get_specular_color();
+    t = np.get_net_transform()->get_mat() *
+      get_scene()->get_world_transform()->get_mat();
+    LVecBase3f p = (t.xform_point(lt->get_point()));
+    LVecBase3f a = lt->get_attenuation();
+    t = LMatrix4f(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);
+    return &t;
+  }
+  case Shader::SMO_slight_x: {
+    // The slight matrix contains COLOR, SPECULAR, POINT, DIRECTION
+    const NodePath &np = _target._shader->get_shader_input_nodepath(name);
+    nassertr(!np.is_empty(), &LMatrix4f::zeros_mat());
+    Spotlight *lt;
+    DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat());
+    Lens *lens = lt->get_lens();
+    nassertr(lens != (Lens *)NULL, &LMatrix4f::zeros_mat());
+    Colorf const &c = lt->get_color();
+    Colorf const &s = lt->get_specular_color();
+    float cutoff = cos(deg_2_rad(lens->get_hfov() * 0.5f));
+    t = np.get_net_transform()->get_mat() *
+      get_scene()->get_world_transform()->get_mat();
+    LVecBase3f p = t.xform_point(lens->get_nodal_point());
+    LVecBase3f d = -(t.xform_vec(lens->get_view_vector()));
+    t = LMatrix4f(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,d[0],d[1],d[2],cutoff);
+    return &t;
+  }
   case Shader::SMO_mat_constant_x: {
     const NodePath &np = _target._shader->get_shader_input_nodepath(name);
     nassertr(!np.is_empty(), &LMatrix4f::ident_mat());

+ 273 - 73
panda/src/gobj/shader.cxx

@@ -20,6 +20,8 @@
 #include "shader.h"
 #include "preparedGraphicsObjects.h"
 #include "virtualFileSystem.h"
+#include <iostream>
+#include <fstream>
 
 #ifdef HAVE_CG
 #include "Cg/cg.h"
@@ -31,6 +33,7 @@ TypeHandle Shader::_type_handle;
 Shader::LoadTable Shader::_load_table;
 Shader::MakeTable Shader::_make_table;
 Shader::ShaderCaps Shader::_default_caps;
+int Shader::_shaders_generated;
 ShaderUtilization Shader::_shader_utilization = SUT_UNSPECIFIED;
 
 ////////////////////////////////////////////////////////////////////
@@ -188,29 +191,136 @@ cp_errchk_parameter_sampler(ShaderArgInfo &p)
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: Shader::cp_parse_trans_clause
+//     Function: Shader::cp_parse_eol
 //       Access: Public
-//  Description: Parses a single clause of a "trans" parameter.
+//  Description: Make sure the next thing on the word list is EOL
 ////////////////////////////////////////////////////////////////////
 bool Shader::
-cp_parse_trans_clause(ShaderArgInfo &p, ShaderMatSpec &spec, 
-                      int part, const vector_string &pieces,
-                      int &next, ShaderMatInput ofop, ShaderMatInput op) {
-  if (pieces[next+1]=="of") {
-    if (pieces[next+2]=="") {
-      cp_report_error(p, "'of' should be followed by a name");
-      return false;
+cp_parse_eol(ShaderArgInfo &p, vector_string &words, int &next) {
+  if (words[next] != "") {
+    cp_report_error(p, "Too many words in parameter");
+    return false;
+  }
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::cp_parse_delimiter
+//       Access: Public
+//  Description: Pop a delimiter ('to' or 'rel') from the word list.
+////////////////////////////////////////////////////////////////////
+bool Shader::
+cp_parse_delimiter(ShaderArgInfo &p, vector_string &words, int &next) {
+  if ((words[next] != "to")&&(words[next] != "rel")) {
+    cp_report_error(p, "Keyword 'to' or 'rel' expected");
+    return false;
+  }
+  next += 1;
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::cp_parse_non_delimiter
+//       Access: Public
+//  Description: Pop a non-delimiter word from the word list.
+//               Delimiters are 'to' and 'rel.'
+////////////////////////////////////////////////////////////////////
+string Shader::
+cp_parse_non_delimiter(vector_string &words, int &next) {
+  const string &nword = words[next];
+  if ((nword == "")||(nword == "to")||(nword == "rel")) {
+    return "";
+  }
+  next += 1;
+  return nword;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::cp_parse_coord_sys
+//       Access: Public
+//  Description: Convert a single-word coordinate system name into
+//               a PART/ARG of a ShaderMatSpec.
+////////////////////////////////////////////////////////////////////
+bool Shader::
+cp_parse_coord_sys(ShaderArgInfo &p,
+                   vector_string &pieces, int &next,
+                   ShaderMatSpec &bind, bool fromflag) {
+
+  string word1 = cp_parse_non_delimiter(pieces, next);
+  string word2 = cp_parse_non_delimiter(pieces, next);
+
+  ShaderMatInput from_single;
+  ShaderMatInput from_double;
+  ShaderMatInput to_single;
+  ShaderMatInput to_double;
+
+  if (word1 == "") {
+    cp_report_error(p, "Could not parse coordinate system name");
+    return false;
+  } else if (word1 == "world") {
+    from_single = SMO_world_to_view;
+    from_double = SMO_INVALID;
+    to_single   = SMO_view_to_world;
+    to_double   = SMO_INVALID;
+  } else if (word1 == "model") {
+    from_single = SMO_model_to_view;
+    from_double = SMO_view_x_to_view;
+    to_single   = SMO_view_to_model;
+    to_double   = SMO_view_to_view_x;
+  } else if (word1 == "clip") {
+    from_single = SMO_clip_to_view;
+    from_double = SMO_clip_x_to_view;
+    to_single   = SMO_view_to_clip;
+    to_double   = SMO_view_to_clip_x;
+  } else if (word1 == "view") {
+    from_single = SMO_identity;
+    from_double = SMO_view_x_to_view;
+    to_single   = SMO_identity;
+    to_double   = SMO_view_to_view_x;
+  } else if (word1 == "apiview") {
+    from_single = SMO_apiview_to_view;
+    from_double = SMO_apiview_x_to_view;
+    to_single   = SMO_view_to_apiview;
+    to_double   = SMO_view_to_apiview_x;
+  } else if (word1 == "apiclip") {
+    from_single = SMO_apiclip_to_view;
+    from_double = SMO_apiclip_x_to_view;
+    to_single   = SMO_view_to_apiclip;
+    to_double   = SMO_view_to_apiclip_x;
+  } else {
+    from_single = SMO_view_x_to_view;
+    from_double = SMO_view_x_to_view;
+    to_single   = SMO_view_to_view_x;
+    to_double   = SMO_view_to_view_x;
+    word2 = word1;
+  }
+  
+  if (fromflag) {
+    if (word2 == "") {
+      bind._part[0] = from_single;
+      bind._arg[0] = NULL;
+    } else {
+      if (from_double == SMO_INVALID) {
+        cp_report_error(p, "Could not parse coordinate system name");
+        return false;
+      }
+      bind._part[0] = from_double;
+      bind._arg[0] = InternalName::make(word2);
     }
-    spec._part[part] = ofop;
-    spec._arg[part] = InternalName::make(pieces[next+2]);
-    next += 3;
-    return true;
   } else {
-    spec._part[part] = op;
-    spec._arg[part] = NULL;
-    next += 1;
-    return true;
+    if (word2 == "") {
+      bind._part[1] = to_single;
+      bind._arg[1] = NULL;
+    } else {
+      if (to_double == SMO_INVALID) {
+        cp_report_error(p, "Could not parse coordinate system name");
+        return false;
+      }
+      bind._part[1] = to_double;
+      bind._arg[1] = InternalName::make(word2);
+    }
   }
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -468,84 +578,163 @@ compile_parameter(const ShaderArgId  &arg_id,
       if (!cp_errchk_parameter_float(p, 4, 4)) return false;
     }
     
-    // Parse the first half of the clause.
-    bool ok = true;
-    if ((pieces[next]=="")||(pieces[next]=="of")||(pieces[next]=="to")){
-      cp_report_error(p, "argument missing");
+    if (!cp_parse_coord_sys(p, pieces, next, bind, true)) {
       return false;
-    } else if (pieces[next] == "world") {
-      bind._part[0] = SMO_world_to_view;
-      bind._arg[0] = NULL;
-      next += 1;
-    } else if (pieces[next] == "model") {
-      ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_view_x_to_view, SMO_model_to_view);
-    } else if (pieces[next] == "clip") {
-      ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_clip_x_to_view, SMO_clip_to_view);
-    } else if (pieces[next] == "view") {
-      ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_view_x_to_view, SMO_identity);
-    } else if (pieces[next] == "apiview") {
-      ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_apiview_x_to_view, SMO_apiview_to_view);
-    } else if (pieces[next] == "apiclip") {
-      ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_apiclip_x_to_view, SMO_apiclip_to_view);
-    } else {
-      bind._part[0] = SMO_view_x_to_view;
-      bind._arg[0] = InternalName::make(pieces[next]);
-      next += 1;
     }
-
-    // Check for errors in the first clause.
-    if (!ok) {
+    if (!cp_parse_delimiter(p, pieces, next)) {
       return false;
     }
-
-    // Check for syntactic well-formed-ness.
-    if (pieces[next] != "to") {
-      cp_report_error(p, "keyword 'to' expected");
+    if (!cp_parse_coord_sys(p, pieces, next, bind, false)) {
+      return false;
+    }
+    if (!cp_parse_eol(p, pieces, next)) {
       return false;
-    } else {
-      next += 1;
     }
     
-    // Parse the second half of the clause.
-    if ((pieces[next]=="")||(pieces[next]=="of")||(pieces[next]=="to")){
-      cp_report_error(p, "argument missing");
+    cp_optimize_mat_spec(bind);
+    _mat_spec.push_back(bind);
+    return true;
+  }
+
+  // Special parameter: attr_material or attr_color
+
+  if (pieces[0] == "attr") {
+    if ((!cp_errchk_parameter_words(p,2)) ||
+        (!cp_errchk_parameter_in(p)) ||
+        (!cp_errchk_parameter_uniform(p))) {
       return false;
-    } else if (pieces[next] == "world") {
-      bind._part[1] = SMO_view_to_world;
+    }
+    ShaderMatSpec bind;
+    if (pieces[1] == "material") {
+      if (!cp_errchk_parameter_float(p,16,16)) {
+        return false;
+      }
+      bind._id = arg_id;
+      bind._piece = SMP_transpose;
+      bind._func = SMF_first;
+      bind._part[0] = SMO_attr_material;
+      bind._arg[0] = NULL;
+      bind._part[1] = SMO_identity;
+      bind._arg[1] = NULL;
+    } else if (pieces[1] == "color") {
+      if (!cp_errchk_parameter_float(p,3,4)) {
+        return false;
+      }
+      bind._id = arg_id;
+      bind._piece = SMP_row3;
+      bind._func = SMF_first;
+      bind._part[0] = SMO_attr_color;
+      bind._arg[0] = NULL;
+      bind._part[1] = SMO_identity;
       bind._arg[1] = NULL;
-      next += 1;
-    } else if (pieces[next] == "model") {
-      ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_view_x, SMO_view_to_model);
-    } else if (pieces[next] == "clip") {
-      ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_clip_x, SMO_view_to_clip);
-    } else if (pieces[next] == "view") {
-      ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_view_x, SMO_identity);
-    } else if (pieces[next] == "apiview") {
-      ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_apiview_x, SMO_view_to_apiview);
-    } else if (pieces[next] == "apiclip") {
-      ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_apiclip_x, SMO_view_to_apiclip);
     } else {
-      bind._part[1] = SMO_view_to_view_x;
-      bind._arg[1] = InternalName::make(pieces[next]);
-      next += 1;
+      cp_report_error(p,"Unknown attr parameter.");
+      return false;
     }
     
-    // Check for errors in the second clause.
-    if (!ok) {
+    cp_optimize_mat_spec(bind);
+    _mat_spec.push_back(bind);
+    return true;
+  }
+
+  if (pieces[0] == "color") {
+    if ((!cp_errchk_parameter_words(p,1)) ||
+        (!cp_errchk_parameter_in(p)) ||
+        (!cp_errchk_parameter_uniform(p))) {
       return false;
     }
+    ShaderMatSpec bind;
+    
+    cp_optimize_mat_spec(bind);
+    _mat_spec.push_back(bind);
+    return true;
+  }
 
-    // Check for syntactic well-formed-ness.
-    if (pieces[next] != "") {
-      cp_report_error(p, "end of line expected");
+  // Keywords to access light properties.
+
+  if (pieces[0] == "alight") {
+    if ((!cp_errchk_parameter_words(p,2))||
+        (!cp_errchk_parameter_in(p)) ||
+        (!cp_errchk_parameter_uniform(p))||
+        (!cp_errchk_parameter_float(p,3,4))) {
       return false;
     }
-    
+    ShaderMatSpec bind;
+    bind._id = arg_id;
+    bind._piece = SMP_row3;
+    bind._func = SMF_first;
+    bind._part[0] = SMO_alight_x;
+    bind._arg[0] = InternalName::make(pieces[1]);
+    bind._part[1] = SMO_identity;
+    bind._arg[1] = NULL;
+
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     return true;
   }
 
+  if (pieces[0] == "satten") {
+    if ((!cp_errchk_parameter_words(p,2))||
+        (!cp_errchk_parameter_in(p)) ||
+        (!cp_errchk_parameter_uniform(p))||
+        (!cp_errchk_parameter_float(p,4,4))) {
+      return false;
+    }
+    ShaderMatSpec bind;
+    bind._id = arg_id;
+    bind._piece = SMP_row3;
+    bind._func = SMF_first;
+    bind._part[0] = SMO_satten_x;
+    bind._arg[0] = InternalName::make(pieces[1]);
+    bind._part[1] = SMO_identity;
+    bind._arg[1] = NULL;
+
+    cp_optimize_mat_spec(bind);
+    _mat_spec.push_back(bind);
+    return true;
+  }
+
+  if ((pieces[0]=="dlight")||(pieces[0]=="plight")||(pieces[0]=="slight")) {
+    if ((!cp_errchk_parameter_in(p)) ||
+        (!cp_errchk_parameter_uniform(p))||
+        (!cp_errchk_parameter_float(p,16,16))) {
+      return false;
+    }
+    ShaderMatSpec bind;
+    bind._id = arg_id;
+    bind._piece = SMP_transpose;
+    int next = 1;
+    pieces.push_back("");
+    if (pieces[next] == "") {
+      cp_report_error(p, "Light name expected");
+      return false;
+    }
+    if (pieces[0] == "dlight") {
+      bind._func = SMF_transform_dlight;
+      bind._part[0] = SMO_dlight_x;
+    } else if (pieces[0] == "plight") {
+      bind._func = SMF_transform_plight;
+      bind._part[0] = SMO_plight_x;
+    } else if (pieces[0] == "slight") {
+      bind._func = SMF_transform_slight;
+      bind._part[0] = SMO_slight_x;
+    }
+    bind._arg[0] = InternalName::make(pieces[next]);
+    next += 1;
+    if (!cp_parse_delimiter(p, pieces, next)) {
+      return false;
+    }
+    if (!cp_parse_coord_sys(p, pieces, next, bind, false)) {
+      return false;
+    }
+    if (!cp_parse_eol(p, pieces, next)) {
+      return false;
+    }
+    cp_optimize_mat_spec(bind);
+    _mat_spec.push_back(bind);
+    return true;
+  }
+  
   // Keywords to access unusual parameters.
   
   if (pieces[0] == "sys") {
@@ -1253,6 +1442,17 @@ make(const string &body) {
   }
   PT(Shader) result = new Shader("created-shader", body);
   _make_table[body] = result;
+  if (dump_generated_shaders) {
+    ostringstream fns;
+    int index = _shaders_generated ++;
+    fns << "genshader" << index;
+    string fn = fns.str();
+    gobj_cat.warning() << "Dumping shader: " << fn << "\n";
+    ofstream s;
+    s.open(fn.c_str());
+    s << body;
+    s.close();
+  }
   return result;
 }
 

+ 28 - 8
panda/src/gobj/shader.h

@@ -72,6 +72,15 @@ public:
     SMO_pixel_size,
     SMO_card_center,
     
+    SMO_attr_material,
+    SMO_attr_color,
+    
+    SMO_alight_x,
+    SMO_dlight_x,
+    SMO_plight_x,
+    SMO_slight_x,
+    SMO_satten_x,
+    
     SMO_mat_constant_x,
     SMO_vec_constant_x,
     
@@ -101,6 +110,12 @@ public:
 
     SMO_apiclip_x_to_view,
     SMO_view_to_apiclip_x,
+    
+    SMO_light_vector,
+    SMO_light_color,
+    SMO_light_spec,
+
+    SMO_INVALID
   };
 
   enum ShaderArgType {
@@ -139,11 +154,14 @@ public:
   enum ShaderBug {
     SBUG_ati_draw_buffers,
   };
-
+  
   enum ShaderMatFunc {
     SMF_compose,
     SMF_compose_cache_first,
     SMF_compose_cache_second,
+    SMF_transform_dlight,
+    SMF_transform_plight,
+    SMF_transform_slight,
     SMF_first,
   };
 
@@ -215,13 +233,14 @@ public:
   bool cp_errchk_parameter_uniform(ShaderArgInfo &arg);
   bool cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi);
   bool cp_errchk_parameter_sampler(ShaderArgInfo &arg);
-  bool cp_parse_trans_clause(ShaderArgInfo &arg,
-                             ShaderMatSpec &spec,
-                             int part,
-                             const vector_string &pieces,
-                             int &next,
-                             ShaderMatInput ofop,
-                             ShaderMatInput op);
+  bool cp_parse_eol(ShaderArgInfo &arg,
+                    vector_string &pieces, int &next);
+  bool cp_parse_delimiter(ShaderArgInfo &arg, 
+                          vector_string &pieces, int &next);
+  string cp_parse_non_delimiter(vector_string &pieces, int &next);
+  bool cp_parse_coord_sys(ShaderArgInfo &arg,
+                          vector_string &pieces, int &next,
+                          ShaderMatSpec &spec, bool fromflag);
   void cp_optimize_mat_spec(ShaderMatSpec &spec);
   
   bool compile_parameter(const ShaderArgId    &arg_id,
@@ -273,6 +292,7 @@ public:
   
   static ShaderCaps _default_caps;
   static ShaderUtilization _shader_utilization;
+  static int _shaders_generated;
 
   typedef pmap < Filename , Shader * > LoadTable;
   typedef pmap < string   , Shader * > MakeTable;