Browse Source

Shader vertex arrays implemented

Josh Yelon 20 years ago
parent
commit
83b88c1ac3

+ 14 - 0
panda/src/display/graphicsStateGuardian.I

@@ -707,6 +707,20 @@ set_transform(const TransformState *transform) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_transform
+//       Access: Public
+//  Description: Fetches the external net transform.  This
+//               transform is generally only set when geometry is
+//               about to be rendered.  Therefore, this "get" function
+//               is typically only meaningful during the geometry
+//               rendering process.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(TransformState) GraphicsStateGuardian::
+get_transform() {
+  return _external_transform;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_current_display_region
 //     Function: GraphicsStateGuardian::get_current_display_region
 //       Access: Public
 //       Access: Public

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

@@ -209,7 +209,8 @@ public:
   INLINE void modify_state(const RenderState *state);
   INLINE void modify_state(const RenderState *state);
   INLINE void set_state(const RenderState *state);
   INLINE void set_state(const RenderState *state);
   INLINE void set_transform(const TransformState *transform);
   INLINE void set_transform(const TransformState *transform);
-
+  INLINE CPT(TransformState) get_transform();
+  
   RenderBuffer get_render_buffer(int buffer_type);
   RenderBuffer get_render_buffer(int buffer_type);
 
 
   INLINE const DisplayRegion *get_current_display_region() const;
   INLINE const DisplayRegion *get_current_display_region() const;

+ 117 - 15
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -771,8 +771,10 @@ reset() {
 
 
   _texgen_forced_normal = false;
   _texgen_forced_normal = false;
 
 
-  _shader_mode = (ShaderMode *)NULL;
-  _shader_context = (CLP(ShaderContext) *)NULL;
+  _current_shader_mode = (ShaderMode *)NULL;
+  _current_shader_context = (CLP(ShaderContext) *)NULL;
+  _vertex_array_shader_mode = (ShaderMode *)NULL;
+  _vertex_array_shader_context = (CLP(ShaderContext) *)NULL;
   
   
   // Count the max number of lights
   // Count the max number of lights
   GLint max_lights;
   GLint max_lights;
@@ -1297,8 +1299,53 @@ begin_draw_primitives(const Geom *geom, const GeomMunger *munger,
 #endif
 #endif
   }
   }
 
 
+  // Enable the appropriate vertex arrays, and disable any
+  // extra vertex arrays used by the previous rendering mode.
 #ifdef SUPPORT_IMMEDIATE_MODE
 #ifdef SUPPORT_IMMEDIATE_MODE
   _use_sender = !vertex_arrays;
   _use_sender = !vertex_arrays;
+#endif
+  if (_vertex_array_shader_context==0) {
+    if (_current_shader_context==0) {
+      update_standard_vertex_arrays();
+    } else {
+      disable_standard_vertex_arrays();
+      _current_shader_context->update_shader_vertex_arrays(NULL,this);
+    }
+  } else {
+    if (_current_shader_context==0) {
+      _vertex_array_shader_context->disable_shader_vertex_arrays(this);
+      update_standard_vertex_arrays();
+    } else {
+      _current_shader_context->
+        update_shader_vertex_arrays(_vertex_array_shader_context,this);
+    }
+  }
+  _vertex_array_shader_mode = _current_shader_mode;
+  _vertex_array_shader_context = _current_shader_context;
+  
+  report_my_gl_errors();
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::update_standard_vertex_arrays
+//       Access: Protected
+//  Description: Disables any unneeded vertex arrays that
+//               were previously enabled, and enables any vertex
+//               arrays that are needed that were not previously
+//               enabled (or, sets up an immediate-mode sender).
+//               Called only from begin_draw_primitives.
+//               Used only when the standard (non-shader) pipeline
+//               is about to be used - glShaderContexts are responsible
+//               for setting up their own vertex arrays.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+update_standard_vertex_arrays()
+{
+  const GeomVertexAnimationSpec &animation = 
+    _vertex_data->get_format()->get_animation();
+  bool hardware_animation = (animation.get_animation_type() == Geom::AT_hardware);
+#ifdef SUPPORT_IMMEDIATE_MODE
   if (_use_sender) {
   if (_use_sender) {
     // We must use immediate mode to render primitives.
     // We must use immediate mode to render primitives.
     _sender.clear();
     _sender.clear();
@@ -1500,9 +1547,46 @@ begin_draw_primitives(const Geom *geom, const GeomMunger *munger,
       GLP(EnableClientState)(GL_VERTEX_ARRAY);
       GLP(EnableClientState)(GL_VERTEX_ARRAY);
     }
     }
   }
   }
+}
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::disable_standard_vertex_arrays
+//       Access: Protected
+//  Description: Used to disable all the standard vertex arrays that
+//               are currently enabled.  glShaderContexts are
+//               responsible for setting up their own vertex arrays,
+//               but before they can do so, the standard vertex
+//               arrays need to be disabled to get them "out of the
+//               way."  Called only from begin_draw_primitives.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+disable_standard_vertex_arrays()
+{
+#ifdef SUPPORT_IMMEDIATE_MODE
+  if (_use_sender) return;
+#endif
+
+  GLP(DisableClientState)(GL_NORMAL_ARRAY);
+  GLP(DisableClientState)(GL_COLOR_ARRAY);
+  GLP(Color4f)(1.0f, 1.0f, 1.0f, 1.0f);
+  report_my_gl_errors();
+
+  for (int stage_index=0; stage_index < _last_max_stage_index; stage_index++) {
+    _glClientActiveTexture(GL_TEXTURE0 + stage_index);
+    GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY);
+  }
+  _last_max_stage_index = 0;
+  report_my_gl_errors();
+  
+  if (_supports_vertex_blend) {
+    GLP(DisableClientState)(GL_WEIGHT_ARRAY_ARB);
+    if (_supports_matrix_palette) {
+      GLP(DisableClientState)(GL_MATRIX_INDEX_ARRAY_ARB);
+    }
+  }
+  
+  GLP(DisableClientState)(GL_VERTEX_ARRAY);
   report_my_gl_errors();
   report_my_gl_errors();
