Browse Source

Added better code to compile shaders

Josh Yelon 20 years ago
parent
commit
23b0c5d850

+ 4 - 1
doc/makepanda/makepanda.py

@@ -1773,7 +1773,10 @@ ConditionalWriteFile(PREFIX+'/include/dtool_config.h',conf)
 ##########################################################################################
 
 CONFAUTOPRC=ReadFile("makepanda/confauto.in")
-CONFIGPRC=ReadFile("makepanda/config.in")
+if (os.path.isfile("makepanda/myconfig.in")):
+  CONFIGPRC=ReadFile("makepanda/myconfig.in")
+else:
+  CONFIGPRC=ReadFile("makepanda/config.in")
 
 if (sys.platform != "win32"):
     CONFAUTOPRC = CONFAUTOPRC.replace("aux-display pandadx9","")

+ 42 - 42
doc/makepanda/makepanda71.vcproj

@@ -1,42 +1,42 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="7.10"
-	Name="makepanda71"
-	ProjectGUID="{F4935D7A-20AD-4132-B3CB-ADFF4F928D25}"
-	Keyword="MakeFileProj">
-	<Platforms>
-		<Platform
-			Name="Win32"/>
-	</Platforms>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			OutputDirectory="Debug"
-			IntermediateDirectory="Debug"
-			ConfigurationType="0">
-			<Tool
-				Name="VCNMakeTool"
-				BuildCommandLine="cd .. &amp; makepanda\makepanda --everything --installer"
-				Output="..\built\bin\ppython.exe"/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Source Files"
-			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
-		</Filter>
-		<Filter
-			Name="Header Files"
-			Filter="h;hpp;hxx;hm;inl;inc">
-		</Filter>
-		<Filter
-			Name="Resource Files"
-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.10"
+	Name="makepanda71"
+	ProjectGUID="{F4935D7A-20AD-4132-B3CB-ADFF4F928D25}"
+	Keyword="MakeFileProj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="0">
+			<Tool
+				Name="VCNMakeTool"
+				BuildCommandLine="cd .. &amp; makepanda\makepanda --everything --installer"
+				Output="..\built\python\python.exe"/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc">
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

+ 5 - 22
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -68,10 +68,6 @@
 #include "shader.h"
 #include "shaderMode.h"
 
-#ifdef HAVE_CGGL
-#include "Cg/cgGL.h"
-#endif
-
 #include <algorithm>
 
 TypeHandle CLP(GraphicsStateGuardian)::_type_handle;
@@ -859,16 +855,6 @@ reset() {
 
   _error_count = 0;
 
-#ifdef HAVE_CGGL
-  _cg_context = cgCreateContext();
-  if (_cg_context != 0) {
-    _cg_vprofile = cgGLGetLatestProfile(CG_GL_VERTEX);
-    _cg_fprofile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
-  } else {
-    cerr << "Warning: could not create Cg context.\n";
-  }
-#endif
-
   report_my_gl_errors();
 }
 
