2
0
Эх сурвалжийг харах

clean up shader code, add more debugging info, make shaders writable

rdb 12 жил өмнө
parent
commit
8ef24aa846

+ 11 - 2
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1790,11 +1790,20 @@ reset() {
   CGprofile vertex_profile;
   CGprofile pixel_profile;
 
-  vertex_profile = cgGLGetLatestProfile (CG_GL_VERTEX);
-  pixel_profile = cgGLGetLatestProfile (CG_GL_FRAGMENT);
+  vertex_profile = cgGLGetLatestProfile(CG_GL_VERTEX);
+  pixel_profile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
   if (GLCAT.is_debug()) {
     // Temp ifdef: this crashes Mesa.
 #ifndef OSMESA_MAJOR_VERSION
+    GLCAT.debug() << "Supported Cg profiles:\n";
+    int num_profiles = cgGetNumSupportedProfiles();
+    for (int i = 0; i < num_profiles; ++i) {
+      CGprofile profile = cgGetSupportedProfile(i);
+      if (cgGLIsProfileSupported(profile)) {
+        GLCAT.debug() << "  " << cgGetProfileString(profile) << "\n";
+      }
+    }
+
     GLCAT.debug()
       << "\nCg vertex profile = " << cgGetProfileString(vertex_profile) << "  id = " << vertex_profile
       << "\nCg pixel profile = " << cgGetProfileString(pixel_profile) << "  id = " << pixel_profile

+ 124 - 0
panda/src/gobj/shader.I

@@ -542,3 +542,127 @@ ShaderPtrData(const LMatrix3d &mat) :
   nassertv(sizeof(mat(0, 0)) * mat.get_num_components() == pta.size() * sizeof(pta[0]));
   memcpy(_ptr, mat.get_data(), sizeof(mat(0, 0)) * mat.get_num_components());
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::ShaderPtrData::write_datagram
+//       Access: Public
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+INLINE void Shader::ShaderPtrData::
+write_datagram(Datagram &dg) const {
+  dg.add_uint8(_type);
+  dg.add_uint32(_size);
+
+  if (_type == SPT_double) {
+    const double *data = (const double *) _ptr;
+    for (size_t i = 0; i < _size; ++i) {
+      dg.add_float64(data[i]);
+    }
+
+  } else if (_type == SPT_float) {
+    const float *data = (const float *) _ptr;
+    for (size_t i = 0; i < _size; ++i) {
+      dg.add_float32(data[i]);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::ShaderPtrData::write_datagram
+//       Access: Public
+//  Description: Reads the object from a Datagram.
+////////////////////////////////////////////////////////////////////
+INLINE void Shader::ShaderPtrData::
+read_datagram(DatagramIterator &scan) {
+  _type = (ShaderPtrType) scan.get_uint8();
+  _size = scan.get_uint32();
+
+  if (_type == SPT_double) {
+    PTA_double pta = PTA_double::empty_array(_size);
+    for (size_t i = 0; i < _size; ++i) {
+      pta[i] = scan.get_float64();
+    }
+    _pta = pta.v0();
+    _ptr = pta.p();
+
+  } else if (_type == SPT_float) {
+    PTA_float pta = PTA_float::empty_array(_size);
+    for (size_t i = 0; i < _size; ++i) {
+      pta[i] = scan.get_float32();
+    }
+    _pta = pta.v0();
+    _ptr = pta.p();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::ShaderFile::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE Shader::ShaderFile::
+ShaderFile(const string &shared) :
+  _separate(false),
+  _shared(shared)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::ShaderFile::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE Shader::ShaderFile::
+ShaderFile(const string &vertex, 
+           const string &fragment, 
+           const string &geometry,
+           const string &tess_control,
+           const string &tess_evaluation) :
+  _separate(false),
+  _vertex(vertex),
+  _fragment(fragment),
+  _geometry(geometry),
+  _tess_control(tess_control),
+  _tess_evaluation(tess_evaluation)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::ShaderFile::write_datagram
+//       Access: Public
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+INLINE void Shader::ShaderFile::
+write_datagram(Datagram &dg) const {
+  dg.add_bool(_separate);
+  if (_separate) {
+    dg.add_string(_vertex);
+    dg.add_string(_fragment);
+    dg.add_string(_geometry);
+    dg.add_string(_tess_control);
+    dg.add_string(_tess_evaluation);
+  } else {
+    dg.add_string(_shared);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::ShaderFile::write_datagram
+//       Access: Public
+//  Description: Reads the object from a Datagram.
+////////////////////////////////////////////////////////////////////
+INLINE void Shader::ShaderFile::
+read_datagram(DatagramIterator &scan) {
+  _separate = scan.get_bool();
+  if (_separate) {
+    _vertex = scan.get_string();
+    _fragment = scan.get_string();
+    _geometry = scan.get_string();
+    _tess_control = scan.get_string();
+    _tess_evaluation = scan.get_string();
+  } else {
+    _shared = scan.get_string();
+  }
+}

+ 155 - 42
panda/src/gobj/shader.cxx

@@ -1405,6 +1405,22 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
   compiler_args[nargs] = 0;
 
   if ((active != (int)CG_PROFILE_UNKNOWN) && (active != ultimate)) {
+    // Print out some debug information about what we're doing.
+    if (gobj_cat.is_debug()) {
+      gobj_cat.debug()
+        << "Compiling Cg shader " << get_filename(type) << " with entry point " << entry
+        << " and active profile " << cgGetProfileString((CGprofile) active) << "\n";
+
+      if (nargs > 0) {
+        gobj_cat.debug() << "Using compiler arguments:";
+        for (int i = 0; i < nargs; ++i) {
+          gobj_cat.debug(false) << " " << compiler_args[i];
+        }
+        gobj_cat.debug(false) << "\n";
+      }
+    }
+
+    // Compile the shader with the active profile.
     prog = cgCreateProgram(_cg_context, CG_SOURCE, text.c_str(),
                            (CGprofile)active, entry, (const char **)compiler_args);
     err = cgGetError();
@@ -1414,8 +1430,19 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
     if (prog != 0) {
       cgDestroyProgram(prog);
     }
+    if (gobj_cat.is_debug()) {
+      gobj_cat.debug()
+        << "Compilation with active profile failed: " << cgGetErrorString(err) << "\n";
+    }
   }
 
+  if (gobj_cat.is_debug()) {
+    gobj_cat.debug()
+      << "Compiling Cg shader " << get_filename(type) << " with entry point " << entry
+      << " and ultimate profile " << cgGetProfileString((CGprofile) ultimate) << "\n";
+  }
+
+  // The active profile failed, so recompile it with the ultimate profile.
   prog = cgCreateProgram(_cg_context, CG_SOURCE, text.c_str(),
                          (CGprofile)ultimate, entry, (const char **)NULL);
   err = cgGetError();
@@ -1423,10 +1450,11 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
     return prog;
   }
   if (err == CG_COMPILER_ERROR) {
+    // A compiler error has occurred.  Extract the error messages.
     string listing = cgGetLastListing(_cg_context);
     vector_string errlines;
     tokenize(listing, errlines, "\n");
-    for (int i=0; i<(int)errlines.size(); i++) {
+    for (int i = 0; i < (int) errlines.size(); ++i) {
       string line = trim(errlines[i]);
       if (line != "") {
         gobj_cat.error() << get_filename(type) << ": " << errlines[i] << "\n";
@@ -1466,12 +1494,8 @@ cg_compile_shader(const ShaderCaps &caps) {
 
   _cg_context = cgCreateContext();
 
-  if (!_text->_separate) {
-    gobj_cat.debug() << "Compiling Shader: \n" << _text << "\n";
-  }
-
   if (_cg_context == 0) {
-    gobj_cat.error() << "could not create a Cg context object.\n";
+    gobj_cat.error() << "Could not create a Cg context object.\n";
     return false;
   }
 
@@ -1481,6 +1505,7 @@ cg_compile_shader(const ShaderCaps &caps) {
       cg_release_resources();
       return false;
     }
+    _cg_vprofile = cgGetProgramProfile(_cg_vprogram);
   }
 
   if (!_text->_separate || !_text->_fragment.empty()) {
@@ -1489,6 +1514,7 @@ cg_compile_shader(const ShaderCaps &caps) {
       cg_release_resources();
       return false;
     }
+    _cg_fprofile = cgGetProgramProfile(_cg_fprogram);
   }
 
   if ((_text->_separate && !_text->_geometry.empty()) || (!_text->_separate && _text->_shared.find("gshader") != string::npos)) {
@@ -1497,6 +1523,7 @@ cg_compile_shader(const ShaderCaps &caps) {
       cg_release_resources();
       return false;
     }
+    _cg_gprofile = cgGetProgramProfile(_cg_gprogram);
   }
 
   if (_cg_vprogram == 0 && _cg_fprogram == 0 && _cg_gprogram == 0) {
@@ -1508,19 +1535,25 @@ cg_compile_shader(const ShaderCaps &caps) {
   // DEBUG: output the generated program
   if (gobj_cat.is_debug()) {
     const char *vertex_program;
-    const char *pixel_program;
+    const char *fragment_program;
     const char *geometry_program;
 
     if (_cg_vprogram != 0) {
-      vertex_program   = cgGetProgramString (_cg_vprogram, CG_COMPILED_PROGRAM);
+      gobj_cat.debug()
+        << "Cg vertex profile: " << cgGetProfileString((CGprofile)_cg_vprofile) << "\n";
+      vertex_program = cgGetProgramString(_cg_vprogram, CG_COMPILED_PROGRAM);
       gobj_cat.debug() << vertex_program << "\n";
     }
     if (_cg_fprogram != 0) {
-      pixel_program    = cgGetProgramString (_cg_fprogram, CG_COMPILED_PROGRAM);
-      gobj_cat.debug() << pixel_program << "\n";
+      gobj_cat.debug()
+        << "Cg fragment profile: " << cgGetProfileString((CGprofile)_cg_fprofile) << "\n";
+      fragment_program = cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM);
+      gobj_cat.debug() << fragment_program << "\n";
     }
     if (_cg_gprogram != 0) {
-      geometry_program = cgGetProgramString (_cg_gprogram, CG_COMPILED_PROGRAM);
+      gobj_cat.debug()
+        << "Cg geometry profile: " << cgGetProfileString((CGprofile)_cg_gprofile) << "\n";
+      geometry_program = cgGetProgramString(_cg_gprogram, CG_COMPILED_PROGRAM);
       gobj_cat.debug() << geometry_program << "\n";
     }
   }
@@ -1752,7 +1785,6 @@ cg_compile_for(const ShaderCaps &caps,
                pvector<CGparameter> &map) {
 
   // Initialize the return values to empty.
-
   ctx = 0;
   vprogram = 0;
   fprogram = 0;
@@ -1771,31 +1803,23 @@ cg_compile_for(const ShaderCaps &caps,
   // If the compile routine used the ultimate profile instead of the
   // active one, it means the active one isn't powerful enough to
   // compile the shader.
-
-  if (_filename->_separate) {
-    if (_cg_vprogram != 0 && _cg_vprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_vprogram) != caps._active_vprofile) {
-      gobj_cat.error() << "Cg vprogram too complex for driver: "
-        << get_filename(ST_vertex) << ". Try choosing a different profile.\n";
-      return false;
-    }
-    if (_cg_fprogram != 0 && _cg_fprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_fprogram) != caps._active_fprofile) {
-      gobj_cat.error() << "Cg fprogram too complex for driver: "
-        << get_filename(ST_fragment) << ". Try choosing a different profile.\n";
-      return false;
-    }
-    if (_cg_gprogram != 0 && _cg_gprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_gprogram) != caps._active_gprofile) {
-      gobj_cat.error() << "Cg gprogram too complex for driver: "
-        << get_filename(ST_geometry) << ". Try choosing a different profile.\n";
-      return false;
-    }
-  } else {
-    if ((_cg_vprogram != 0 && _cg_vprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_vprogram) != caps._active_vprofile) ||
-        (_cg_fprogram != 0 && _cg_fprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_fprogram) != caps._active_fprofile) ||
-        (_cg_gprogram != 0 && _cg_gprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_gprogram) != caps._active_gprofile)) {
-      gobj_cat.error() << "Cg program too complex for driver: "
-        << get_filename() << ". Try choosing a different profile.\n";
-      return false;
-    }
+  if (_cg_vprogram != 0 && _cg_vprofile != caps._active_vprofile) {
+    gobj_cat.error() << "Cg vertex program not supported by profile "
+      << cgGetProfileString((CGprofile) caps._active_vprofile) << ": "
+      << get_filename(ST_vertex) << ". Try choosing a different profile.\n";
+    return false;
+  }
+  if (_cg_fprogram != 0 && _cg_fprofile != caps._active_fprofile) {
+    gobj_cat.error() << "Cg vertex program not supported by profile "
+      << cgGetProfileString((CGprofile) caps._active_fprofile) << ": "
+      << get_filename(ST_fragment) << ". Try choosing a different profile.\n";
+    return false;
+  }
+  if (_cg_gprogram != 0 && _cg_gprofile != caps._active_gprofile) {
+    gobj_cat.error() << "Cg vertex program not supported by profile "
+      << cgGetProfileString((CGprofile) caps._active_gprofile) << ": "
+      << get_filename(ST_fragment) << ". Try choosing a different profile.\n";
+    return false;
   }
 
   // Build a parameter map.
@@ -1854,6 +1878,43 @@ cg_compile_for(const ShaderCaps &caps,
 }
 #endif  // HAVE_CG
 
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::Constructor
+//       Access: Private
+//  Description: Construct a Shader that will be filled in using
+//               fillin() later.
+////////////////////////////////////////////////////////////////////
+Shader::
+Shader() :
+  _error_flag(false),
+  _text(NULL),
+  _filename(NULL),
+  _parse(0),
+  _loaded(false),
+  _language(SL_none)
+{
+#ifdef HAVE_CG
+  _cg_context = 0;
+  _cg_vprogram = 0;
+  _cg_fprogram = 0;
+  _cg_gprogram = 0;
+  _cg_vprofile = CG_PROFILE_UNKNOWN;
+  _cg_fprofile = CG_PROFILE_UNKNOWN;
+  _cg_gprofile = CG_PROFILE_UNKNOWN;
+  if (_default_caps._ultimate_vprofile == 0 || _default_caps._ultimate_vprofile == CG_PROFILE_UNKNOWN) {
+    _default_caps._active_vprofile = CG_PROFILE_UNKNOWN;
+    _default_caps._active_fprofile = CG_PROFILE_UNKNOWN;
+    _default_caps._active_gprofile = CG_PROFILE_UNKNOWN;
+    _default_caps._ultimate_vprofile = cgGetProfile("glslv");
+    _default_caps._ultimate_fprofile = cgGetProfile("glslf");
+    _default_caps._ultimate_gprofile = cgGetProfile("glslg");
+    if (_default_caps._ultimate_gprofile == CG_PROFILE_UNKNOWN) {
+      _default_caps._ultimate_gprofile = cgGetProfile("gp4gp");
+    }
+  }
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Shader::Constructor
 //       Access: Private
@@ -1861,15 +1922,13 @@ cg_compile_for(const ShaderCaps &caps,
 ////////////////////////////////////////////////////////////////////
 Shader::
 Shader(CPT(ShaderFile) filename, CPT(ShaderFile) text, const ShaderLanguage &lang) :
-  _error_flag(true),
+  _error_flag(false),
   _text(text),
   _filename(filename),
   _parse(0),
   _loaded(false),
   _language(lang)
 {
-  _error_flag = false;
-  
 #ifdef HAVE_CG
   _cg_context = 0;
   _cg_vprogram = 0;
@@ -2466,10 +2525,64 @@ clear() {
 ////////////////////////////////////////////////////////////////////
 //     Function: Shader::register_with_read_factory
 //       Access: Public, Static
-//  Description:
+//  Description: Tells the BamReader how to create objects of type
+//               Shader.
 ////////////////////////////////////////////////////////////////////
 void Shader::
 register_with_read_factory() {
-  // IMPLEMENT ME
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void Shader::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  dg.add_uint8(_language);
+  dg.add_bool(_loaded);
+  _filename->write_datagram(dg);
+  _text->write_datagram(dg);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type Shader is encountered
+//               in the Bam file.  It should create the Shader
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *Shader::
+make_from_bam(const FactoryParams &params) {
+  Shader *attrib = new Shader;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  attrib->fillin(scan, manager);
+  return attrib;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Shader::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new Shader.
+////////////////////////////////////////////////////////////////////
+void Shader::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  _language = (ShaderLanguage) scan.get_uint8();
+  _loaded = scan.get_bool();
+
+  PT(ShaderFile) filename = new ShaderFile;
+  filename->read_datagram(scan);
+  _filename = filename;
+
+  PT(ShaderFile) text = new ShaderFile;
+  text->read_datagram(scan);
+  _text = text;
+}

+ 57 - 58
panda/src/gobj/shader.h

@@ -16,7 +16,7 @@
 #define SHADER_H
 
 #include "pandabase.h"
-#include "typedReferenceCount.h"
+#include "typedWritableReferenceCount.h"
 #include "namable.h"
 #include "graphicsStateGuardianBase.h"
 #include "internalName.h"
@@ -44,10 +44,8 @@ typedef struct _CGparameter *CGparameter;
 //               finally compile and store the shader parameters  
 //               in the appropriate structure.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_GOBJ Shader: public TypedReferenceCount {
-
+class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount {
 PUBLISHED:
-  
   enum ShaderLanguage {
     SL_none,
     SL_Cg,
@@ -110,7 +108,6 @@ PUBLISHED:
                              GraphicsStateGuardianBase *gsg);
 
 public:
-
   enum ShaderMatInput {
     SMO_identity,
 
@@ -311,6 +308,9 @@ public:
     INLINE ShaderPtrData(const LVecBase2d &vec);
     INLINE ShaderPtrData(const LMatrix4d &mat);
     INLINE ShaderPtrData(const LMatrix3d &mat);
+
+    INLINE void write_datagram(Datagram &dg) const;
+    INLINE void read_datagram(DatagramIterator &source);
   };
 
   struct ShaderMatSpec {
@@ -372,22 +372,16 @@ public:
 
   class ShaderFile : public ReferenceCount {
   public:
-    ShaderFile(const string &shared) { 
-      _separate = false; 
-      _shared = shared; 
-    }
-    ShaderFile(const string &vertex, 
-               const string &fragment, 
-               const string &geometry,
-               const string &tess_control,
-               const string &tess_evaluation) {
-      _separate = true;
-      _vertex = vertex;
-      _fragment = fragment;
-      _geometry = geometry;
-      _tess_control = tess_control;
-      _tess_evaluation = tess_evaluation;
-    }
+    INLINE ShaderFile() {};
+    INLINE ShaderFile(const string &shared);
+    INLINE ShaderFile(const string &vertex, 
+                      const string &fragment, 
+                      const string &geometry,
+                      const string &tess_control,
+                      const string &tess_evaluation);
+
+    INLINE void write_datagram(Datagram &dg) const;
+    INLINE void read_datagram(DatagramIterator &source);
 
   public:
     bool _separate;
@@ -399,7 +393,7 @@ public:
     string _tess_evaluation;
   };
 
- public:
+public:
   // These routines help split the shader into sections,
   // for those shader implementations that need to do so.
   // Don't use them when you use separate shader programs.
@@ -446,23 +440,23 @@ public:
   void clear_parameters();
 
 #ifdef HAVE_CG
- private:
-  ShaderArgClass    cg_parameter_class(CGparameter p); 
-  ShaderArgType     cg_parameter_type(CGparameter p);
-  ShaderArgDir      cg_parameter_dir(CGparameter p);
+private:
+  ShaderArgClass cg_parameter_class(CGparameter p); 
+  ShaderArgType cg_parameter_type(CGparameter p);
+  ShaderArgDir cg_parameter_dir(CGparameter p);
 
-  CGprogram     cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType type = ST_vertex);
+  CGprogram cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType type = ST_vertex);
 
-  bool          cg_analyze_entry_point(CGprogram prog, ShaderType type);
+  bool cg_analyze_entry_point(CGprogram prog, ShaderType type);
 
-  bool          cg_analyze_shader(const ShaderCaps &caps);
-  bool          cg_compile_shader(const ShaderCaps &caps);
-  void          cg_release_resources();
-  void          cg_report_errors();
+  bool cg_analyze_shader(const ShaderCaps &caps);
+  bool cg_compile_shader(const ShaderCaps &caps);
+  void cg_release_resources();
+  void cg_report_errors();
   
   // Determines the appropriate cg profile settings and stores them in the active shader caps
   // based on any profile settings stored in the shader's header
-  void          cg_get_profile_from_header(ShaderCaps &caps);
+  void cg_get_profile_from_header(ShaderCaps &caps);
 
   ShaderCaps _cg_last_caps;
   CGcontext  _cg_context;
@@ -470,36 +464,33 @@ public:
   CGprogram  _cg_fprogram;
   CGprogram  _cg_gprogram;
 
-  int        _cg_vprofile;
-  int        _cg_fprofile;
-  int        _cg_gprofile;
+  int _cg_vprofile;
+  int _cg_fprofile;
+  int _cg_gprofile;
 
-  CGprogram     cg_program_from_shadertype(ShaderType type);
+  CGprogram cg_program_from_shadertype(ShaderType type);
 
- public:
+public:
 
-  bool          cg_compile_for(const ShaderCaps &caps,
-                               CGcontext &ctx,
-                               CGprogram &vprogram,
-                               CGprogram &fprogram,
-                               CGprogram &gprogram,
-                               pvector<CGparameter> &map);
+  bool cg_compile_for(const ShaderCaps &caps, CGcontext &ctx,
+                      CGprogram &vprogram, CGprogram &fprogram,
+                      CGprogram &gprogram, pvector<CGparameter> &map);
   
 #endif
 
- public:
+public:
   pvector <ShaderPtrSpec> _ptr_spec; 
   epvector <ShaderMatSpec> _mat_spec;
   pvector <ShaderTexSpec> _tex_spec;
   pvector <ShaderVarSpec> _var_spec;
   
-  bool           _error_flag;
+  bool _error_flag;
   CPT(ShaderFile) _text;
 
- protected:
+protected:
   CPT(ShaderFile) _filename; 
-  int            _parse;
-  bool           _loaded;
+  int _parse;
+  bool _loaded;
   ShaderLanguage _language;
   
   static ShaderCaps _default_caps;
@@ -517,30 +508,38 @@ public:
   typedef pmap <PreparedGraphicsObjects *, ShaderContext *> Contexts;
   Contexts _contexts;
 
- private:  
+private:  
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
 
- public:
+  Shader();
+
+public:
   Shader(CPT(ShaderFile) name, CPT(ShaderFile) text, const ShaderLanguage &lang = SL_none);
-  static void register_with_read_factory();
-  
   ~Shader();
-  
- public:
+
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
+public:
   static TypeHandle get_class_type() {
     return _type_handle;
   }
   static void init_type() {
-    TypedReferenceCount::init_type();
+    TypedWritableReferenceCount::init_type();
     register_type(_type_handle, "Shader",
-                  TypedReferenceCount::get_class_type());
+                  TypedWritableReferenceCount::get_class_type());
   }
   virtual TypeHandle get_type() const {
     return get_class_type();
   }
   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
 
- private:
+private:
   static TypeHandle _type_handle;
 };