-  return true;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1554,6 +1638,9 @@ draw_triangles(const GeomTriangles *primitive) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 draw_tristrips(const GeomTristrips *primitive) {
 draw_tristrips(const GeomTristrips *primitive) {
+
+  report_my_gl_errors();
+
 #ifndef NDEBUG
 #ifndef NDEBUG
   if (GLCAT.is_spam()) {
   if (GLCAT.is_spam()) {
     GLCAT.spam() << "draw_tristrips: " << *primitive << "\n";
     GLCAT.spam() << "draw_tristrips: " << *primitive << "\n";
@@ -2558,6 +2645,9 @@ issue_transform(const TransformState *transform) {
     do_auto_rescale_normal();
     do_auto_rescale_normal();
   }
   }
 
 
+  if (_current_shader_context)
+    _current_shader_context->issue_transform(_current_shader_mode, this);
+  
   report_my_gl_errors();
   report_my_gl_errors();
 }
 }
 
 
@@ -2590,10 +2680,10 @@ void CLP(GraphicsStateGuardian)::
 issue_shader(const ShaderAttrib *attrib) {
 issue_shader(const ShaderAttrib *attrib) {
   ShaderMode *mode = attrib->get_shader_mode();
   ShaderMode *mode = attrib->get_shader_mode();
   if (mode == 0) {
   if (mode == 0) {
-    if (_shader_context != 0) {
-      _shader_context->unbind();
-      _shader_context = 0;
-      _shader_mode = 0;
+    if (_current_shader_context != 0) {
+      _current_shader_context->unbind();
+      _current_shader_mode = 0;
+      _current_shader_context = 0;
     }
     }
     return;
     return;
   }
   }
@@ -2601,23 +2691,35 @@ issue_shader(const ShaderAttrib *attrib) {
   Shader *shader = mode->get_shader();
   Shader *shader = mode->get_shader();
   CLP(ShaderContext) *context = (CLP(ShaderContext) *)(shader->prepare_now(get_prepared_objects(), this));
   CLP(ShaderContext) *context = (CLP(ShaderContext) *)(shader->prepare_now(get_prepared_objects(), this));
 
 
-  if (context != _shader_context) {
+  if (context == 0) {
+    if (_current_shader_context != 0) {
+      _current_shader_context->unbind();
+      _current_shader_mode = 0;
+      _current_shader_context = 0;
+    }
+    return;
+  }
+  
+  if (context != _current_shader_context) {
     // Use a completely different shader than before.
     // Use a completely different shader than before.
     // Unbind old shader, bind the new one.
     // Unbind old shader, bind the new one.
-    if (_shader_context != 0) {
-      _shader_context->unbind();
-      _shader_context = 0;
+    if (_current_shader_context != 0) {
+      _current_shader_context->unbind();
+      _current_shader_context = 0;
     }
     }
     if (context != 0) {
     if (context != 0) {
       context->bind(mode, this);
       context->bind(mode, this);
-      _shader_context = context;
+      _current_shader_mode = mode;
+      _current_shader_context = context;
     }
     }
-    _shader_mode = mode;
   } else {
   } else {
     // Use the same shader as before, but with new input arguments.
     // Use the same shader as before, but with new input arguments.
-    context->rebind(_shader_mode, mode);
-    _shader_mode = mode;
+    _current_shader_mode = mode;
+    _current_shader_context = context;
+    context->issue_parameters(mode, this);
   }
   }
+
+  report_my_gl_errors();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

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

@@ -73,6 +73,7 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian {
 public:
 public:
   CLP(GraphicsStateGuardian)(const FrameBufferProperties &properties);
   CLP(GraphicsStateGuardian)(const FrameBufferProperties &properties);
   virtual ~CLP(GraphicsStateGuardian)();
   virtual ~CLP(GraphicsStateGuardian)();
+  friend class CLP(ShaderContext);
 
 
   virtual void reset();
   virtual void reset();
 
 
@@ -248,6 +249,9 @@ protected:
   static GLenum get_blend_func(ColorBlendAttrib::Operand operand);
   static GLenum get_blend_func(ColorBlendAttrib::Operand operand);
   static GLenum get_usage(Geom::UsageHint usage_hint);
   static GLenum get_usage(Geom::UsageHint usage_hint);
 
 
+  void disable_standard_vertex_arrays();
+  void update_standard_vertex_arrays();
+
   static CPT(RenderState) get_untextured_state();
   static CPT(RenderState) get_untextured_state();
   static CPT(RenderState) get_smooth_state();
   static CPT(RenderState) get_smooth_state();
   static CPT(RenderState) get_flat_state();
   static CPT(RenderState) get_flat_state();
@@ -296,8 +300,6 @@ protected:
   bool _polygon_offset_enabled;
   bool _polygon_offset_enabled;
   bool _flat_shade_model;
   bool _flat_shade_model;
   int _decal_level;
   int _decal_level;
-  PT(ShaderMode) _shader_mode;
-  CLP(ShaderContext) *_shader_context;
   
   
   bool _dithering_enabled;
   bool _dithering_enabled;
   bool _texgen_forced_normal;
   bool _texgen_forced_normal;
@@ -310,7 +312,12 @@ protected:
   float _point_size;
   float _point_size;
   bool _point_perspective;
   bool _point_perspective;
   bool _vertex_blending_enabled;
   bool _vertex_blending_enabled;
-
+  
+  PT(ShaderMode) _current_shader_mode;
+  CLP(ShaderContext) *_current_shader_context;
+  PT(ShaderMode) _vertex_array_shader_mode;
+  CLP(ShaderContext) *_vertex_array_shader_context;
+  
   CPT(DisplayRegion) _actual_display_region;
   CPT(DisplayRegion) _actual_display_region;
 
 
 #ifdef SUPPORT_IMMEDIATE_MODE
 #ifdef SUPPORT_IMMEDIATE_MODE

+ 357 - 200
panda/src/glstuff/glShaderContext_src.cxx

@@ -31,14 +31,13 @@ CLP(ShaderContext)(Shader *s) : ShaderContext(s) {
   
   
 #ifdef HAVE_CGGL
 #ifdef HAVE_CGGL
   _cg_context = (CGcontext)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;
+  _cg_profile[SHADER_type_vert] = (CGprofile)0;
+  _cg_profile[SHADER_type_frag] = (CGprofile)0;
+  _cg_program[SHADER_type_vert] = (CGprogram)0;
+  _cg_program[SHADER_type_frag] = (CGprogram)0;
 
 
-  if (header == "Cg") {
+  if (header == "//Cg") {
 
 
-    CGerror err;
     _cg_context = cgCreateContext();
     _cg_context = cgCreateContext();
     if (_cg_context == 0) {
     if (_cg_context == 0) {
       release_resources();
       release_resources();
@@ -46,46 +45,28 @@ CLP(ShaderContext)(Shader *s) : ShaderContext(s) {
       return;
       return;
     }
     }
     
     
-    _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)) {
+    _cg_profile[SHADER_type_vert] = cgGLGetLatestProfile(CG_GL_VERTEX);
+    _cg_profile[SHADER_type_frag] = cgGLGetLatestProfile(CG_GL_FRAGMENT);
+    if ((_cg_profile[SHADER_type_vert] == CG_PROFILE_UNKNOWN)||
+        (_cg_profile[SHADER_type_frag] == CG_PROFILE_UNKNOWN)) {
       release_resources();
       release_resources();
       cerr << "Cg not supported by this video card II\n";
       cerr << "Cg not supported by this video card II\n";
       return;
       return;
     }
     }
-    cgGetError();
-    
-    string commentary, stext[2];
-    s->parse_upto(commentary, "---*---", false);
-    _cg_linebase[0] = s->parse_lineno();
-    s->parse_upto(stext[0], "---*---", false);
-    _cg_linebase[1] = s->parse_lineno();
-    s->parse_upto(stext[1], "---*---", false);
     
     
-    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";
-        }
-      }
-    }
+    cgGetError();
+    _cg_program[0] =
+      cgCreateProgram(_cg_context, CG_SOURCE, s->_text.c_str(),
+                      _cg_profile[0], "vshader", (const char**)NULL);
+    print_cg_compile_errors(s->_file, _cg_context);
 
 
-    if ((_cg_program[VERT_SHADER]==0)||(_cg_program[FRAG_SHADER]==0)) {
+    cgGetError();
+    _cg_program[1] =
+      cgCreateProgram(_cg_context, CG_SOURCE, s->_text.c_str(),
+                      _cg_profile[1], "fshader", (const char**)NULL);
+    print_cg_compile_errors(s->_file, _cg_context);
+
+    if ((_cg_program[SHADER_type_vert]==0)||(_cg_program[SHADER_type_frag]==0)) {
       release_resources();
       release_resources();
       return;
       return;
     }
     }
@@ -104,8 +85,8 @@ CLP(ShaderContext)(Shader *s) : ShaderContext(s) {
       return;
       return;
     }
     }
         
         
-    cgGLLoadProgram(_cg_program[VERT_SHADER]);
-    cgGLLoadProgram(_cg_program[FRAG_SHADER]);
+    cgGLLoadProgram(_cg_program[SHADER_type_vert]);
+    cgGLLoadProgram(_cg_program[SHADER_type_frag]);
     
     
     cerr << s->_file << ": compiled ok.\n";
     cerr << s->_file << ": compiled ok.\n";
     return;
     return;
@@ -137,10 +118,10 @@ release_resources() {
   if (_cg_context) {
   if (_cg_context) {
     cgDestroyContext(_cg_context);
     cgDestroyContext(_cg_context);
     _cg_context = (CGcontext)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;
+    _cg_profile[SHADER_type_vert] = (CGprofile)0;
+    _cg_profile[SHADER_type_frag] = (CGprofile)0;
+    _cg_program[SHADER_type_vert] = (CGprogram)0;
+    _cg_program[SHADER_type_frag] = (CGprogram)0;
   }
   }
 #endif
 #endif
 }
 }
@@ -148,71 +129,247 @@ release_resources() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLShaderContext::bind
 //     Function: GLShaderContext::bind
 //       Access: Public
 //       Access: Public
-//  Description: xyz
+//  Description: This function is to be called to enable a new
+//               shader.  It also initializes all of the shader's
+//               input parameters.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(ShaderContext)::
 void CLP(ShaderContext)::
-bind(ShaderMode *m, GraphicsStateGuardianBase *gsg) {
+bind(ShaderMode *m, GSG *gsg) {
 #ifdef HAVE_CGGL
 #ifdef HAVE_CGGL
   if (_cg_context != 0) {
   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);
-    }
-  
+    // Pass in k-parameters and transform-parameters
+    issue_parameters(m, gsg);
+    issue_transform(m, gsg);
+    
     // Bind the shaders.
     // 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;
+    cgGLEnableProfile(_cg_profile[SHADER_type_vert]);
+    cgGLBindProgram(_cg_program[SHADER_type_vert]);
+    cgGLEnableProfile(_cg_profile[SHADER_type_frag]);
+    cgGLBindProgram(_cg_program[SHADER_type_frag]);
+  }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLShaderContext::unbind
+//       Access: Public
+//  Description: This function disables a currently-bound shader.
+////////////////////////////////////////////////////////////////////
+void CLP(ShaderContext)::
+unbind()
+{
+#ifdef HAVE_CGGL
+  if (_cg_context != 0) {
+    cgGLDisableProfile(_cg_profile[SHADER_type_vert]);
+    cgGLDisableProfile(_cg_profile[SHADER_type_frag]);
+  }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLShaderContext::issue_parameters
+//       Access: Public
+//  Description: This function is to be called whenever
+//               the ShaderMode has changed, but the Shader
+//               itself has not changed.  It loads the new
+//               input parameters into the already-bound shader.
+////////////////////////////////////////////////////////////////////
+void CLP(ShaderContext)::
+issue_parameters(ShaderMode *m, GSG *gsg)
+{
+#ifdef HAVE_CGGL
+  if (_cg_context != 0) {
+    // Pass in k-float parameters.
+    for (int i=0; i<(int)_cg_fbind.size(); i++) {
+      int index = _cg_fbind[i].argindex;
       if (index >= (int)m->_args.size()) continue;
       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);
+      if (m->_args[index]._type != ShaderModeArg::SAT_FLOAT) continue;
+      cgGLSetParameter4dv(_cg_fbind[i].parameter, m->_args[index]._fvalue.get_data());
     }
     }
+
+    // Pass in k-float4x4 parameters.
+    for (int i=0; i<(int)_cg_npbind.size(); i++) {
+      int index = _cg_npbind[i].argindex;
+      if (index >= (int)m->_args.size()) continue;
+      if (m->_args[index]._type != ShaderModeArg::SAT_NODEPATH) continue;
+      const float *dat = m->_args[index]._nvalue.node()->get_transform()->get_mat().get_data();
+      cgGLSetMatrixParameterfc(_cg_npbind[i].parameter, dat);
+    }
+    
+    // Pass in trans,tpose,row,col,xvec,yvec,zvec,pos parameters
+    for (int i=0; i<(int)_cg_parameter_bind.size(); i++)
+      bind_cg_transform(_cg_parameter_bind[i], m, gsg);
+
+    // Pass in trans,tpose,row,col,xvec,yvec,zvec,pos parameters
+    for (int i=0; i<(int)_cg_transform_bind.size(); i++)
+      bind_cg_transform(_cg_transform_bind[i], m, gsg);
   }
   }
 #endif
 #endif
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLShaderContext::unbind
+//     Function: GLShaderContext::issue_transform
 //       Access: Public
 //       Access: Public
-//  Description: xyz
+//  Description: This function is to be called whenever
+//               the external_transform has changed, but the
+//               Shader itself has not changed.  It loads the 
+//               new transform into the already-bound shader.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(ShaderContext)::
 void CLP(ShaderContext)::
-unbind() {
+issue_transform(ShaderMode *m, GSG *gsg)
+{
 #ifdef HAVE_CGGL
 #ifdef HAVE_CGGL
   if (_cg_context != 0) {
   if (_cg_context != 0) {
-    // Disable texture parameters.
-    for (int i=0; i<(int)_cg_tbind2d.size(); i++)
-      cgGLDisableTextureParameter(_cg_tbind2d[i].parameter);
+    // Pass in modelview, projection, etc.
+    for (int i=0; i<(int)_cg_autobind.size(); i++)
+      cgGLSetStateMatrixParameter(_cg_autobind[i].parameter,
+                                  _cg_autobind[i].matrix,
+                                  _cg_autobind[i].orient);
     
     
-    cgGLDisableProfile(_cg_profile[VERT_SHADER]);
-    cgGLDisableProfile(_cg_profile[FRAG_SHADER]);
+    // Pass in trans,tpose,row,col,xvec,yvec,zvec,pos parameters
+    for (int i=0; i<(int)_cg_transform_bind.size(); i++)
+      bind_cg_transform(_cg_transform_bind[i], m, gsg);
   }
   }
 #endif
 #endif
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLShaderContext::rebind
+//     Function: GLShaderContext::disable_shader_vertex_arrays
 //       Access: Public
 //       Access: Public
-//  Description: xyz
+//  Description: Disable all the vertex arrays used by this shader.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(ShaderContext)::
 void CLP(ShaderContext)::
-rebind(ShaderMode *oldmode, ShaderMode *newmode) {
+disable_shader_vertex_arrays(GSG *gsg)
+{
+#ifdef HAVE_CGGL
+  if (_cg_context)
+    for (int i=0; i<(int)_cg_varying.size(); i++)
+      cgGLDisableClientState(_cg_varying[i].parameter);
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLShaderContext::update_shader_vertex_arrays
+//       Access: Public
+//  Description: Disables all vertex arrays used by the previous
+//               shader, then enables all the vertex arrays needed
+//               by this shader.  Extracts the relevant vertex array
+//               data from the gsg.
+//               The current implementation is inefficient, because
+//               it may unnecessarily disable arrays then immediately
+//               reenable them.  We may optimize this someday.
+////////////////////////////////////////////////////////////////////
+void CLP(ShaderContext)::
+update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg)
+{
+  if (prev) prev->disable_shader_vertex_arrays(gsg);
+#ifdef HAVE_CGGL
+  if (_cg_context) {
+#ifdef SUPPORT_IMMEDIATE_MODE
+    if (_use_sender) {
+      cerr << "immediate mode shaders not implemented yet\n";
+    } else
+#endif // SUPPORT_IMMEDIATE_MODE
+    {
+      const GeomVertexArrayData *array_data;
+      Geom::NumericType numeric_type;
+      int start, stride, num_values;
+      int nvarying = _cg_varying.size();
+      for (int i=0; i<nvarying; i++) {
+        InternalName *name = _cg_varying[i].name;
+        int texslot = _cg_varying[i].append_uv;
+        if (texslot >= 0) {
+          const Geom::ActiveTextureStages &active_stages = 
+            gsg->_current_texture->get_on_stages();
+          if (texslot < (int)active_stages.size()) {
+            TextureStage *stage = active_stages[texslot];
+            const InternalName *slotname = stage->get_texcoord_name();
+            name = name->append(slotname->get_name());
+          }
+        }
+        if (gsg->_vertex_data->get_array_info(name,
+                                              array_data, num_values, numeric_type, 
+                                              start, stride)) {
+          const unsigned char *client_pointer = gsg->setup_array_data(array_data);
+          cgGLSetParameterPointer(_cg_varying[i].parameter,
+                                  num_values, gsg->get_numeric_type(numeric_type),
+                                  stride, client_pointer + start);
+          cgGLEnableClientState(_cg_varying[i].parameter);
+        } else {
+          cgGLDisableClientState(_cg_varying[i].parameter);
+        }
+      }
+    }
+  }
+#endif // HAVE_CGGL
 }
 }
 
 
 #ifdef HAVE_CGGL
 #ifdef HAVE_CGGL
+////////////////////////////////////////////////////////////////////
+//     Function: GLShaderContext::bind_cg_transform
+//       Access: Public
+//  Description: Should deallocate all system resources (such as
+//               vertex program handles or Cg contexts).
+////////////////////////////////////////////////////////////////////
+void CLP(ShaderContext)::
+bind_cg_transform(const ShaderTransBind &stb, ShaderMode *m, GSG *gsg)
+{
+  CPT(TransformState) src;
+  CPT(TransformState) rel;
+  
+  if (stb.src_argindex < 0) {
+    if (stb.src_argindex == SHADER_arg_camera)
+      src = TransformState::make_identity();
+    else if (stb.src_argindex == SHADER_arg_model)
+      src = gsg->get_transform();
+    else
+      src = gsg->get_scene()->get_world_transform();
+  } else {
+    if ((int)m->_args.size() > stb.src_argindex) {
+      ShaderModeArg *arg = &(m->_args[stb.src_argindex]);
+      if (arg->_type == ShaderModeArg::SAT_NODEPATH)
+        src = gsg->get_scene()->get_world_transform()->compose(arg->_nvalue.get_net_transform());
+    }
+  }
+
+  if (stb.rel_argindex < 0) {
+    if (stb.rel_argindex == SHADER_arg_camera)
+      rel = TransformState::make_identity();
+    else if (stb.rel_argindex == SHADER_arg_model)
+      rel = gsg->get_transform();
+    else
+      rel = gsg->get_scene()->get_world_transform();
+  } else {
+    if ((int)m->_args.size() > stb.rel_argindex) {
+      ShaderModeArg *arg = &(m->_args[stb.rel_argindex]);
+      if (arg->_type == ShaderModeArg::SAT_NODEPATH)
+        rel = gsg->get_scene()->get_world_transform()->compose(arg->_nvalue.get_net_transform());
+    }
+  }
+  
+  CPT(TransformState) total = rel->invert_compose(src);
+  const float *data = total->get_mat().get_data();
+  //  cerr << "Input for " << cgGetParameterName(stb.parameter) << " is\n" << 
+  //    data[ 0] << " " << data[ 1] << " " << data[ 2] << " " << data[ 3] << "\n" <<
+  //    data[ 4] << " " << data[ 5] << " " << data[ 6] << " " << data[ 7] << "\n" <<
+  //    data[ 8] << " " << data[ 9] << " " << data[10] << " " << data[11] << "\n" <<
+  //    data[12] << " " << data[13] << " " << data[14] << " " << data[15] << "\n";
+
+  switch (stb.trans_piece) {
+  case SHADER_data_matrix: cgGLSetMatrixParameterfc(stb.parameter, data); break;
+  case SHADER_data_transpose:  cgGLSetMatrixParameterfr(stb.parameter, data); break;
+  case SHADER_data_row0: cgGLSetParameter4fv(stb.parameter, data+ 0); break;
+  case SHADER_data_row1: cgGLSetParameter4fv(stb.parameter, data+ 4); break;
+  case SHADER_data_row2: cgGLSetParameter4fv(stb.parameter, data+ 8); break;
+  case SHADER_data_row3: cgGLSetParameter4fv(stb.parameter, data+12); break;
+  case SHADER_data_col0: cgGLSetParameter4f(stb.parameter, data[0], data[4], data[ 8], data[12]); break;
+  case SHADER_data_col1: cgGLSetParameter4f(stb.parameter, data[1], data[5], data[ 9], data[13]); break;
+  case SHADER_data_col2: cgGLSetParameter4f(stb.parameter, data[2], data[6], data[10], data[14]); break;
+  case SHADER_data_col3: cgGLSetParameter4f(stb.parameter, data[3], data[7], data[11], data[15]); break;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Shader::errchk_cg_parameter_words
 //     Function: Shader::errchk_cg_parameter_words
 //       Access: Public, Static
 //       Access: Public, Static
@@ -291,28 +448,6 @@ errchk_cg_parameter_prog(CGparameter p, CGprogram prog, const string &msg)
   return true;
   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
 //     Function: Shader::errchk_cg_parameter_type
 //       Access: Public, Static
 //       Access: Public, Static
@@ -368,7 +503,7 @@ errchk_cg_parameter_sampler(CGparameter p)
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: Shader::errchk_cg_parameter_direction
+//     Function: Shader::errchk_cg_output
 //       Access: Public, Static
 //       Access: Public, Static
 //  Description: Print an error message including a description
 //  Description: Print an error message including a description
 //               of the specified Cg parameter.
 //               of the specified Cg parameter.
@@ -389,18 +524,42 @@ errchk_cg_output(CGparameter p, const string &msg)
   if (d == CG_INOUT) dstr = "inout ";
   if (d == CG_INOUT) dstr = "inout ";
   
   
   const char *ts = cgGetTypeString(cgGetParameterType(p));
   const char *ts = cgGetTypeString(cgGetParameterType(p));
-  const char *ss = cgGetParameterSemantic(p);
   
   
   string err;
   string err;
   string fn = _shader->_file;
   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";
-  }
+  err = fn + ": " + msg + " (" + vstr + dstr + ts + " " + cgGetParameterName(p) + ")\n";
   cerr << err << "\n";
   cerr << err << "\n";
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::print_cg_compile_errors
+//       Access: Public, Static
+//  Description: Used only after a Cg compile command, to print
+//               out any error messages that may have occurred
+//               during the Cg shader compilation.  The 'file'
+//               is the name of the file containing the Cg code.
+////////////////////////////////////////////////////////////////////
+void CLP(ShaderContext)::
+print_cg_compile_errors(const string &file, CGcontext ctx)
+{
+  CGerror err = cgGetError();
+  if (err != CG_NO_ERROR) {
+    if (err == CG_COMPILER_ERROR) {
+      string listing = cgGetLastListing(ctx);
+      vector_string errlines;
+      tokenize(listing, errlines, "\n");
+      for (int i=0; i<(int)errlines.size(); i++) {
+        string line = trim(errlines[i]);
+        if (line != "") {
+          cerr << file << " " << errlines[i] << "\n";
+        }
+      }
+    } else {
+      cerr << file << ": " << cgGetErrorString(err) << "\n";
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLShaderContext::compile_cg_parameter
 //     Function: GLShaderContext::compile_cg_parameter
 //       Access: Public
 //       Access: Public
@@ -417,38 +576,52 @@ compile_cg_parameter(CGparameter p)
   if (pname[0] == '$') return true;
   if (pname[0] == '$') return true;
   vector_string pieces;
   vector_string pieces;
   tokenize(pname, pieces, "_");
   tokenize(pname, pieces, "_");
+
+  if (pieces.size() < 2) {
+    errchk_cg_output(p,"invalid parameter name");
+    return false;
+  }
   
   
   if (pieces[0] == "vtx") {
   if (pieces[0] == "vtx") {
-    if ((!errchk_cg_parameter_words(p,2)) ||
-        (!errchk_cg_parameter_direction(p, CG_IN)) ||
+    if ((!errchk_cg_parameter_direction(p, CG_IN)) ||
         (!errchk_cg_parameter_variance(p, CG_VARYING)) ||
         (!errchk_cg_parameter_variance(p, CG_VARYING)) ||
-        (!errchk_cg_parameter_prog(p, _cg_program[VERT_SHADER], "vertex")))
+        (!errchk_cg_parameter_float(p)) ||
+        (!errchk_cg_parameter_prog(p, _cg_program[SHADER_type_vert], "vertex")))
       return false;
       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.
+    ShaderVarying bind;
+    bind.parameter = p;
+    if (pieces.size() == 2) {
+      if (pieces[1]=="position") {
+        bind.name = InternalName::get_vertex();
+        bind.append_uv = -1;
+        _cg_varying.push_back(bind);
+        return true;
+      }
+      if (pieces[1].substr(0,8)=="texcoord") {
+        bind.name = InternalName::get_root();
+        bind.append_uv = atoi(pieces[1].c_str()+8);
+        _cg_varying.push_back(bind);
+        return true;
+      }
+      if (pieces[1].substr(0,7)=="tangent") {
+        bind.name = InternalName::get_tangent();
+        bind.append_uv = atoi(pieces[1].c_str()+7);
+        _cg_varying.push_back(bind);
+        return true;
+      }
+      if (pieces[1].substr(0,8)=="binormal") {
+        bind.name = InternalName::get_binormal();
+        bind.append_uv = atoi(pieces[1].c_str()+8);
+        _cg_varying.push_back(bind);
+        return true;
+      }
     }
     }
-    // Handle an arbitrary column taken from the vertex array.
-    // IMPLEMENT ME.
-    errchk_cg_output(p, "Arbitrary vertex fields not implemented yet");
-    return false;
+    bind.name = InternalName::get_root();
+    bind.append_uv = -1;
+    for (int i=1; i<(int)(pieces.size()-0); i++)
+      bind.name = bind.name->append(pieces[i]);
+    _cg_varying.push_back(bind);
+    return true;
   }
   }
   
   
   if ((pieces[0] == "trans")||
   if ((pieces[0] == "trans")||
@@ -460,57 +633,48 @@ compile_cg_parameter(CGparameter p)
       (pieces[0] == "col0")||
       (pieces[0] == "col0")||
       (pieces[0] == "col1")||
       (pieces[0] == "col1")||
       (pieces[0] == "col2")||
       (pieces[0] == "col2")||
-      (pieces[0] == "col3")||
-      (pieces[0] == "xvec")||
-      (pieces[0] == "yvec")||
-      (pieces[0] == "zvec")||
-      (pieces[0] == "pos")) {
+      (pieces[0] == "col3")) {
     if ((!errchk_cg_parameter_words(p,4)) ||
     if ((!errchk_cg_parameter_words(p,4)) ||
         (!errchk_cg_parameter_direction(p, CG_IN)) ||
         (!errchk_cg_parameter_direction(p, CG_IN)) ||
-        (!errchk_cg_parameter_variance(p, CG_UNIFORM)) ||
-        (!errchk_cg_parameter_semantic(p, "")))
+        (!errchk_cg_parameter_variance(p, CG_UNIFORM)))
       return false;
       return false;
-    if (pieces[2] != "rel") {
+    if ((pieces[2] != "rel")&&(pieces[2] != "to")) {
       errchk_cg_output(p, "syntax error");
       errchk_cg_output(p, "syntax error");
       return false;
       return false;
     }
     }
     ShaderTransBind bind;
     ShaderTransBind bind;
     bind.parameter = p;
     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;
+    if      (pieces[0]=="trans") bind.trans_piece = SHADER_data_matrix;
+    else if (pieces[0]=="tpose") bind.trans_piece = SHADER_data_transpose;
+    else if (pieces[0]=="row0") bind.trans_piece = SHADER_data_row0;
+    else if (pieces[0]=="row1") bind.trans_piece = SHADER_data_row1;
+    else if (pieces[0]=="row2") bind.trans_piece = SHADER_data_row2;
+    else if (pieces[0]=="row3") bind.trans_piece = SHADER_data_row3;
+    else if (pieces[0]=="col0") bind.trans_piece = SHADER_data_col0;
+    else if (pieces[0]=="col1") bind.trans_piece = SHADER_data_col1;
+    else if (pieces[0]=="col2") bind.trans_piece = SHADER_data_col2;
+    else if (pieces[0]=="col3") bind.trans_piece = SHADER_data_col3;
+
+    if      (pieces[1] == "world")  bind.src_argindex = SHADER_arg_world;
+    else if (pieces[1] == "camera") bind.src_argindex = SHADER_arg_camera;
+    else if (pieces[1] == "model")  bind.src_argindex = SHADER_arg_model;
     else bind.src_argindex = _shader->arg_index(pieces[1]);
     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;
+    if      (pieces[3] == "world")  bind.rel_argindex = SHADER_arg_world;
+    else if (pieces[3] == "camera") bind.rel_argindex = SHADER_arg_camera;
+    else if (pieces[3] == "model")  bind.rel_argindex = SHADER_arg_model;
     else bind.rel_argindex = _shader->arg_index(pieces[3]);
     else bind.rel_argindex = _shader->arg_index(pieces[3]);
 
 
-    if ((bind.trans_piece == TRANS_NORMAL)||(bind.trans_piece == TRANS_TPOSE)) {
+    if ((bind.trans_piece == SHADER_data_matrix)||(bind.trans_piece == SHADER_data_transpose)) {
       if (!errchk_cg_parameter_type(p, CG_FLOAT4x4)) return false;
       if (!errchk_cg_parameter_type(p, CG_FLOAT4x4)) return false;
     } else {
     } else {
       if (!errchk_cg_parameter_type(p, CG_FLOAT4)) return false;
       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);
+    _cg_parameter_bind.push_back(bind);
+    if ((bind.src_argindex == SHADER_arg_model) ||
+        (bind.rel_argindex == SHADER_arg_model)) {
+      _cg_transform_bind.push_back(bind);
     }
     }
     return true;
     return true;
   }
   }
@@ -523,34 +687,32 @@ compile_cg_parameter(CGparameter p)
       (pieces[0]=="wspos")) {
       (pieces[0]=="wspos")) {
     if ((!errchk_cg_parameter_words(p,2)) ||
     if ((!errchk_cg_parameter_words(p,2)) ||
         (!errchk_cg_parameter_direction(p, CG_IN)) ||
         (!errchk_cg_parameter_direction(p, CG_IN)) ||
-        (!errchk_cg_parameter_variance(p, CG_UNIFORM)) ||
-        (!errchk_cg_parameter_semantic(p, "")))
+        (!errchk_cg_parameter_variance(p, CG_UNIFORM)))
       return false;
       return false;
     ShaderTransBind bind;
     ShaderTransBind bind;
     bind.parameter = p;
     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[0]=="wstrans") { bind.rel_argindex = SHADER_arg_world;  bind.trans_piece = SHADER_data_matrix; }
+    else if (pieces[0]=="cstrans") { bind.rel_argindex = SHADER_arg_camera; bind.trans_piece = SHADER_data_matrix; }
+    else if (pieces[0]=="mstrans") { bind.rel_argindex = SHADER_arg_model;  bind.trans_piece = SHADER_data_matrix; }
+    else if (pieces[0]=="wspos")   { bind.rel_argindex = SHADER_arg_world;  bind.trans_piece = SHADER_data_row3; }
+    else if (pieces[0]=="cspos")   { bind.rel_argindex = SHADER_arg_camera; bind.trans_piece = SHADER_data_row3; }
+    else if (pieces[0]=="mspos")   { bind.rel_argindex = SHADER_arg_model;  bind.trans_piece = SHADER_data_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;
+    if      (pieces[1] == "world")  bind.src_argindex = SHADER_arg_world;
+    else if (pieces[1] == "camera") bind.src_argindex = SHADER_arg_camera;
+    else if (pieces[1] == "model")  bind.src_argindex = SHADER_arg_model;
     else bind.src_argindex = _shader->arg_index(pieces[1]);
     else bind.src_argindex = _shader->arg_index(pieces[1]);
     
     
-    if ((bind.trans_piece == TRANS_NORMAL)||(bind.trans_piece == TRANS_TPOSE)) {
+    if ((bind.trans_piece == SHADER_data_matrix)||(bind.trans_piece == SHADER_data_transpose)) {
       if (!errchk_cg_parameter_type(p, CG_FLOAT4x4)) return false;
       if (!errchk_cg_parameter_type(p, CG_FLOAT4x4)) return false;
     } else {
     } else {
       if (!errchk_cg_parameter_type(p, CG_FLOAT4)) return false;
       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);
-    }
+    _cg_parameter_bind.push_back(bind);
+    if ((bind.src_argindex == SHADER_arg_model) ||
+        (bind.rel_argindex == SHADER_arg_model))
+      _cg_transform_bind.push_back(bind);
     return true;
     return true;
   }
   }
 
 
@@ -573,10 +735,10 @@ compile_cg_parameter(CGparameter p)
       errchk_cg_output(p, "unrecognized matrix name");
       errchk_cg_output(p, "unrecognized matrix name");
       return false;
       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;
+    if      (pieces[0]=="mat") bind.orient = CG_GL_MATRIX_IDENTITY;
+    else if (pieces[0]=="inv") bind.orient = CG_GL_MATRIX_INVERSE;
+    else if (pieces[0]=="tps") bind.orient = CG_GL_MATRIX_TRANSPOSE;
+    else if (pieces[0]=="itp") bind.orient = CG_GL_MATRIX_INVERSE_TRANSPOSE;
     _cg_autobind.push_back(bind);
     _cg_autobind.push_back(bind);
     return true;
     return true;
   }
   }
@@ -587,10 +749,7 @@ compile_cg_parameter(CGparameter p)
         (!errchk_cg_parameter_variance(p, CG_UNIFORM)) ||
         (!errchk_cg_parameter_variance(p, CG_UNIFORM)) ||
         (!errchk_cg_parameter_sampler(p)))
         (!errchk_cg_parameter_sampler(p)))
       return false;
       return false;