@@ -1944,7 +1930,10 @@ release_geom(GeomContext *gc) {
 ////////////////////////////////////////////////////////////////////
 ShaderContext *CLP(GraphicsStateGuardian)::
 prepare_shader(Shader *shader) {
-  return new CLP(ShaderContext)(this, shader);
+  CLP(ShaderContext) *result = new CLP(ShaderContext)(shader);
+  if (result->valid()) return result;
+  delete result;
+  return NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2620,7 +2609,7 @@ issue_shader(const ShaderAttrib *attrib) {
       _shader_context = 0;
     }
     if (context != 0) {
-      context->bind(mode);
+      context->bind(mode, this);
       _shader_context = context;
     }
     _shader_mode = mode;
@@ -4762,12 +4751,6 @@ finish_modify_state() {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 free_pointers() {
-#ifdef HAVE_CGGL
-  if (_cg_context) {
-    cgDestroyContext(_cg_context);
-    _cg_context = 0;
-  }
-#endif
 }
 
 ////////////////////////////////////////////////////////////////////

+ 0 - 10
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -41,10 +41,6 @@
 #include "shader.h"
 #include "shaderMode.h"
 
-#ifdef HAVE_CGGL
-#include "Cg/cgGL.h"
-#endif
-
 class PlaneNode;
 class Light;
 
@@ -389,12 +385,6 @@ public:
   typedef pvector<GLuint> DeletedDisplayLists;
   DeletedDisplayLists _deleted_display_lists;
 
-#ifdef HAVE_CGGL
-  CGcontext _cg_context;
-  CGprofile _cg_vprofile;
-  CGprofile _cg_fprofile;
-#endif
-
   static PStatCollector _load_display_list_pcollector;
   static PStatCollector _primitive_batches_display_list_pcollector;
   static PStatCollector _vertices_display_list_pcollector;

+ 13 - 23
panda/src/glstuff/glShaderContext_src.I

@@ -17,29 +17,19 @@
 ////////////////////////////////////////////////////////////////////
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GLShaderContext::bind
+//     Function: GLShaderContext::valid
 //       Access: Public
-//  Description: xyz
-////////////////////////////////////////////////////////////////////
-INLINE void CLP(ShaderContext)::
-bind(ShaderMode *m) {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GLShaderContext::unbind
-//       Access: Public
-//  Description: xyz
-////////////////////////////////////////////////////////////////////
-INLINE void CLP(ShaderContext)::
-unbind() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GLShaderContext::rebind
-//       Access: Public
-//  Description: xyz
-////////////////////////////////////////////////////////////////////
-INLINE void CLP(ShaderContext)::
-rebind(ShaderMode *oldmode, ShaderMode *newmode) {
+//  Description: Returns true if the shader is "valid", ie, if the
+//               compilation was successful.  The compilation could
+//               fail if there is a syntax error in the shader, or
+//               if the current video card isn't shader-capable,
+//               or if no shader languages are compiled into panda.
+////////////////////////////////////////////////////////////////////
+INLINE bool CLP(ShaderContext)::
+valid() {
+#ifdef HAVE_CGGL
+  if (_cg_context) return true;
+#endif
+  return false;
 }
 

+ 581 - 23
panda/src/glstuff/glShaderContext_src.cxx

@@ -24,44 +24,95 @@ TypeHandle CLP(ShaderContext)::_type_handle;
 //  Description: xyz
 ////////////////////////////////////////////////////////////////////
 CLP(ShaderContext)::
-CLP(ShaderContext)(CLP(GraphicsStateGuardian) *gsg, Shader *s) : ShaderContext(s) {
+CLP(ShaderContext)(Shader *s) : ShaderContext(s) {
   string header;
-  _gsg = gsg;
-  _valid = false;
   s->parse_init();
   s->parse_line(header, true, true);
   
 #ifdef HAVE_CGGL
-  _cg_vprogram = 0;
-  _cg_fprogram = 0;
+  _cg_context = (CGcontext)0;
+  _cg_profile[VERT_SHADER] = (CGprofile)0;
+  _cg_profile[FRAG_SHADER] = (CGprofile)0;
+  _cg_program[VERT_SHADER] = (CGprogram)0;
+  _cg_program[FRAG_SHADER] = (CGprogram)0;
 
   if (header == "Cg") {
-    if (_gsg->_cg_context == 0) {
-      cerr << "Cannot compile shader, no Cg context\n";
+
+    CGerror err;
+    _cg_context = cgCreateContext();
+    if (_cg_context == 0) {
+      release_resources();
+      cerr << "Cg not supported by this video card.\n";
       return;
     }
-    string commentary, vs, fs;
+    
+    _cg_profile[VERT_SHADER] = cgGLGetLatestProfile(CG_GL_VERTEX);
+    _cg_profile[FRAG_SHADER] = cgGLGetLatestProfile(CG_GL_FRAGMENT);
+    if ((_cg_profile[VERT_SHADER] == CG_PROFILE_UNKNOWN)||
+        (_cg_profile[FRAG_SHADER] == CG_PROFILE_UNKNOWN)) {
+      release_resources();
+      cerr << "Cg not supported by this video card II\n";
+      return;
+    }
+    cgGetError();
+    
+    string commentary, stext[2];
     s->parse_upto(commentary, "---*---", false);
-    s->parse_upto(vs, "---*---", false);
-    s->parse_upto(fs, "---*---", false);
-
-    _cg_vprogram = cgCreateProgram(_gsg->_cg_context, CG_SOURCE,
-                                   vs.c_str(), _gsg->_cg_vprofile,
-                                   "main", (const char**)NULL);
-    _cg_fprogram = cgCreateProgram(_gsg->_cg_context, CG_SOURCE,
-                                   fs.c_str(), _gsg->_cg_fprofile,
-                                   "main", (const char**)NULL);
+    _cg_linebase[0] = s->parse_lineno();
+    s->parse_upto(stext[0], "---*---", false);
+    _cg_linebase[1] = s->parse_lineno();
+    s->parse_upto(stext[1], "---*---", false);
     
-    if ((_cg_vprogram==0)||(_cg_fprogram == 0)) {
-      if (_cg_vprogram != 0) cgDestroyProgram(_cg_vprogram);
-      if (_cg_fprogram != 0) cgDestroyProgram(_cg_fprogram);
-      cerr << "Invalid Cg program" << s->_file << "\n";
+    for (int progindex=0; progindex<2; progindex++) {
+      _cg_program[progindex] =
+        cgCreateProgram(_cg_context, CG_SOURCE, stext[progindex].c_str(),
+                        _cg_profile[progindex], "main", (const char**)NULL);
+      err = cgGetError();
+      if (err != CG_NO_ERROR) {
+        if (err == CG_COMPILER_ERROR) {
+          string listing = cgGetLastListing(_cg_context);
+          vector_string errlines;
+          tokenize(listing, errlines, "\n");
+          for (int i=0; i<(int)errlines.size(); i++) {
+            string line = trim(errlines[i]);
+            if (line != "") {
+              cerr << s->_file << " " << (_cg_linebase[progindex]-1) << "+" << errlines[i] << "\n";
+            }
+          }
+        } else {
+          cerr << s->_file << ": " << cgGetErrorString(err) << "\n";
+        }
+      }
+    }
+
+    if ((_cg_program[VERT_SHADER]==0)||(_cg_program[FRAG_SHADER]==0)) {
+      release_resources();
+      return;
+    }
+
+    bool success = true;
+    CGparameter parameter;
+    for (int progindex=0; progindex<2; progindex++) {
+      for (parameter = cgGetFirstLeafParameter(_cg_program[progindex],CG_PROGRAM);
+           parameter != 0;
+           parameter = cgGetNextLeafParameter(parameter)) {
+        success &= compile_cg_parameter(parameter);
+      }
+    }
+    if (!success) {
+      release_resources();
       return;
     }
+        
+    cgGLLoadProgram(_cg_program[VERT_SHADER]);
+    cgGLLoadProgram(_cg_program[FRAG_SHADER]);
+    
+    cerr << s->_file << ": compiled ok.\n";
+    return;
   }
 #endif
-
-  cerr << "Unrecognized shader language " << header << "\n";
+  
+  cerr << s->_file << ": unrecognized shader language " << header << "\n";
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -71,5 +122,512 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *gsg, Shader *s) : ShaderContext(s
 ////////////////////////////////////////////////////////////////////
 CLP(ShaderContext)::
 ~CLP(ShaderContext)() {
+  release_resources();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLShaderContext::release_resources
+//       Access: Public
+//  Description: Should deallocate all system resources (such as
+//               vertex program handles or Cg contexts).
+////////////////////////////////////////////////////////////////////
+void CLP(ShaderContext)::
+release_resources() {
+#ifdef HAVE_CGGL
+  if (_cg_context) {
+    cgDestroyContext(_cg_context);
+    _cg_context = (CGcontext)0;
+    _cg_profile[VERT_SHADER] = (CGprofile)0;
+    _cg_profile[FRAG_SHADER] = (CGprofile)0;
+    _cg_program[VERT_SHADER] = (CGprogram)0;
+    _cg_program[FRAG_SHADER] = (CGprogram)0;
+  }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLShaderContext::bind
+//       Access: Public
+//  Description: xyz
+////////////////////////////////////////////////////////////////////
+void CLP(ShaderContext)::
+bind(ShaderMode *m, GraphicsStateGuardianBase *gsg) {
+#ifdef HAVE_CGGL
+  if (_cg_context != 0) {
+    LVector4d tvec;
+
+    // Assign the uniform Auto-Matrices
+    for (int i=0; i<(int)_cg_autobind.size(); i++) {
+      cgGLSetStateMatrixParameter(_cg_autobind[i].parameter,
+                                  _cg_autobind[i].matrix,
+                                  _cg_autobind[i].orientation);
+    }
+  
+    // Bind the shaders.
+    cgGLEnableProfile(_cg_profile[VERT_SHADER]);
+    cgGLBindProgram(_cg_program[VERT_SHADER]);
+    cgGLEnableProfile(_cg_profile[FRAG_SHADER]);
+    cgGLBindProgram(_cg_program[FRAG_SHADER]);
+
+    // Pass in uniform sampler2d parameters.
+    for (int i=0; i<(int)_cg_tbind2d.size(); i++) {
+      int index = _cg_tbind2d[i].argindex;
+      if (index >= (int)m->_args.size()) continue;
+      if (m->_args[index]._type != ShaderModeArg::SAT_TEXTURE) continue;
+      Texture *tex = m->_args[index]._tvalue;
+      TextureContext *tc = tex->prepare_now(gsg->get_prepared_objects(),gsg);
+      CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
+      cgGLSetTextureParameter(_cg_tbind2d[i].parameter, gtc->_index);
+      cgGLEnableTextureParameter(_cg_tbind2d[i].parameter);
+    }
+  }
+#endif
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLShaderContext::unbind
+//       Access: Public
+//  Description: xyz
+////////////////////////////////////////////////////////////////////
+void CLP(ShaderContext)::
+unbind() {
+#ifdef HAVE_CGGL
+  if (_cg_context != 0) {
+    // Disable texture parameters.
+    for (int i=0; i<(int)_cg_tbind2d.size(); i++)
+      cgGLDisableTextureParameter(_cg_tbind2d[i].parameter);
+    
+    cgGLDisableProfile(_cg_profile[VERT_SHADER]);
+    cgGLDisableProfile(_cg_profile[FRAG_SHADER]);
+  }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLShaderContext::rebind
+//       Access: Public
+//  Description: xyz
+////////////////////////////////////////////////////////////////////
+void CLP(ShaderContext)::
+rebind(ShaderMode *oldmode, ShaderMode *newmode) {
+}
+
+#ifdef HAVE_CGGL
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::errchk_cg_parameter_words
+//       Access: Public, Static
+//  Description: Make sure the provided Cg parameter contains 
+//               the specified number of words.  If not, print
+//               error message and return false.
+////////////////////////////////////////////////////////////////////
+bool CLP(ShaderContext)::
+errchk_cg_parameter_words(CGparameter p, int len)
+{
+  vector_string words;
+  tokenize(cgGetParameterName(p), words, "_");
+  if (words.size() != len) {
+    errchk_cg_output(p, "parameter name has wrong number of words");
+    return false;
+  }
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::errchk_cg_parameter_direction
+//       Access: Public, Static
+//  Description: Make sure the provided Cg parameter has the
+//               correct direction.  If not, print
+//               error message and return false.
+////////////////////////////////////////////////////////////////////
+bool CLP(ShaderContext)::
+errchk_cg_parameter_direction(CGparameter p, CGenum dir)
+{
+  if (cgGetParameterDirection(p) != dir) {
+    if (dir == CG_IN)    errchk_cg_output(p, "parameter should be declared 'in'");
+    if (dir == CG_OUT)   errchk_cg_output(p, "parameter should be declared 'out'");
+    if (dir == CG_INOUT) errchk_cg_output(p, "parameter should be declared 'inout'");
+    return false;
+  }
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::errchk_cg_parameter_variance
+//       Access: Public, Static
+//  Description: Make sure the provided Cg parameter has the
+//               correct variance.  If not, print
+//               error message and return false.
+////////////////////////////////////////////////////////////////////
+bool CLP(ShaderContext)::
+errchk_cg_parameter_variance(CGparameter p, CGenum var)
+{
+  if (cgGetParameterVariability(p) != var) {
+    if (var == CG_UNIFORM) 
+      errchk_cg_output(p, "parameter should be declared 'uniform'");
+    if (var == CG_VARYING) 
+      errchk_cg_output(p, "parameter should be declared 'varying'");
+    if (var == CG_CONSTANT)
+      errchk_cg_output(p, "parameter should be declared 'const'");
+    return false;
+  }
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::errchk_cg_parameter_prog
+//       Access: Public, Static
+//  Description: Make sure the provided Cg parameter is a part
+//               of the correct program.  If not, print
+//               error message and return false.
+////////////////////////////////////////////////////////////////////
+bool CLP(ShaderContext)::
+errchk_cg_parameter_prog(CGparameter p, CGprogram prog, const string &msg)
+{
+  if (cgGetParameterProgram(p) != prog) {
+    string fmsg = "parameter can only be used in a ";
+    errchk_cg_output(p, fmsg+msg+" program");
+    return false;
+  }
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::errchk_cg_parameter_semantic
+//       Access: Public, Static
+//  Description: Make sure the provided Cg parameter has the
+//               correct semantic string.  If not, print
+//               error message and return false.
+////////////////////////////////////////////////////////////////////
+bool CLP(ShaderContext)::
+errchk_cg_parameter_semantic(CGparameter p, const string &semantic)
+{
+  if (semantic != cgGetParameterSemantic(p)) {
+    if (semantic == "") {
+      errchk_cg_output(p, "parameter should have no semantic string");
+    } else {
+      string msg = "parameter should have the semantic string ";
+      errchk_cg_output(p, msg + semantic);
+    }
+    return false;
+  }
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::errchk_cg_parameter_type
+//       Access: Public, Static
+//  Description: Make sure the provided Cg parameter has the
+//               correct type.  If not, print
+//               error message and return false.
+////////////////////////////////////////////////////////////////////
+bool CLP(ShaderContext)::
+errchk_cg_parameter_type(CGparameter p, CGtype dt)
+{
+  if (cgGetParameterType(p) != dt) {
+    string msg = "parameter should be of type ";
+    errchk_cg_output(p, msg + cgGetTypeString(dt));
+    return false;
+  }
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::errchk_cg_parameter_float
+//       Access: Public, Static
+//  Description: Make sure the provided Cg parameter has
+//               a floating point type.  If not, print
+//               error message and return false.
+////////////////////////////////////////////////////////////////////
+bool CLP(ShaderContext)::
+errchk_cg_parameter_float(CGparameter p)
+{
+  CGtype t = cgGetParameterType(p);
+  if ((t != CG_FLOAT1)&&(t != CG_FLOAT2)&&(t != CG_FLOAT3)&&(t != CG_FLOAT4)) {
+    errchk_cg_output(p, "parameter should have a float type");
+    return false;
+  }
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::errchk_cg_parameter_sampler
+//       Access: Public, Static
+//  Description: Make sure the provided Cg parameter has
+//               a texture type.  If not, print
+//               error message and return false.
+////////////////////////////////////////////////////////////////////
+bool CLP(ShaderContext)::
+errchk_cg_parameter_sampler(CGparameter p)
+{
+  CGtype t = cgGetParameterType(p);
+  if (t != CG_SAMPLER2D) {
+    errchk_cg_output(p, "parameter should have a 'sampler' type");
+    return false;
+  }
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::errchk_cg_parameter_direction
+//       Access: Public, Static
+//  Description: Print an error message including a description
+//               of the specified Cg parameter.
+////////////////////////////////////////////////////////////////////
+void CLP(ShaderContext)::
+errchk_cg_output(CGparameter p, const string &msg)
+{
+  string vstr;
+  CGenum v = cgGetParameterVariability(p);
+  if (v == CG_UNIFORM)  vstr = "uniform ";
+  if (v == CG_VARYING)  vstr = "varying ";
+  if (v == CG_CONSTANT) vstr = "const ";
+
+  string dstr;
+  CGenum d = cgGetParameterDirection(p);
+  if (d == CG_IN)    dstr = "in ";
+  if (d == CG_OUT)   dstr = "out ";
+  if (d == CG_INOUT) dstr = "inout ";
+  
+  const char *ts = cgGetTypeString(cgGetParameterType(p));
+  const char *ss = cgGetParameterSemantic(p);
+  
+  string err;
+  string fn = _shader->_file;
+  if (ss) {
+    err = fn + ": " + msg + " (" + vstr + dstr + ts + " " + cgGetParameterName(p) + ":" + ss + ")\n";
+  } else {
+    err = fn + ": " + msg + " (" + vstr + dstr + ts + " " + cgGetParameterName(p) + ")\n";
+  }
+  cerr << err << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLShaderContext::compile_cg_parameter
+//       Access: Public
+//  Description: Analyzes a Cg parameter and decides how to
+//               bind the parameter to some part of panda's
+//               internal state.  Updates one of the cg bind
+//               arrays to cause the binding to occur.
+////////////////////////////////////////////////////////////////////
+bool CLP(ShaderContext)::
+compile_cg_parameter(CGparameter p)
+{
+  string pname = cgGetParameterName(p);
+  if (pname.size() == 0) return true;
+  if (pname[0] == '$') return true;
+  vector_string pieces;
+  tokenize(pname, pieces, "_");
+  
+  if (pieces[0] == "vtx") {
+    if ((!errchk_cg_parameter_words(p,2)) ||
+        (!errchk_cg_parameter_direction(p, CG_IN)) ||
+        (!errchk_cg_parameter_variance(p, CG_VARYING)) ||
+        (!errchk_cg_parameter_prog(p, _cg_program[VERT_SHADER], "vertex")))
+      return false;
+    if (pieces[1] == "position") {
+      if (!errchk_cg_parameter_semantic(p,"POSITION")) return false;
+      if (!errchk_cg_parameter_float(p)) return false;
+      return true; // Cg handles this automatically.
+    }
+    if (pieces[1] == "normal") {
+      if (!errchk_cg_parameter_semantic(p,"NORMAL")) return false;
+      if (!errchk_cg_parameter_float(p)) return false;
+      return true; // Cg handles this automatically.
+    }
+    if (pieces[1] == "color") {
+      if (!errchk_cg_parameter_semantic(p,"COLOR")) return false;
+      if (!errchk_cg_parameter_float(p)) return false;
+      return true; // Cg handles this automatically.
+    }
+    if (pieces[1].substr(0,8) == "texcoord") {
+      string ss = upcase(pieces[1]);
+      if (!errchk_cg_parameter_semantic(p,ss)) return false;
+      if (!errchk_cg_parameter_float(p)) return false;
+      return true; // Cg handles this automatically.
+    }
+    // Handle an arbitrary column taken from the vertex array.
+    // IMPLEMENT ME.
+    errchk_cg_output(p, "Arbitrary vertex fields not implemented yet");
+    return false;
+  }
+  
+  if ((pieces[0] == "trans")||
+      (pieces[0] == "tpose")||
+      (pieces[0] == "row0")||
+      (pieces[0] == "row1")||
+      (pieces[0] == "row2")||
+      (pieces[0] == "row3")||
+      (pieces[0] == "col0")||
+      (pieces[0] == "col1")||
+      (pieces[0] == "col2")||
+      (pieces[0] == "col3")||
+      (pieces[0] == "xvec")||
+      (pieces[0] == "yvec")||
+      (pieces[0] == "zvec")||
+      (pieces[0] == "pos")) {
+    if ((!errchk_cg_parameter_words(p,4)) ||
+        (!errchk_cg_parameter_direction(p, CG_IN)) ||
+        (!errchk_cg_parameter_variance(p, CG_UNIFORM)) ||
+        (!errchk_cg_parameter_semantic(p, "")))
+      return false;
+    if (pieces[2] != "rel") {
+      errchk_cg_output(p, "syntax error");
+      return false;
+    }
+    ShaderTransBind bind;
+    bind.parameter = p;
+
+    if      (pieces[0]=="trans") bind.trans_piece = TRANS_NORMAL;
+    else if (pieces[0]=="tpose") bind.trans_piece = TRANS_TPOSE;
+    else if (pieces[0]=="row0") bind.trans_piece = TRANS_ROW0;
+    else if (pieces[0]=="row1") bind.trans_piece = TRANS_ROW1;
+    else if (pieces[0]=="row2") bind.trans_piece = TRANS_ROW2;
+    else if (pieces[0]=="row3") bind.trans_piece = TRANS_ROW3;
+    else if (pieces[0]=="col0") bind.trans_piece = TRANS_COL0;
+    else if (pieces[0]=="col1") bind.trans_piece = TRANS_COL1;
+    else if (pieces[0]=="col2") bind.trans_piece = TRANS_COL2;
+    else if (pieces[0]=="col3") bind.trans_piece = TRANS_COL3;
+    else if (pieces[0]=="xvec") bind.trans_piece = TRANS_ROW0;
+    else if (pieces[0]=="yvec") bind.trans_piece = TRANS_ROW1;
+    else if (pieces[0]=="zvec") bind.trans_piece = TRANS_ROW2;
+    else if (pieces[0]=="pos")  bind.trans_piece = TRANS_ROW3;
+
+    if      (pieces[1] == "world")  bind.src_argindex = ARGINDEX_WORLD;
+    else if (pieces[1] == "camera") bind.src_argindex = ARGINDEX_CAMERA;
+    else if (pieces[1] == "model")  bind.src_argindex = ARGINDEX_MODEL;
+    else bind.src_argindex = _shader->arg_index(pieces[1]);
+    if      (pieces[3] == "world")  bind.rel_argindex = ARGINDEX_WORLD;
+    else if (pieces[3] == "camera") bind.rel_argindex = ARGINDEX_CAMERA;
+    else if (pieces[3] == "model")  bind.rel_argindex = ARGINDEX_MODEL;
+    else bind.rel_argindex = _shader->arg_index(pieces[3]);
+
+    if ((bind.trans_piece == TRANS_NORMAL)||(bind.trans_piece == TRANS_TPOSE)) {
+      if (!errchk_cg_parameter_type(p, CG_FLOAT4x4)) return false;
+    } else {
+      if (!errchk_cg_parameter_type(p, CG_FLOAT4)) return false;
+    }
+
+    _cg_trans_bind.push_back(bind);
+    if ((bind.src_argindex == ARGINDEX_MODEL) ||
+        (bind.rel_argindex == ARGINDEX_MODEL)) {
+      _cg_trans_rebind.push_back(bind);
+    }
+    return true;
+  }
+
+  if ((pieces[0]=="mstrans")||
+      (pieces[0]=="cstrans")||
+      (pieces[0]=="wstrans")||
+      (pieces[0]=="mspos")||
+      (pieces[0]=="cspos")||
+      (pieces[0]=="wspos")) {
+    if ((!errchk_cg_parameter_words(p,2)) ||
+        (!errchk_cg_parameter_direction(p, CG_IN)) ||
+        (!errchk_cg_parameter_variance(p, CG_UNIFORM)) ||
+        (!errchk_cg_parameter_semantic(p, "")))
+      return false;
+    ShaderTransBind bind;
+    bind.parameter = p;
+    
+    if      (pieces[0]=="wstrans") { bind.rel_argindex = ARGINDEX_WORLD;  bind.trans_piece = TRANS_NORMAL; }
+    else if (pieces[0]=="cstrans") { bind.rel_argindex = ARGINDEX_CAMERA; bind.trans_piece = TRANS_NORMAL; }
+    else if (pieces[0]=="mstrans") { bind.rel_argindex = ARGINDEX_MODEL;  bind.trans_piece = TRANS_NORMAL; }
+    else if (pieces[0]=="wspos")   { bind.rel_argindex = ARGINDEX_WORLD;  bind.trans_piece = TRANS_ROW3; }
+    else if (pieces[0]=="cspos")   { bind.rel_argindex = ARGINDEX_CAMERA; bind.trans_piece = TRANS_ROW3; }
+    else if (pieces[0]=="mspos")   { bind.rel_argindex = ARGINDEX_MODEL;  bind.trans_piece = TRANS_ROW3; }
+    
+    if      (pieces[1] == "world")  bind.src_argindex = ARGINDEX_WORLD;
+    else if (pieces[1] == "camera") bind.src_argindex = ARGINDEX_CAMERA;
+    else if (pieces[1] == "model")  bind.src_argindex = ARGINDEX_MODEL;
+    else bind.src_argindex = _shader->arg_index(pieces[1]);
+    
+    if ((bind.trans_piece == TRANS_NORMAL)||(bind.trans_piece == TRANS_TPOSE)) {
+      if (!errchk_cg_parameter_type(p, CG_FLOAT4x4)) return false;
+    } else {
+      if (!errchk_cg_parameter_type(p, CG_FLOAT4)) return false;
+    }
+    _cg_trans_bind.push_back(bind);
+    if ((bind.src_argindex == ARGINDEX_MODEL) ||
+        (bind.rel_argindex == ARGINDEX_MODEL)) {
+      _cg_trans_rebind.push_back(bind);
+    }
+    return true;
+  }
+
+  if ((pieces[0]=="mat")||
+      (pieces[0]=="inv")||
+      (pieces[0]=="tps")||
+      (pieces[0]=="itp")) {
+    if ((!errchk_cg_parameter_words(p,2)) ||
+        (!errchk_cg_parameter_direction(p, CG_IN)) ||
+        (!errchk_cg_parameter_variance(p, CG_UNIFORM)) ||
+        (!errchk_cg_parameter_type(p, CG_FLOAT4x4)))
+      return false;
+    ShaderAutoBind bind;
+    bind.parameter = p;
+    if      (pieces[1] == "modelview")  bind.matrix = CG_GL_MODELVIEW_MATRIX;
+    else if (pieces[1] == "projection") bind.matrix = CG_GL_PROJECTION_MATRIX;
+    else if (pieces[1] == "texmatrix")  bind.matrix = CG_GL_TEXTURE_MATRIX;
+    else if (pieces[1] == "modelproj")  bind.matrix = CG_GL_MODELVIEW_PROJECTION_MATRIX;
+    else {
+      errchk_cg_output(p, "unrecognized matrix name");
+      return false;
+    }
+    if      (pieces[0]=="mat") bind.orientation = CG_GL_MATRIX_IDENTITY;
+    else if (pieces[0]=="inv") bind.orientation = CG_GL_MATRIX_INVERSE;
+    else if (pieces[0]=="tps") bind.orientation = CG_GL_MATRIX_TRANSPOSE;
+    else if (pieces[0]=="itp") bind.orientation = CG_GL_MATRIX_INVERSE_TRANSPOSE;
+    _cg_autobind.push_back(bind);
+    return true;
+  }
+
+  if (pieces[0] == "tex") {
+    if ((!errchk_cg_parameter_words(p,2)) ||
+        (!errchk_cg_parameter_direction(p, CG_IN)) ||
+        (!errchk_cg_parameter_variance(p, CG_UNIFORM)) ||
+        (!errchk_cg_parameter_sampler(p)))
+      return false;
+    if (cgGetParameterSemantic(p)[0]!=0) {
+      string texunit = "TEX"+upcase(pieces[1]);
+      if (!errchk_cg_parameter_semantic(p, texunit)) return false;
+    }
+    return true; // Cg handles this automatically.
+  }
+
+  if (pieces[0] == "k") {
+    if ((!errchk_cg_parameter_words(p,2)) ||
+        (!errchk_cg_parameter_direction(p, CG_IN)) ||
+        (!errchk_cg_parameter_variance(p, CG_UNIFORM)))
+      return false;
+    ShaderArgBind bind;
+    bind.parameter = p;
+    bind.argindex = _shader->arg_index(pieces[1]);
+    switch (cgGetParameterType(p)) {
+    case CG_FLOAT1:    _cg_vbind1.push_back(bind); break;
+    case CG_FLOAT2:    _cg_vbind2.push_back(bind); break;
+    case CG_FLOAT3:    _cg_vbind3.push_back(bind); break;
+    case CG_FLOAT4:    _cg_vbind4.push_back(bind); break;
+    case CG_SAMPLER2D: _cg_tbind2d.push_back(bind); break;
+    case CG_SAMPLER3D: _cg_tbind3d.push_back(bind); break;
+    case CG_FLOAT4x4:  _cg_npbind.push_back(bind); break;
+    default:
+      errchk_cg_output(p, "Invalid type for a k-parameter");
+      return false;
+    }
+    return true;
+  }
+
+  if (pieces[0] == "l") {
+    // IMPLEMENT THE ERROR CHECKING
+    return true; // Cg handles this automatically.
+  }
+
+  if (pieces[0] == "o") {
+    // IMPLEMENT THE ERROR CHECKING
+    return true; // Cg handles this automatically.
+  }
+
+  errchk_cg_output(p, "unrecognized parameter name");
+  return false;
+}
+#endif

+ 68 - 11
panda/src/glstuff/glShaderContext_src.h

@@ -21,8 +21,7 @@
 #ifdef HAVE_CGGL
 #include "Cg/cgGL.h"
 #endif
-
-class CLP(GraphicsStateGuardian);
+#include "string_utils.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GLShaderContext
@@ -31,23 +30,81 @@ class CLP(GraphicsStateGuardian);
 
 class EXPCL_GL CLP(ShaderContext): public ShaderContext {
 public:
-  CLP(ShaderContext)(CLP(GraphicsStateGuardian) *gsg, Shader *shader);
+  CLP(ShaderContext)(Shader *s);
   ~CLP(ShaderContext)();
 
-  INLINE void bind(ShaderMode *mode);
-  INLINE void unbind();
-  INLINE void rebind(ShaderMode *oldmode, ShaderMode *newmode);
+  INLINE bool valid(void);
+  void bind(ShaderMode *mode, GraphicsStateGuardianBase *gsg);
+  void unbind();
+  void rebind(ShaderMode *oldmode, ShaderMode *newmode);
 
-  bool _valid;
-  
 private:
-  CLP(GraphicsStateGuardian) *_gsg;
   
 #ifdef HAVE_CGGL
-  CGprogram _cg_vprogram;
-  CGprogram _cg_fprogram;
+  enum {
+    ARGINDEX_WORLD =-1,
+    ARGINDEX_CAMERA=-2,
+    ARGINDEX_MODEL =-3
+  };
+  enum {
+    TRANS_NORMAL,
+    TRANS_TPOSE,
+    TRANS_ROW0,
+    TRANS_ROW1,
+    TRANS_ROW2,
+    TRANS_ROW3,
+    TRANS_COL0,
+    TRANS_COL1,
+    TRANS_COL2,
+    TRANS_COL3,
+  };
+  struct ShaderAutoBind {
+    CGparameter parameter;
+    CGGLenum matrix;
+    CGGLenum orientation;
+  };
+  struct ShaderArgBind {
+    CGparameter parameter;
+    int argindex;
+  };
+  struct ShaderTransBind {
+    CGparameter parameter;
+    int src_argindex;
+    int rel_argindex;
+    int trans_piece;
+  };
+  CGcontext _cg_context;
+  CGprofile _cg_profile[2];
+  CGprogram _cg_program[2];
+  int       _cg_linebase[2];
+  
+  // These arrays contain lists of "bindings." They
+  // tell us how to fill the shader's input parameters.
+  vector <ShaderAutoBind> _cg_autobind;
+  vector <ShaderArgBind> _cg_tbind2d;
+  vector <ShaderArgBind> _cg_tbind3d;
+  vector <ShaderArgBind> _cg_vbind1;
+  vector <ShaderArgBind> _cg_vbind2;
+  vector <ShaderArgBind> _cg_vbind3;
+  vector <ShaderArgBind> _cg_vbind4;
+  vector <ShaderArgBind> _cg_npbind;
+  vector <ShaderTransBind> _cg_trans_bind;
+  vector <ShaderTransBind> _cg_trans_rebind;
+  
+  bool compile_cg_parameter(CGparameter p);
+  bool errchk_cg_parameter_words(CGparameter p, int len);
+  bool errchk_cg_parameter_direction(CGparameter p, CGenum dir);
+  bool errchk_cg_parameter_variance(CGparameter p, CGenum var);
+  bool errchk_cg_parameter_prog(CGparameter p, CGprogram prog, const string &msg);
+  bool errchk_cg_parameter_semantic(CGparameter p, const string &semantic);
+  bool errchk_cg_parameter_type(CGparameter p, CGtype dt);
+  bool errchk_cg_parameter_float(CGparameter p);
+  bool errchk_cg_parameter_sampler(CGparameter p);
+  void errchk_cg_output(CGparameter p, const string &msg);
 #endif
 
+  void release_resources(void);
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

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

@@ -115,6 +115,19 @@ parse_rest(string &result) {
   result = _text.substr(_parse, _text.size() - _parse);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::parse_lineno
+//       Access: Public
+//  Description: Returns the line number of the current parse pointer.
+////////////////////////////////////////////////////////////////////
+int Shader::
+parse_lineno() {
+  int result = 1;
+  for (int i=0; i<_parse; i++)
+    if (_text[i] == '\n') result += 1;
+  return result;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Shader::parse_eof
 //       Access: Public
@@ -277,3 +290,4 @@ void Shader::
 register_with_read_factory() {
   // IMPLEMENT ME
 }
+

+ 5 - 1
panda/src/gobj/shader.h

@@ -61,13 +61,17 @@ PUBLISHED:
   int release_all();
 
 PUBLISHED:
+  // These routines help split the shader into sections,
+  // for those shader implementations that need to do so.
   void parse_init();
   void parse_line(string &result, bool rt, bool lt);
   void parse_upto(string &result, string pattern, bool include);
   void parse_rest(string &result);
+  int  parse_lineno();
   bool parse_eof();
-
+  
 public:
+
   INLINE int arg_count();
   int        arg_index(const string &id);
 

+ 6 - 0
panda/src/gobj/shaderContext.h

@@ -41,6 +41,12 @@ public:
   INLINE ShaderContext(Shader *shader);
   
   Shader *_shader;
+
+  enum {
+    VERT_SHADER=0,
+    FRAG_SHADER=1,
+    BOTH_SHADER=2,
+  };
   
 public:
   static TypeHandle get_class_type() {