-    if (cgGetParameterSemantic(p)[0]!=0) {
-      string texunit = "TEX"+upcase(pieces[1]);
-      if (!errchk_cg_parameter_semantic(p, texunit)) return false;
-    }
+    // IMPLEMENT ME
     return true; // Cg handles this automatically.
     return true; // Cg handles this automatically.
   }
   }
 
 
@@ -603,10 +762,7 @@ compile_cg_parameter(CGparameter p)
     bind.parameter = p;
     bind.parameter = p;
     bind.argindex = _shader->arg_index(pieces[1]);
     bind.argindex = _shader->arg_index(pieces[1]);
     switch (cgGetParameterType(p)) {
     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_FLOAT4:    _cg_fbind.push_back(bind); break;
     case CG_SAMPLER2D: _cg_tbind2d.push_back(bind); break;
     case CG_SAMPLER2D: _cg_tbind2d.push_back(bind); break;
     case CG_SAMPLER3D: _cg_tbind3d.push_back(bind); break;
     case CG_SAMPLER3D: _cg_tbind3d.push_back(bind); break;
     case CG_FLOAT4x4:  _cg_npbind.push_back(bind); break;
     case CG_FLOAT4x4:  _cg_npbind.push_back(bind); break;
@@ -631,3 +787,4 @@ compile_cg_parameter(CGparameter p)
   return false;
   return false;
 }
 }
 #endif
 #endif
+

+ 23 - 29
panda/src/glstuff/glShaderContext_src.h

@@ -23,6 +23,8 @@
 #endif
 #endif
 #include "string_utils.h"
 #include "string_utils.h"
 
 
+class CLP(GraphicsStateGuardian);
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : GLShaderContext
 //       Class : GLShaderContext
 // Description : xyz
 // Description : xyz
@@ -32,36 +34,23 @@ class EXPCL_GL CLP(ShaderContext): public ShaderContext {
 public:
 public:
   CLP(ShaderContext)(Shader *s);
   CLP(ShaderContext)(Shader *s);
   ~CLP(ShaderContext)();
   ~CLP(ShaderContext)();
+  typedef CLP(GraphicsStateGuardian) GSG;
 
 
   INLINE bool valid(void);
   INLINE bool valid(void);
-  void bind(ShaderMode *mode, GraphicsStateGuardianBase *gsg);
+  void bind(ShaderMode *mode, GSG *gsg);
   void unbind();
   void unbind();
-  void rebind(ShaderMode *oldmode, ShaderMode *newmode);
+  void issue_parameters(ShaderMode *mode, GSG *gsg);
+  void issue_transform(ShaderMode *mode, GSG *gsg);
+  void disable_shader_vertex_arrays(GSG *gsg);
+  void update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg);
 
 
 private:
 private:
-  
+
 #ifdef HAVE_CGGL
 #ifdef HAVE_CGGL
-  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 {
   struct ShaderAutoBind {
     CGparameter parameter;
     CGparameter parameter;
     CGGLenum matrix;
     CGGLenum matrix;
-    CGGLenum orientation;
+    CGGLenum orient;
   };
   };
   struct ShaderArgBind {
   struct ShaderArgBind {
     CGparameter parameter;
     CGparameter parameter;
@@ -73,34 +62,39 @@ private:
     int rel_argindex;
     int rel_argindex;
     int trans_piece;
     int trans_piece;
   };
   };
+  struct ShaderVarying {
+    CGparameter parameter;
+    PT(InternalName) name;
+    int append_uv;
+  };
   CGcontext _cg_context;
   CGcontext _cg_context;
   CGprofile _cg_profile[2];
   CGprofile _cg_profile[2];
   CGprogram _cg_program[2];
   CGprogram _cg_program[2];
-  int       _cg_linebase[2];
   
   
   // These arrays contain lists of "bindings." They
   // These arrays contain lists of "bindings." They
   // tell us how to fill the shader's input parameters.
   // tell us how to fill the shader's input parameters.
   vector <ShaderAutoBind> _cg_autobind;
   vector <ShaderAutoBind> _cg_autobind;
   vector <ShaderArgBind> _cg_tbind2d;
   vector <ShaderArgBind> _cg_tbind2d;
   vector <ShaderArgBind> _cg_tbind3d;
   vector <ShaderArgBind> _cg_tbind3d;
-  vector <ShaderArgBind> _cg_vbind1;
-  vector <ShaderArgBind> _cg_vbind2;
-  vector <ShaderArgBind> _cg_vbind3;
-  vector <ShaderArgBind> _cg_vbind4;
+  vector <ShaderArgBind> _cg_fbind;
   vector <ShaderArgBind> _cg_npbind;
   vector <ShaderArgBind> _cg_npbind;
-  vector <ShaderTransBind> _cg_trans_bind;
-  vector <ShaderTransBind> _cg_trans_rebind;
+  vector <ShaderTransBind> _cg_transform_bind;
+  vector <ShaderTransBind> _cg_parameter_bind;
+  vector <ShaderVarying> _cg_varying;
+  
+  void bind_cg_transform(const ShaderTransBind &stb, ShaderMode *m,
+                         CLP(GraphicsStateGuardian) *gsg);
   
   
   bool compile_cg_parameter(CGparameter p);
   bool compile_cg_parameter(CGparameter p);
   bool errchk_cg_parameter_words(CGparameter p, int len);
   bool errchk_cg_parameter_words(CGparameter p, int len);
   bool errchk_cg_parameter_direction(CGparameter p, CGenum dir);
   bool errchk_cg_parameter_direction(CGparameter p, CGenum dir);
   bool errchk_cg_parameter_variance(CGparameter p, CGenum var);
   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_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_type(CGparameter p, CGtype dt);
   bool errchk_cg_parameter_float(CGparameter p);
   bool errchk_cg_parameter_float(CGparameter p);
   bool errchk_cg_parameter_sampler(CGparameter p);
   bool errchk_cg_parameter_sampler(CGparameter p);
   void errchk_cg_output(CGparameter p, const string &msg);
   void errchk_cg_output(CGparameter p, const string &msg);
+  void print_cg_compile_errors(const string &file, CGcontext ctx);
 #endif
 #endif
 
 
   void release_resources(void);
   void release_resources(void);

+ 26 - 5
panda/src/gobj/shaderContext.h

@@ -41,13 +41,34 @@ public:
   INLINE ShaderContext(Shader *shader);
   INLINE ShaderContext(Shader *shader);
   
   
   Shader *_shader;
   Shader *_shader;
-
+  
+public:
+  // The following declarations represent useful routines
+  // and constants that can be used by shader implementations.
+  
   enum {
   enum {
-    VERT_SHADER=0,
-    FRAG_SHADER=1,
-    BOTH_SHADER=2,
+    SHADER_type_vert=0,
+    SHADER_type_frag=1,
+    SHADER_type_both=2,
   };
   };
-  
+  enum {
+    SHADER_arg_world = -1,
+    SHADER_arg_camera = -2,
+    SHADER_arg_model = -3,
+  };
+  enum {
+    SHADER_data_matrix,
+    SHADER_data_transpose,
+    SHADER_data_row0,
+    SHADER_data_row1,
+    SHADER_data_row2,
+    SHADER_data_row3,
+    SHADER_data_col0,
+    SHADER_data_col1,
+    SHADER_data_col2,
+    SHADER_data_col3,
+  };
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

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

@@ -355,6 +355,25 @@ get_clip_plane() const {
   return _clip_plane;
   return _clip_plane;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::get_shader
+//       Access: Published
+//  Description: This function is provided as an optimization, to
+//               speed up the render-time checking for the existance
+//               of a ShaderAttrib on this state.  It returns a
+//               pointer to the ShaderAttrib, if there is one, or
+//               NULL if there is not.
+////////////////////////////////////////////////////////////////////
+INLINE const ShaderAttrib *RenderState::
+get_shader() const {
+  if ((_flags & F_checked_shader) == 0) {
+    // We pretend this function is const, even though it transparently
+    // modifies the internal shader cache.
+    ((RenderState *)this)->determine_shader();
+  }
+  return _shader;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::set_destructing
 //     Function: RenderState::set_destructing
 //       Access: Private
 //       Access: Private

+ 16 - 0
panda/src/pgraph/renderState.cxx

@@ -27,6 +27,7 @@
 #include "colorScaleAttrib.h"
 #include "colorScaleAttrib.h"
 #include "textureAttrib.h"
 #include "textureAttrib.h"
 #include "texGenAttrib.h"
 #include "texGenAttrib.h"
+#include "shaderAttrib.h"
 #include "pStatTimer.h"
 #include "pStatTimer.h"
 #include "config_pgraph.h"
 #include "config_pgraph.h"
 #include "bamReader.h"
 #include "bamReader.h"
@@ -1663,6 +1664,21 @@ determine_clip_plane() {
   _flags |= F_checked_clip_plane;
   _flags |= F_checked_clip_plane;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::determine_shader
+//       Access: Private
+//  Description: This is the private implementation of get_shader().
+////////////////////////////////////////////////////////////////////
+void RenderState::
+determine_shader() {
+  const RenderAttrib *attrib = get_attrib(ShaderAttrib::get_class_type());
+  _shader = (const ShaderAttrib *)NULL;
+  if (attrib != (const RenderAttrib *)NULL) {
+    _shader = DCAST(ShaderAttrib, attrib);
+  }
+  _flags |= F_checked_shader;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::update_pstats
 //     Function: RenderState::update_pstats
 //       Access: Private
 //       Access: Private

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

@@ -41,6 +41,7 @@ class ColorScaleAttrib;
 class TextureAttrib;
 class TextureAttrib;
 class TexGenAttrib;
 class TexGenAttrib;
 class ClipPlaneAttrib;
 class ClipPlaneAttrib;
+class ShaderAttrib;
 class FactoryParams;
 class FactoryParams;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -135,7 +136,8 @@ PUBLISHED:
   INLINE const TexMatrixAttrib *get_tex_matrix() const;
   INLINE const TexMatrixAttrib *get_tex_matrix() const;
   INLINE const RenderModeAttrib *get_render_mode() const;
   INLINE const RenderModeAttrib *get_render_mode() const;
   INLINE const ClipPlaneAttrib *get_clip_plane() const;
   INLINE const ClipPlaneAttrib *get_clip_plane() const;
-
+  INLINE const ShaderAttrib *get_shader() const;
+  
   int get_geom_rendering(int geom_rendering) const;
   int get_geom_rendering(int geom_rendering) const;
 
 
 public:
 public:
@@ -180,6 +182,7 @@ private:
   void determine_tex_matrix();
   void determine_tex_matrix();
   void determine_render_mode();
   void determine_render_mode();
   void determine_clip_plane();
   void determine_clip_plane();
+  void determine_shader();
 
 
   INLINE void set_destructing();
   INLINE void set_destructing();
   INLINE bool is_destructing() const;
   INLINE bool is_destructing() const;
@@ -278,7 +281,8 @@ private:
   const TexMatrixAttrib *_tex_matrix;
   const TexMatrixAttrib *_tex_matrix;
   const RenderModeAttrib *_render_mode;
   const RenderModeAttrib *_render_mode;
   const ClipPlaneAttrib *_clip_plane;
   const ClipPlaneAttrib *_clip_plane;
-
+  const ShaderAttrib *_shader;
+  
   enum Flags {
   enum Flags {
     F_checked_bin_index    = 0x0001,
     F_checked_bin_index    = 0x0001,
     F_checked_fog          = 0x0002,
     F_checked_fog          = 0x0002,
@@ -291,6 +295,7 @@ private:
     F_checked_tex_matrix   = 0x0100,
     F_checked_tex_matrix   = 0x0100,
     F_checked_render_mode  = 0x0200,
     F_checked_render_mode  = 0x0200,
     F_checked_clip_plane   = 0x0400,
     F_checked_clip_plane   = 0x0400,
+    F_checked_shader       = 0x0800,
     F_is_destructing       = 0x8000,
     F_is_destructing       = 0x8000,
   };
   };
   unsigned short _flags;
   unsigned short _flags;