Panda3D

shader.cxx

00001 // Filename: shader.cxx
00002 // Created by: jyelon (01Sep05)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "pandabase.h"
00016 #include "shader.h"
00017 #include "preparedGraphicsObjects.h"
00018 #include "virtualFileSystem.h"
00019 
00020 #ifdef HAVE_CG
00021 #include "Cg/cg.h"
00022 #define JCG_PROFILE_GLSLV ((CGprofile)7007)
00023 #define JCG_PROFILE_GLSLF ((CGprofile)7008)
00024 #endif
00025 
00026 TypeHandle Shader::_type_handle;
00027 Shader::ShaderTable Shader::_load_table;
00028 Shader::ShaderTable Shader::_make_table;
00029 Shader::ShaderCaps Shader::_default_caps;
00030 int Shader::_shaders_generated;
00031 ShaderUtilization Shader::_shader_utilization = SUT_UNSPECIFIED;
00032 
00033 ////////////////////////////////////////////////////////////////////
00034 //     Function: Shader::cp_report_error
00035 //       Access: Public
00036 //  Description: Generate an error message including a description
00037 //               of the specified parameter.
00038 ////////////////////////////////////////////////////////////////////
00039 void Shader::
00040 cp_report_error(ShaderArgInfo &p, const string &msg) {
00041   string vstr;
00042   if (p._varying) vstr = "varying ";
00043   else            vstr = "uniform ";
00044 
00045   string dstr = "unknown ";
00046   if (p._direction == SAD_in)    dstr = "in ";
00047   if (p._direction == SAD_out)   dstr = "out ";
00048   if (p._direction == SAD_inout) dstr = "inout ";
00049 
00050   string tstr = "invalid ";
00051   switch (p._type) {
00052   case SAT_float1: tstr = "float1 "; break;
00053   case SAT_float2: tstr = "float2 "; break;
00054   case SAT_float3: tstr = "float3 "; break;
00055   case SAT_float4: tstr = "float4 "; break;
00056   case SAT_float4x4: tstr = "float4x4 "; break;
00057   case SAT_sampler1d: tstr = "sampler1d "; break;
00058   case SAT_sampler2d: tstr = "sampler2d "; break;
00059   case SAT_sampler3d: tstr = "sampler3d "; break;
00060   case SAT_samplercube: tstr = "samplercube "; break;
00061   case SAT_unknown: tstr = "unknown "; break;
00062   }
00063 
00064   Filename fn = get_filename(p._id._type);
00065   p._cat->error() << fn << ": " << msg << " (" <<
00066     vstr << dstr << tstr << p._id._name << ")\n";
00067 }
00068 
00069 ////////////////////////////////////////////////////////////////////
00070 //     Function: Shader::cp_errchk_parameter_words
00071 //       Access: Public, Static
00072 //  Description: Make sure the provided parameter contains
00073 //               the specified number of words.  If not, print
00074 //               error message and return false.
00075 ////////////////////////////////////////////////////////////////////
00076 bool Shader::
00077 cp_errchk_parameter_words(ShaderArgInfo &p, int len)
00078 {
00079   vector_string words;
00080   tokenize(p._id._name, words, "_");
00081   if ((int)words.size() != len) {
00082     cp_report_error(p, "parameter name has wrong number of words");
00083     return false;
00084   }
00085   return true;
00086 }
00087 
00088 ////////////////////////////////////////////////////////////////////
00089 //     Function: Shader::cp_errchk_parameter_in
00090 //       Access: Public, Static
00091 //  Description: Make sure the provided parameter has the
00092 //               'in' direction.  If not, print
00093 //               error message and return false.
00094 ////////////////////////////////////////////////////////////////////
00095 bool Shader::
00096 cp_errchk_parameter_in(ShaderArgInfo &p)
00097 {
00098   if (p._direction != SAD_in) {
00099     cp_report_error(p, "parameter should be declared 'in'");
00100     return false;
00101   }
00102   return true;
00103 }
00104 
00105 ////////////////////////////////////////////////////////////////////
00106 //     Function: Shader::cp_errchk_parameter_varying
00107 //       Access: Public, Static
00108 //  Description: Make sure the provided parameter has the
00109 //               correct variance.  If not, print
00110 //               error message and return false.
00111 ////////////////////////////////////////////////////////////////////
00112 bool Shader::
00113 cp_errchk_parameter_varying(ShaderArgInfo &p)
00114 {
00115   if (!p._varying) {
00116     cp_report_error(p, "parameter should be declared 'varying'");
00117     return false;
00118   }
00119   return true;
00120 }
00121 
00122 ////////////////////////////////////////////////////////////////////
00123 //     Function: Shader::cp_errchk_parameter_uniform
00124 //       Access: Public, Static
00125 //  Description: Make sure the provided parameter has the
00126 //               correct variance.  If not, print
00127 //               error message and return false.
00128 ////////////////////////////////////////////////////////////////////
00129 bool Shader::
00130 cp_errchk_parameter_uniform(ShaderArgInfo &p)
00131 {
00132   if (p._varying) {
00133     cp_report_error(p, "parameter should be declared 'uniform'");
00134     return false;
00135   }
00136   return true;
00137 }
00138 
00139 ////////////////////////////////////////////////////////////////////
00140 //     Function: Shader::cp_errchk_parameter_float
00141 //       Access: Public, Static
00142 //  Description: Make sure the provided parameter has
00143 //               a floating point type.  If not, print
00144 //               error message and return false.
00145 ////////////////////////////////////////////////////////////////////
00146 bool Shader::
00147 cp_errchk_parameter_float(ShaderArgInfo &p, int lo, int hi)
00148 {
00149   int nfloat;
00150   switch (p._type) {
00151   case SAT_float1: nfloat = 1; break;
00152   case SAT_float2: nfloat = 2; break;
00153   case SAT_float3: nfloat = 3; break;
00154   case SAT_float4: nfloat = 4; break;
00155   case SAT_float4x4: nfloat = 16; break;
00156   default: nfloat = 0; break;
00157   }
00158   if ((nfloat < lo)||(nfloat > hi)) {
00159     string msg = "wrong type for parameter: should be float";
00160     cp_report_error(p, msg);
00161     return false;
00162   }
00163   return true;
00164 }
00165 
00166 ////////////////////////////////////////////////////////////////////
00167 //     Function: Shader::cp_errchk_parameter_sampler
00168 //       Access: Public, Static
00169 //  Description: Make sure the provided parameter has
00170 //               a texture type.  If not, print
00171 //               error message and return false.
00172 ////////////////////////////////////////////////////////////////////
00173 bool Shader::
00174 cp_errchk_parameter_sampler(ShaderArgInfo &p)
00175 {
00176   if ((p._type!=SAT_sampler1d)&&
00177       (p._type!=SAT_sampler2d)&&
00178       (p._type!=SAT_sampler3d)&&
00179       (p._type!=SAT_samplercube)) {
00180     cp_report_error(p, "parameter should have a 'sampler' type");
00181     return false;
00182   }
00183   return true;
00184 }
00185 
00186 ////////////////////////////////////////////////////////////////////
00187 //     Function: Shader::cp_parse_eol
00188 //       Access: Public
00189 //  Description: Make sure the next thing on the word list is EOL
00190 ////////////////////////////////////////////////////////////////////
00191 bool Shader::
00192 cp_parse_eol(ShaderArgInfo &p, vector_string &words, int &next) {
00193   if (words[next] != "") {
00194     cp_report_error(p, "Too many words in parameter");
00195     return false;
00196   }
00197   return true;
00198 }
00199 
00200 ////////////////////////////////////////////////////////////////////
00201 //     Function: Shader::cp_parse_delimiter
00202 //       Access: Public
00203 //  Description: Pop a delimiter ('to' or 'rel') from the word list.
00204 ////////////////////////////////////////////////////////////////////
00205 bool Shader::
00206 cp_parse_delimiter(ShaderArgInfo &p, vector_string &words, int &next) {
00207   if ((words[next] != "to")&&(words[next] != "rel")) {
00208     cp_report_error(p, "Keyword 'to' or 'rel' expected");
00209     return false;
00210   }
00211   next += 1;
00212   return true;
00213 }
00214 
00215 ////////////////////////////////////////////////////////////////////
00216 //     Function: Shader::cp_parse_non_delimiter
00217 //       Access: Public
00218 //  Description: Pop a non-delimiter word from the word list.
00219 //               Delimiters are 'to' and 'rel.'
00220 ////////////////////////////////////////////////////////////////////
00221 string Shader::
00222 cp_parse_non_delimiter(vector_string &words, int &next) {
00223   const string &nword = words[next];
00224   if ((nword == "")||(nword == "to")||(nword == "rel")) {
00225     return "";
00226   }
00227   next += 1;
00228   return nword;
00229 }
00230 
00231 ////////////////////////////////////////////////////////////////////
00232 //     Function: Shader::cp_parse_coord_sys
00233 //       Access: Public
00234 //  Description: Convert a single-word coordinate system name into
00235 //               a PART/ARG of a ShaderMatSpec.
00236 ////////////////////////////////////////////////////////////////////
00237 bool Shader::
00238 cp_parse_coord_sys(ShaderArgInfo &p,
00239                    vector_string &pieces, int &next,
00240                    ShaderMatSpec &bind, bool fromflag) {
00241 
00242   string word1 = cp_parse_non_delimiter(pieces, next);
00243   if (pieces[next] == "of") next++;
00244   string word2 = cp_parse_non_delimiter(pieces, next);
00245 
00246   ShaderMatInput from_single;
00247   ShaderMatInput from_double;
00248   ShaderMatInput to_single;
00249   ShaderMatInput to_double;
00250 
00251   if (word1 == "") {
00252     cp_report_error(p, "Could not parse coordinate system name");
00253     return false;
00254   } else if (word1 == "world") {
00255     from_single = SMO_world_to_view;
00256     from_double = SMO_INVALID;
00257     to_single   = SMO_view_to_world;
00258     to_double   = SMO_INVALID;
00259   } else if (word1 == "model") {
00260     from_single = SMO_model_to_view;
00261     from_double = SMO_view_x_to_view;
00262     to_single   = SMO_view_to_model;
00263     to_double   = SMO_view_to_view_x;
00264   } else if (word1 == "clip") {
00265     from_single = SMO_clip_to_view;
00266     from_double = SMO_clip_x_to_view;
00267     to_single   = SMO_view_to_clip;
00268     to_double   = SMO_view_to_clip_x;
00269   } else if (word1 == "view") {
00270     from_single = SMO_identity;
00271     from_double = SMO_view_x_to_view;
00272     to_single   = SMO_identity;
00273     to_double   = SMO_view_to_view_x;
00274   } else if (word1 == "apiview") {
00275     from_single = SMO_apiview_to_view;
00276     from_double = SMO_apiview_x_to_view;
00277     to_single   = SMO_view_to_apiview;
00278     to_double   = SMO_view_to_apiview_x;
00279   } else if (word1 == "apiclip") {
00280     from_single = SMO_apiclip_to_view;
00281     from_double = SMO_apiclip_x_to_view;
00282     to_single   = SMO_view_to_apiclip;
00283     to_double   = SMO_view_to_apiclip_x;
00284   } else {
00285     from_single = SMO_view_x_to_view;
00286     from_double = SMO_view_x_to_view;
00287     to_single   = SMO_view_to_view_x;
00288     to_double   = SMO_view_to_view_x;
00289     word2 = word1;
00290   }
00291 
00292   if (fromflag) {
00293     if (word2 == "") {
00294       bind._part[0] = from_single;
00295       bind._arg[0] = NULL;
00296     } else {
00297       if (from_double == SMO_INVALID) {
00298         cp_report_error(p, "Could not parse coordinate system name");
00299         return false;
00300       }
00301       bind._part[0] = from_double;
00302       bind._arg[0] = InternalName::make(word2);
00303     }
00304   } else {
00305     if (word2 == "") {
00306       bind._part[1] = to_single;
00307       bind._arg[1] = NULL;
00308     } else {
00309       if (to_double == SMO_INVALID) {
00310         cp_report_error(p, "Could not parse coordinate system name");
00311         return false;
00312       }
00313       bind._part[1] = to_double;
00314       bind._arg[1] = InternalName::make(word2);
00315     }
00316   }
00317   return true;
00318 }
00319 
00320 ////////////////////////////////////////////////////////////////////
00321 //     Function: Shader::cp_dependency
00322 //       Access: Public
00323 //  Description: Given ShaderMatInput, returns an indication of what
00324 //               part or parts of the state_and_transform the
00325 //               ShaderMatInput depends upon.
00326 ////////////////////////////////////////////////////////////////////
00327 int Shader::
00328 cp_dependency(ShaderMatInput inp) {
00329 
00330   int dep = SSD_general;
00331 
00332   if (inp == SMO_INVALID) {
00333     return SSD_NONE;
00334   }
00335   if (inp == SMO_attr_material) {
00336     dep |= SSD_material;
00337   }
00338   if (inp == SMO_attr_color) {
00339     dep |= SSD_color;
00340   }
00341   if (inp == SMO_attr_colorscale) {
00342     dep |= SSD_colorscale;
00343   }
00344   if ((inp == SMO_model_to_view)||
00345       (inp == SMO_view_to_model)) {
00346     dep |= SSD_transform;
00347   }
00348   if ((inp == SMO_texpad_x)||
00349       (inp == SMO_texpix_x)||
00350       (inp == SMO_alight_x)||
00351       (inp == SMO_dlight_x)||
00352       (inp == SMO_plight_x)||
00353       (inp == SMO_slight_x)||
00354       (inp == SMO_satten_x)||
00355       (inp == SMO_clipplane_x)||
00356       (inp == SMO_mat_constant_x)||
00357       (inp == SMO_vec_constant_x)||
00358       (inp == SMO_view_x_to_view)||
00359       (inp == SMO_view_to_view_x)||
00360       (inp == SMO_apiview_x_to_view)||
00361       (inp == SMO_view_to_apiview_x)||
00362       (inp == SMO_clip_x_to_view)||
00363       (inp == SMO_view_to_clip_x)||
00364       (inp == SMO_apiclip_x_to_view)||
00365       (inp == SMO_view_to_apiclip_x)) {
00366     dep |= SSD_shaderinputs;
00367   }
00368 
00369   return dep;
00370 }
00371 
00372 ////////////////////////////////////////////////////////////////////
00373 //     Function: Shader::cp_optimize_mat_spec
00374 //       Access: Public
00375 //  Description: Analyzes a ShaderMatSpec and decides what it should
00376 //               use its cache for.  It can cache the results of any
00377 //               one opcode, or, it can cache the entire result.  This
00378 //               routine needs to be smart enough to know which
00379 //               data items can be correctly cached, and which cannot.
00380 ////////////////////////////////////////////////////////////////////
00381 void Shader::
00382 cp_optimize_mat_spec(ShaderMatSpec &spec) {
00383 
00384   // If we're composing with identity, simplify.
00385 
00386   if (spec._func == SMF_first) {
00387     spec._part[1] = SMO_INVALID;
00388     spec._arg[1] = 0;
00389   }
00390   if (spec._func == SMF_compose) {
00391     if (spec._part[1] == SMO_identity) {
00392       spec._func = SMF_first;
00393     }
00394   }
00395   if (spec._func == SMF_compose) {
00396     if (spec._part[0] == SMO_identity) {
00397       spec._func = SMF_first;
00398       spec._part[0] = spec._part[1];
00399       spec._arg[0] = spec._arg[1];
00400     }
00401   }
00402 
00403   // Calculate state and transform dependencies.
00404 
00405   spec._dep[0] = cp_dependency(spec._part[0]);
00406   spec._dep[1] = cp_dependency(spec._part[1]);
00407 }
00408 
00409 ////////////////////////////////////////////////////////////////////
00410 //     Function: Shader::compile_parameter
00411 //       Access: Public
00412 //  Description: Analyzes a parameter and decides how to
00413 //               bind the parameter to some part of panda's
00414 //               internal state.  Updates one of the bind
00415 //               arrays to cause the binding to occur.
00416 //
00417 //               If there is an error, this routine will append
00418 //               an error message onto the error messages.
00419 ////////////////////////////////////////////////////////////////////
00420 bool Shader::
00421 compile_parameter(const ShaderArgId  &arg_id,
00422                   ShaderArgType       arg_type,
00423                   ShaderArgDir        arg_direction,
00424                   bool                arg_varying,
00425                   NotifyCategory     *arg_cat)
00426 {
00427   ShaderArgInfo p;
00428   p._id         = arg_id;
00429   p._type       = arg_type;
00430   p._direction  = arg_direction;
00431   p._varying    = arg_varying;
00432   p._cat        = arg_cat;
00433 
00434   if (p._id._name.size() == 0) return true;
00435   if (p._id._name[0] == '$') return true;
00436 
00437   // It could be inside a struct, strip off
00438   // everything before the last dot.
00439   size_t loc = p._id._name.find_last_of('.');
00440   string basename (p._id._name);
00441   if (loc < string::npos) {
00442     basename = p._id._name.substr(loc + 1);
00443   }
00444   if (basename.size() >= 2 && basename.substr(0, 2) == "__") {
00445     return true;
00446   }
00447 
00448   // Split it at the underscores.
00449   vector_string pieces;
00450   tokenize(basename, pieces, "_");
00451 
00452   if (pieces.size() < 2) {
00453     cp_report_error(p, "invalid parameter name");
00454     return false;
00455   }
00456 
00457   // Implement vtx parameters - the varying kind.
00458 
00459   if (pieces[0] == "vtx") {
00460     if ((!cp_errchk_parameter_in(p)) ||
00461         (!cp_errchk_parameter_varying(p)) ||
00462         (!cp_errchk_parameter_float(p, 1, 4))) {
00463       return false;
00464     }
00465     ShaderVarSpec bind;
00466     bind._id = arg_id;
00467     if (pieces.size() == 2) {
00468       if (pieces[1]=="position") {
00469         bind._name = InternalName::get_vertex();
00470         bind._append_uv = -1;
00471         _var_spec.push_back(bind);
00472         return true;
00473       }
00474       if (pieces[1].substr(0,8)=="texcoord") {
00475         bind._name = InternalName::get_texcoord();
00476         bind._append_uv = atoi(pieces[1].c_str()+8);
00477         _var_spec.push_back(bind);
00478         return true;
00479       }
00480       if (pieces[1].substr(0,7)=="tangent") {
00481         bind._name = InternalName::get_tangent();
00482         bind._append_uv = atoi(pieces[1].c_str()+7);
00483         _var_spec.push_back(bind);
00484         return true;
00485       }
00486       if (pieces[1].substr(0,8)=="binormal") {
00487         bind._name = InternalName::get_binormal();
00488         bind._append_uv = atoi(pieces[1].c_str()+8);
00489         _var_spec.push_back(bind);
00490         return true;
00491       }
00492     }
00493     bind._name = InternalName::get_root();
00494     bind._append_uv = -1;
00495     for (int i=1; i<(int)(pieces.size()-0); i++)
00496       bind._name = bind._name->append(pieces[i]);
00497     _var_spec.push_back(bind);
00498     return true;
00499   }
00500 
00501   // Implement some macros. Macros work by altering the
00502   // contents of the 'pieces' array, and then falling through.
00503 
00504   if (pieces[0] == "mstrans") {
00505     pieces[0] = "trans";
00506     pieces.push_back("to");
00507     pieces.push_back("model");
00508   }
00509   if (pieces[0] == "wstrans") {
00510     pieces[0] = "trans";
00511     pieces.push_back("to");
00512     pieces.push_back("world");
00513   }
00514   if (pieces[0] == "vstrans") {
00515     pieces[0] = "trans";
00516     pieces.push_back("to");
00517     pieces.push_back("view");
00518   }
00519   if (pieces[0] == "cstrans") {
00520     pieces[0] = "trans";
00521     pieces.push_back("to");
00522     pieces.push_back("clip");
00523   }
00524   if (pieces[0] == "mspos") {
00525     pieces[0] = "row3";
00526     pieces.push_back("to");
00527     pieces.push_back("model");
00528   }
00529   if (pieces[0] == "wspos") {
00530     pieces[0] = "row3";
00531     pieces.push_back("to");
00532     pieces.push_back("world");
00533   }
00534   if (pieces[0] == "vspos") {
00535     pieces[0] = "row3";
00536     pieces.push_back("to");
00537     pieces.push_back("view");
00538   }
00539   if (pieces[0] == "cspos") {
00540     pieces[0] = "row3";
00541     pieces.push_back("to");
00542     pieces.push_back("clip");
00543   }
00544 
00545   // Implement the modelview macros.
00546 
00547   if ((pieces[0] == "mat")||(pieces[0] == "inv")||
00548       (pieces[0] == "tps")||(pieces[0] == "itp")) {
00549     if (!cp_errchk_parameter_words(p, 2)) {
00550       return false;
00551     }
00552     string trans = pieces[0];
00553     string matrix = pieces[1];
00554     pieces.clear();
00555     if (matrix == "modelview") {
00556       tokenize("trans_model_to_apiview", pieces, "_");
00557     } else if (matrix == "projection") {
00558       tokenize("trans_apiview_to_apiclip", pieces, "_");
00559     } else if (matrix == "modelproj") {
00560       tokenize("trans_model_to_apiclip", pieces, "_");
00561     } else {
00562       cp_report_error(p,"unrecognized matrix name");
00563       return false;
00564     }
00565     if (trans=="mat") {
00566       pieces[0] = "trans";
00567     } else if (trans=="inv") {
00568       string t = pieces[1];
00569       pieces[1] = pieces[3];
00570       pieces[3] = t;
00571     } else if (trans=="tps") {
00572       pieces[0] = "tpose";
00573     } else if (trans=="itp") {
00574       string t = pieces[1];
00575       pieces[1] = pieces[3];
00576       pieces[3] = t;
00577       pieces[0] = "tpose";
00578     }
00579   }
00580 
00581   // Implement the transform-matrix generator.
00582 
00583   if ((pieces[0]=="trans")||
00584       (pieces[0]=="tpose")||
00585       (pieces[0]=="row0")||
00586       (pieces[0]=="row1")||
00587       (pieces[0]=="row2")||
00588       (pieces[0]=="row3")||
00589       (pieces[0]=="col0")||
00590       (pieces[0]=="col1")||
00591       (pieces[0]=="col2")||
00592       (pieces[0]=="col3")) {
00593 
00594     if ((!cp_errchk_parameter_in(p)) ||
00595         (!cp_errchk_parameter_uniform(p)))
00596       return false;
00597 
00598     ShaderMatSpec bind;
00599     bind._id = arg_id;
00600     bind._func = SMF_compose;
00601 
00602     int next = 1;
00603     pieces.push_back("");
00604 
00605     // Decide whether this is a matrix or vector.
00606     if      (pieces[0]=="trans")   bind._piece = SMP_whole;
00607     else if (pieces[0]=="tpose")   bind._piece = SMP_transpose;
00608     else if (pieces[0]=="row0")    bind._piece = SMP_row0;
00609     else if (pieces[0]=="row1")    bind._piece = SMP_row1;
00610     else if (pieces[0]=="row2")    bind._piece = SMP_row2;
00611     else if (pieces[0]=="row3")    bind._piece = SMP_row3;
00612     else if (pieces[0]=="col0")    bind._piece = SMP_col0;
00613     else if (pieces[0]=="col1")    bind._piece = SMP_col1;
00614     else if (pieces[0]=="col2")    bind._piece = SMP_col2;
00615     else if (pieces[0]=="col3")    bind._piece = SMP_col3;
00616     if ((bind._piece == SMP_whole)||(bind._piece == SMP_transpose)) {
00617       if (!cp_errchk_parameter_float(p, 16, 16)) return false;
00618     } else {
00619       if (!cp_errchk_parameter_float(p, 4, 4)) return false;
00620     }
00621 
00622     if (!cp_parse_coord_sys(p, pieces, next, bind, true)) {
00623       return false;
00624     }
00625     if (!cp_parse_delimiter(p, pieces, next)) {
00626       return false;
00627     }
00628     if (!cp_parse_coord_sys(p, pieces, next, bind, false)) {
00629       return false;
00630     }
00631     if (!cp_parse_eol(p, pieces, next)) {
00632       return false;
00633     }
00634     cp_optimize_mat_spec(bind);
00635     _mat_spec.push_back(bind);
00636     return true;
00637   }
00638 
00639   // Special parameter: attr_material or attr_color
00640 
00641   if (pieces[0] == "attr") {
00642     if ((!cp_errchk_parameter_words(p,2)) ||
00643         (!cp_errchk_parameter_in(p)) ||
00644         (!cp_errchk_parameter_uniform(p))) {
00645       return false;
00646     }
00647     ShaderMatSpec bind;
00648     if (pieces[1] == "material") {
00649       if (!cp_errchk_parameter_float(p,16,16)) {
00650         return false;
00651       }
00652       bind._id = arg_id;
00653       bind._piece = SMP_transpose;
00654       bind._func = SMF_first;
00655       bind._part[0] = SMO_attr_material;
00656       bind._arg[0] = NULL;
00657       bind._part[1] = SMO_identity;
00658       bind._arg[1] = NULL;
00659     } else if (pieces[1] == "color") {
00660       if (!cp_errchk_parameter_float(p,3,4)) {
00661         return false;
00662       }
00663       bind._id = arg_id;
00664       bind._piece = SMP_row3;
00665       bind._func = SMF_first;
00666       bind._part[0] = SMO_attr_color;
00667       bind._arg[0] = NULL;
00668       bind._part[1] = SMO_identity;
00669       bind._arg[1] = NULL;
00670     } else if (pieces[1] == "colorscale") {
00671       if (!cp_errchk_parameter_float(p,3,4)) {
00672         return false;
00673       }
00674       bind._id = arg_id;
00675       bind._piece = SMP_row3;
00676       bind._func = SMF_first;
00677       bind._part[0] = SMO_attr_colorscale;
00678       bind._arg[0] = NULL;
00679       bind._part[1] = SMO_identity;
00680       bind._arg[1] = NULL;
00681     } else {
00682       cp_report_error(p,"Unknown attr parameter.");
00683       return false;
00684     }
00685 
00686     cp_optimize_mat_spec(bind);
00687     _mat_spec.push_back(bind);
00688     return true;
00689   }
00690 
00691   if (pieces[0] == "color") {
00692     if ((!cp_errchk_parameter_words(p,1)) ||
00693         (!cp_errchk_parameter_in(p)) ||
00694         (!cp_errchk_parameter_uniform(p))) {
00695       return false;
00696     }
00697     ShaderMatSpec bind;
00698 
00699     cp_optimize_mat_spec(bind);
00700     _mat_spec.push_back(bind);
00701     return true;
00702   }
00703 
00704   // Keywords to access light properties.
00705 
00706   if (pieces[0] == "alight") {
00707     if ((!cp_errchk_parameter_words(p,2))||
00708         (!cp_errchk_parameter_in(p)) ||
00709         (!cp_errchk_parameter_uniform(p))||
00710         (!cp_errchk_parameter_float(p,3,4))) {
00711       return false;
00712     }
00713     ShaderMatSpec bind;
00714     bind._id = arg_id;
00715     bind._piece = SMP_row3;
00716     bind._func = SMF_first;
00717     bind._part[0] = SMO_alight_x;
00718     bind._arg[0] = InternalName::make(pieces[1]);
00719     bind._part[1] = SMO_identity;
00720     bind._arg[1] = NULL;
00721 
00722     cp_optimize_mat_spec(bind);
00723     _mat_spec.push_back(bind);
00724     return true;
00725   }
00726 
00727   if (pieces[0] == "satten") {
00728     if ((!cp_errchk_parameter_words(p,2))||
00729         (!cp_errchk_parameter_in(p)) ||
00730         (!cp_errchk_parameter_uniform(p))||
00731         (!cp_errchk_parameter_float(p,4,4))) {
00732       return false;
00733     }
00734     ShaderMatSpec bind;
00735     bind._id = arg_id;
00736     bind._piece = SMP_row3;
00737     bind._func = SMF_first;
00738     bind._part[0] = SMO_satten_x;
00739     bind._arg[0] = InternalName::make(pieces[1]);
00740     bind._part[1] = SMO_identity;
00741     bind._arg[1] = NULL;
00742 
00743     cp_optimize_mat_spec(bind);
00744     _mat_spec.push_back(bind);
00745     return true;
00746   }
00747 
00748   if ((pieces[0]=="dlight")||(pieces[0]=="plight")||(pieces[0]=="slight")) {
00749     if ((!cp_errchk_parameter_in(p)) ||
00750         (!cp_errchk_parameter_uniform(p))||
00751         (!cp_errchk_parameter_float(p,16,16))) {
00752       return false;
00753     }
00754     ShaderMatSpec bind;
00755     bind._id = arg_id;
00756     bind._piece = SMP_transpose;
00757     int next = 1;
00758     pieces.push_back("");
00759     if (pieces[next] == "") {
00760       cp_report_error(p, "Light name expected");
00761       return false;
00762     }
00763     if (pieces[0] == "dlight") {
00764       bind._func = SMF_transform_dlight;
00765       bind._part[0] = SMO_dlight_x;
00766     } else if (pieces[0] == "plight") {
00767       bind._func = SMF_transform_plight;
00768       bind._part[0] = SMO_plight_x;
00769     } else if (pieces[0] == "slight") {
00770       bind._func = SMF_transform_slight;
00771       bind._part[0] = SMO_slight_x;
00772     }
00773     bind._arg[0] = InternalName::make(pieces[next]);
00774     next += 1;
00775     if (!cp_parse_delimiter(p, pieces, next)) {
00776       return false;
00777     }
00778     if (!cp_parse_coord_sys(p, pieces, next, bind, false)) {
00779       return false;
00780     }
00781     if (!cp_parse_eol(p, pieces, next)) {
00782       return false;
00783     }
00784     cp_optimize_mat_spec(bind);
00785     _mat_spec.push_back(bind);
00786     return true;
00787   }
00788 
00789   if (pieces[0] == "texmat") {
00790     if ((!cp_errchk_parameter_words(p,2))||
00791         (!cp_errchk_parameter_in(p)) ||
00792         (!cp_errchk_parameter_uniform(p))||
00793         (!cp_errchk_parameter_float(p,16,16))) {
00794       return false;
00795     }
00796     ShaderMatSpec bind;
00797     bind._id = arg_id;
00798     bind._piece = SMP_whole;
00799     bind._func = SMF_first;
00800     bind._part[0] = SMO_texmat_x;
00801     bind._arg[0] = InternalName::make(pieces[1]);
00802     bind._part[1] = SMO_identity;
00803     bind._arg[1] = NULL;
00804 
00805     cp_optimize_mat_spec(bind);
00806     _mat_spec.push_back(bind);
00807     return true;
00808   }
00809 
00810   if (pieces[0] == "plane") {
00811     if ((!cp_errchk_parameter_words(p,2))||
00812         (!cp_errchk_parameter_in(p)) ||
00813         (!cp_errchk_parameter_uniform(p))||
00814         (!cp_errchk_parameter_float(p,4,4))) {
00815       return false;
00816     }
00817     ShaderMatSpec bind;
00818     bind._id = arg_id;
00819     bind._piece = SMP_row3;
00820     bind._func = SMF_first;
00821     bind._part[0] = SMO_plane_x;
00822     bind._arg[0] = InternalName::make(pieces[1]);
00823     bind._part[1] = SMO_identity;
00824     bind._arg[1] = NULL;
00825 
00826     cp_optimize_mat_spec(bind);
00827     _mat_spec.push_back(bind);
00828     return true;
00829   }
00830 
00831   if (pieces[0] == "clipplane") {
00832     if ((!cp_errchk_parameter_words(p,2))||
00833         (!cp_errchk_parameter_in(p)) ||
00834         (!cp_errchk_parameter_uniform(p))||
00835         (!cp_errchk_parameter_float(p,4,4))) {
00836       return false;
00837     }
00838     ShaderMatSpec bind;
00839     bind._id = arg_id;
00840     bind._piece = SMP_row3;
00841     bind._func = SMF_first;
00842     bind._part[0] = SMO_clipplane_x;
00843     bind._arg[0] = InternalName::make(pieces[1]);
00844     bind._part[1] = SMO_identity;
00845     bind._arg[1] = NULL;
00846 
00847     cp_optimize_mat_spec(bind);
00848     _mat_spec.push_back(bind);
00849     return true;
00850   }
00851 
00852   // Keywords to access unusual parameters.
00853 
00854   if (pieces[0] == "sys") {
00855     if ((!cp_errchk_parameter_words(p,2)) ||
00856         (!cp_errchk_parameter_in(p)) ||
00857         (!cp_errchk_parameter_uniform(p))) {
00858       return false;
00859     }
00860     ShaderMatSpec bind;
00861     bind._id = arg_id;
00862     bind._piece = SMP_row3;
00863     bind._func = SMF_first;
00864     bind._part[1] = SMO_identity;
00865     bind._arg[1] = NULL;
00866     if (pieces[1] == "pixelsize") {
00867       if (!cp_errchk_parameter_float(p, 2, 2)) {
00868         return false;
00869       }
00870       bind._part[0] = SMO_pixel_size;
00871       bind._arg[0] = NULL;
00872     } else if (pieces[1] == "windowsize") {
00873       if (!cp_errchk_parameter_float(p, 2, 2)) {
00874         return false;
00875       }
00876       bind._part[0] = SMO_window_size;
00877       bind._arg[0] = NULL;
00878     } else {
00879       cp_report_error(p,"unknown system parameter");
00880       return false;
00881     }
00882 
00883     cp_optimize_mat_spec(bind);
00884     _mat_spec.push_back(bind);
00885     return true;
00886   }
00887 
00888   // Keywords to access textures.
00889 
00890   if (pieces[0] == "tex") {
00891     if ((!cp_errchk_parameter_in(p)) ||
00892         (!cp_errchk_parameter_uniform(p)) ||
00893         (!cp_errchk_parameter_sampler(p)))
00894       return false;
00895     if ((pieces.size() != 2)&&(pieces.size() != 3)) {
00896       cp_report_error(p, "Invalid parameter name");
00897       return false;
00898     }
00899     ShaderTexSpec bind;
00900     bind._id = arg_id;
00901     bind._name = 0;
00902     bind._stage = atoi(pieces[1].c_str());
00903     switch (p._type) {
00904     case SAT_sampler1d:   bind._desired_type = Texture::TT_1d_texture; break;
00905     case SAT_sampler2d:   bind._desired_type = Texture::TT_2d_texture; break;
00906     case SAT_sampler3d:   bind._desired_type = Texture::TT_3d_texture; break;
00907     case SAT_samplercube: bind._desired_type = Texture::TT_cube_map; break;
00908     default:
00909       cp_report_error(p, "Invalid type for a tex-parameter");
00910       return false;
00911     }
00912     if (pieces.size()==3) {
00913       bind._suffix = InternalName::make(((string)"-") + pieces[2]);
00914     }
00915     _tex_spec.push_back(bind);
00916     return true;
00917   }
00918 
00919   // Keywords to access constants.
00920 
00921   if (pieces[0] == "k") {
00922     if ((!cp_errchk_parameter_in(p)) ||
00923         (!cp_errchk_parameter_uniform(p)))
00924       return false;
00925     // In the case of k-parameters, we allow underscores in the name.
00926     PT(InternalName) kinputname = InternalName::make(basename.substr(2));
00927     switch (p._type) {
00928     case SAT_float1:
00929     case SAT_float2:
00930     case SAT_float3:
00931     case SAT_float4: {
00932       ShaderMatSpec bind;
00933       bind._id = arg_id;
00934       switch (p._type) {
00935       case SAT_float1: bind._piece = SMP_row3x1; break;
00936       case SAT_float2: bind._piece = SMP_row3x2; break;
00937       case SAT_float3: bind._piece = SMP_row3x3; break;
00938       case SAT_float4: bind._piece = SMP_row3; break;
00939       }
00940       bind._func = SMF_first;
00941       bind._part[0] = SMO_vec_constant_x;
00942       bind._arg[0] = kinputname;
00943       bind._part[1] = SMO_identity;
00944       bind._arg[1] = NULL;
00945       cp_optimize_mat_spec(bind);
00946       _mat_spec.push_back(bind);
00947       break;
00948     }
00949     case SAT_float4x4: {
00950       ShaderMatSpec bind;
00951       bind._id = arg_id;
00952       bind._piece = SMP_whole;
00953       bind._func = SMF_first;
00954       bind._part[0] = SMO_mat_constant_x;
00955       bind._arg[0] = kinputname;
00956       bind._part[1] = SMO_identity;
00957       bind._arg[1] = NULL;
00958       cp_optimize_mat_spec(bind);
00959       _mat_spec.push_back(bind);
00960       break;
00961     }
00962     case SAT_sampler1d: {
00963       ShaderTexSpec bind;
00964       bind._id = arg_id;
00965       bind._name = kinputname;
00966       bind._desired_type=Texture::TT_1d_texture;
00967       _tex_spec.push_back(bind);
00968       break;
00969     }
00970     case SAT_sampler2d: {
00971       ShaderTexSpec bind;
00972       bind._id = arg_id;
00973       bind._name = kinputname;
00974       bind._desired_type=Texture::TT_2d_texture;
00975       _tex_spec.push_back(bind);
00976       break;
00977     }
00978     case SAT_sampler3d: {
00979       ShaderTexSpec bind;
00980       bind._id = arg_id;
00981       bind._name = kinputname;
00982       bind._desired_type=Texture::TT_3d_texture;
00983       _tex_spec.push_back(bind);
00984       break;
00985     }
00986     case SAT_samplercube: {
00987       ShaderTexSpec bind;
00988       bind._id = arg_id;
00989       bind._name = kinputname;
00990       bind._desired_type = Texture::TT_cube_map;
00991       _tex_spec.push_back(bind);
00992       break;
00993     }
00994     default:
00995       cp_report_error(p, "Invalid type for a k-parameter");
00996       return false;
00997     }
00998     return true;
00999   }
01000 
01001   // Keywords to fetch texture parameter data.
01002 
01003   if (pieces[0] == "texpad") {
01004     if ((!cp_errchk_parameter_words(p,2)) ||
01005         (!cp_errchk_parameter_in(p)) ||
01006         (!cp_errchk_parameter_uniform(p))||
01007         (!cp_errchk_parameter_float(p,3,4))) {
01008       return false;
01009     }
01010     ShaderMatSpec bind;
01011     bind._id = arg_id;
01012     bind._piece = SMP_row3;
01013     bind._func = SMF_first;
01014     bind._part[0] = SMO_texpad_x;
01015     bind._arg[0] = InternalName::make(pieces[1]);
01016     bind._part[1] = SMO_identity;
01017     bind._arg[1] = NULL;
01018     cp_optimize_mat_spec(bind);
01019     _mat_spec.push_back(bind);
01020     return true;
01021   }
01022 
01023   if (pieces[0] == "texpix") {
01024     if ((!cp_errchk_parameter_words(p,2)) ||
01025         (!cp_errchk_parameter_in(p)) ||
01026         (!cp_errchk_parameter_uniform(p))||
01027         (!cp_errchk_parameter_float(p,2,4))) {
01028       return false;
01029     }
01030     ShaderMatSpec bind;
01031     bind._id = arg_id;
01032     bind._piece = SMP_row3;
01033     bind._func = SMF_first;
01034     bind._part[0] = SMO_texpix_x;
01035     bind._arg[0] = InternalName::make(pieces[1]);
01036     bind._part[1] = SMO_identity;
01037     bind._arg[1] = NULL;
01038     cp_optimize_mat_spec(bind);
01039     _mat_spec.push_back(bind);
01040     return true;
01041   }
01042 
01043   if (pieces[0] == "l") {
01044     // IMPLEMENT THE ERROR CHECKING
01045     return true; // Cg handles this automatically.
01046   }
01047 
01048   if (pieces[0] == "o") {
01049     // IMPLEMENT THE ERROR CHECKING
01050     return true; // Cg handles this automatically.
01051   }
01052 
01053   cp_report_error(p, "unrecognized parameter name");
01054   return false;
01055 }
01056 
01057 
01058 ////////////////////////////////////////////////////////////////////
01059 //     Function: Shader::clear_parameters
01060 //       Access: Private
01061 //  Description:
01062 ////////////////////////////////////////////////////////////////////
01063 void Shader::
01064 clear_parameters() {
01065   _mat_spec.clear();
01066   _var_spec.clear();
01067   _tex_spec.clear();
01068 }
01069 
01070 #ifdef HAVE_CG
01071 ////////////////////////////////////////////////////////////////////
01072 //     Function: Shader::cg_parameter_type
01073 //       Access: Private
01074 //  Description:
01075 ////////////////////////////////////////////////////////////////////
01076 Shader::ShaderArgType Shader::
01077 cg_parameter_type(CGparameter p) {
01078   switch (cgGetParameterType(p)) {
01079   case CG_FLOAT1:      return Shader::SAT_float1;
01080   case CG_FLOAT2:      return Shader::SAT_float2;
01081   case CG_FLOAT3:      return Shader::SAT_float3;
01082   case CG_FLOAT4:      return Shader::SAT_float4;
01083   case CG_FLOAT4x4:    return Shader::SAT_float4x4;
01084   case CG_SAMPLER1D:   return Shader::SAT_sampler1d;
01085   case CG_SAMPLER2D:   return Shader::SAT_sampler2d;
01086   case CG_SAMPLER3D:   return Shader::SAT_sampler3d;
01087   case CG_SAMPLERCUBE: return Shader::SAT_samplercube;
01088   // CG_SAMPLER1DSHADOW and CG_SAMPLER2DSHADOW
01089   case 1313:           return Shader::SAT_sampler1d;
01090   case 1314:           return Shader::SAT_sampler2d;
01091   default:             return Shader::SAT_unknown;
01092   }
01093 }
01094 
01095 ////////////////////////////////////////////////////////////////////
01096 //     Function: Shader::cg_parameter_dir
01097 //       Access: Private
01098 //  Description:
01099 ////////////////////////////////////////////////////////////////////
01100 Shader::ShaderArgDir Shader::
01101 cg_parameter_dir(CGparameter p) {
01102   switch (cgGetParameterDirection(p)) {
01103   case CG_IN:    return Shader::SAD_in;
01104   case CG_OUT:   return Shader::SAD_out;
01105   case CG_INOUT: return Shader::SAD_inout;
01106   default:       return Shader::SAD_unknown;
01107   }
01108 }
01109 
01110 ////////////////////////////////////////////////////////////////////
01111 //     Function: Shader::cg_release_resources
01112 //       Access: Private
01113 //  Description: xyz
01114 ////////////////////////////////////////////////////////////////////
01115 void Shader::
01116 cg_release_resources() {
01117   if (_cg_vprogram != 0) {
01118     cgDestroyProgram(_cg_vprogram);
01119     _cg_vprogram = 0;
01120   }
01121   if (_cg_fprogram != 0) {
01122     cgDestroyProgram(_cg_fprogram);
01123     _cg_fprogram = 0;
01124   }
01125   if (_cg_gprogram != 0) {
01126     cgDestroyProgram(_cg_gprogram);
01127     _cg_gprogram = 0;
01128   }
01129   if (_cg_context != 0) {
01130     cgDestroyContext(_cg_context);
01131     _cg_context = 0;
01132   }
01133 }
01134 
01135 ////////////////////////////////////////////////////////////////////
01136 //     Function: Shader::cg_compile_entry_point
01137 //       Access: Private
01138 //  Description: xyz
01139 ////////////////////////////////////////////////////////////////////
01140 CGprogram Shader::
01141 cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType type) {
01142   CGprogram prog;
01143   CGerror err;
01144   const char *compiler_args[100];
01145   const string text = get_text(type);
01146   int nargs = 0;
01147 
01148   int active, ultimate;
01149 
01150   switch(type) {
01151     case ST_vertex:
01152       active   = caps._active_vprofile;
01153       ultimate = caps._ultimate_vprofile;
01154       break;
01155 
01156     case ST_fragment:
01157       active   = caps._active_fprofile;
01158       ultimate = caps._ultimate_fprofile;
01159       break;
01160 
01161     case ST_geometry:
01162       active   = caps._active_gprofile;
01163       ultimate = caps._ultimate_gprofile;
01164       break;
01165   };
01166 
01167   cgGetError();
01168 
01169   if (type == ST_fragment && caps._bug_list.count(SBUG_ati_draw_buffers)) {
01170     compiler_args[nargs++] = "-po";
01171     compiler_args[nargs++] = "ATI_draw_buffers";
01172   }
01173   compiler_args[nargs] = 0;
01174 
01175   if ((active != (int)CG_PROFILE_UNKNOWN) && (active != ultimate)) {
01176     prog = cgCreateProgram(_cg_context, CG_SOURCE, text.c_str(),
01177                            (CGprofile)active, entry, (const char **)compiler_args);
01178     err = cgGetError();
01179     if (err == CG_NO_ERROR) {
01180       return prog;
01181     }
01182     if (prog != 0) {
01183       cgDestroyProgram(prog);
01184     }
01185   }
01186 
01187   prog = cgCreateProgram(_cg_context, CG_SOURCE, text.c_str(),
01188                          (CGprofile)ultimate, entry, (const char **)NULL);
01189   err = cgGetError();
01190   if (err == CG_NO_ERROR) {
01191     return prog;
01192   }
01193   if (err == CG_COMPILER_ERROR) {
01194     string listing = cgGetLastListing(_cg_context);
01195     vector_string errlines;
01196     tokenize(listing, errlines, "\n");
01197     for (int i=0; i<(int)errlines.size(); i++) {
01198       string line = trim(errlines[i]);
01199       if (line != "") {
01200         gobj_cat.error() << get_filename(type) << ": " << errlines[i] << "\n";
01201       }
01202     }
01203   } else {
01204     gobj_cat.error() << get_filename(type) << ": " << cgGetErrorString(err) << "\n";
01205   }
01206   if (prog != 0) {
01207     cgDestroyProgram(prog);
01208   }
01209 
01210   return 0;
01211 }
01212 
01213 ////////////////////////////////////////////////////////////////////
01214 //     Function: Shader::cg_compile_shader
01215 //       Access: Private
01216 //  Description: Compiles a Cg shader for a given set of capabilities.
01217 //               If successful, the shader is stored in the instance
01218 //               variables _cg_context, _cg_vprogram, _cg_fprogram.
01219 ////////////////////////////////////////////////////////////////////
01220 bool Shader::
01221 cg_compile_shader(const ShaderCaps &caps) {
01222 
01223   // If we already tried compiling for this set of caps, there's no point
01224   // trying again.  Just return the results of the previous compile.
01225   if (caps == _cg_last_caps) {
01226     if (_cg_context == 0) {
01227       return false;
01228     } else {
01229       return true;
01230     }
01231   }
01232 
01233   _cg_last_caps = caps;
01234 
01235   _cg_context = cgCreateContext();
01236 
01237   if (!_text->_separate) {
01238     gobj_cat.debug() << "Compiling Shader: \n" << _text << "\n";
01239   }
01240 
01241   if (_cg_context == 0) {
01242     gobj_cat.error() << "could not create a Cg context object.\n";
01243     return false;
01244   }
01245 
01246   if (!_text->_separate || !_text->_vertex.empty()) {
01247     _cg_vprogram = cg_compile_entry_point("vshader", caps, ST_vertex);
01248     if (_cg_vprogram == 0) {
01249       cg_release_resources();
01250       return false;
01251     }
01252   }
01253 
01254   if (!_text->_separate || !_text->_fragment.empty()) {
01255     _cg_fprogram = cg_compile_entry_point("fshader", caps, ST_fragment);
01256     if (_cg_fprogram == 0) {
01257       cg_release_resources();
01258       return false;
01259     }
01260   }
01261 
01262   if ((_text->_separate && !_text->_geometry.empty()) || (!_text->_separate && _text->_shared.find("gshader") != -1)) {
01263     _cg_gprogram = cg_compile_entry_point("gshader", caps, ST_geometry);
01264     if (_cg_gprogram == 0) {
01265       cg_release_resources();
01266       return false;
01267     }
01268   }
01269 
01270   if (_cg_vprogram == 0 && _cg_fprogram == 0 && _cg_gprogram == 0) {
01271     gobj_cat.error() << "Shader must at least have one program!\n";
01272     cg_release_resources();
01273     return false;
01274   }
01275 
01276   return true;
01277 }
01278 
01279 ////////////////////////////////////////////////////////////////////
01280 //     Function: Shader::cg_analyze_entry_point
01281 //       Access: Private
01282 //  Description:
01283 ////////////////////////////////////////////////////////////////////
01284 bool Shader::
01285 cg_analyze_entry_point(CGprogram prog, ShaderType type) {
01286   CGparameter parameter;
01287   bool success = true;
01288   for (parameter = cgGetFirstLeafParameter(prog, CG_PROGRAM);
01289        parameter != 0;
01290        parameter = cgGetNextLeafParameter(parameter)) {
01291     CGenum vbl = cgGetParameterVariability(parameter);
01292 
01293     if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) {
01294       ShaderArgId id;
01295       id._name = cgGetParameterName(parameter);
01296 
01297       id._type  = type;
01298       id._seqno = -1;
01299       success &= compile_parameter(id,
01300                                    cg_parameter_type(parameter),
01301                                    cg_parameter_dir(parameter),
01302                                    (vbl == CG_VARYING),
01303                                    gobj_cat.get_safe_ptr());
01304     }
01305   }
01306   return success;
01307 }
01308 
01309 
01310 ////////////////////////////////////////////////////////////////////
01311 //     Function: Shader::cg_analyze_shader
01312 //       Access: Private
01313 //  Description: This subroutine analyzes the parameters of a Cg
01314 //               shader. The output is stored in instance variables:
01315 //               _mat_spec, _var_spec, and _tex_spec.
01316 //
01317 //               In order to do this, it is necessary to compile the
01318 //               shader.  It would be a waste of CPU time to compile
01319 //               the shader, analyze the parameters, and then discard
01320 //               the compiled shader.  This would force us to compile it
01321 //               again later, when we need to build the ShaderContext.
01322 //               Instead, we cache the compiled Cg program in instance
01323 //               variables.  Later, a ShaderContext can pull the
01324 //               compiled shader from these instance vars.
01325 //
01326 //               To compile a shader, you need to first choose a profile.
01327 //               There are two contradictory objectives:
01328 //
01329 //               1. If you don't use the gsg's active profile,
01330 //               then the cached compiled shader will not be useful to
01331 //               the ShaderContext.
01332 //
01333 //               2. If you use too weak a profile, then the shader may
01334 //               not compile.  So to guarantee success, you should use
01335 //               the ultimate profile.
01336 //
01337 //               To resolve this conflict, we try the active profile
01338 //               first, and if that doesn't work, we try the ultimate
01339 //               profile.
01340 //
01341 ////////////////////////////////////////////////////////////////////
01342 bool Shader::
01343 cg_analyze_shader(const ShaderCaps &caps) {
01344 
01345   if (!cg_compile_shader(caps)) {
01346     return false;
01347   }
01348 
01349   if (_cg_fprogram != 0) {
01350      if (!cg_analyze_entry_point(_cg_fprogram, ST_fragment)) {
01351       cg_release_resources();
01352       clear_parameters();
01353       return false;
01354     }
01355   }
01356 
01357   if (_var_spec.size() != 0) {
01358     gobj_cat.error() << "Cannot use vtx parameters in an fshader\n";
01359     cg_release_resources();
01360     clear_parameters();
01361     return false;
01362   }
01363 
01364   if (_cg_vprogram != 0) {
01365     if (!cg_analyze_entry_point(_cg_vprogram, ST_vertex)) {
01366       cg_release_resources();
01367       clear_parameters();
01368       return false;
01369     }
01370   }
01371 
01372   if (_cg_gprogram != 0) {
01373     if (!cg_analyze_entry_point(_cg_gprogram, ST_geometry)) {
01374       cg_release_resources();
01375       clear_parameters();
01376       return false;
01377     }
01378   }
01379 
01380   // Assign sequence numbers to all parameters.
01381   int seqno = 0;
01382   for (int i=0; i<(int)_mat_spec.size(); i++) {
01383     _mat_spec[i]._id._seqno = seqno++;
01384   }
01385   for (int i=0; i<(int)_tex_spec.size(); i++) {
01386     _tex_spec[i]._id._seqno = seqno++;
01387   }
01388   for (int i=0; i<(int)_var_spec.size(); i++) {
01389     _var_spec[i]._id._seqno = seqno++;
01390   }
01391 
01392   // DEBUG: output the generated program
01393   if (gobj_cat.is_debug()) {
01394     const char *vertex_program;
01395     const char *pixel_program;
01396     const char *geometry_program;
01397 
01398     if (_cg_vprogram != 0) {
01399       vertex_program   = cgGetProgramString (_cg_vprogram, CG_COMPILED_PROGRAM);
01400       gobj_cat.debug() << vertex_program << "\n";
01401     }
01402     if (_cg_fprogram != 0) {
01403       pixel_program    = cgGetProgramString (_cg_fprogram, CG_COMPILED_PROGRAM);
01404       gobj_cat.debug() << pixel_program << "\n";
01405     }
01406     if (_cg_gprogram != 0) {
01407       geometry_program = cgGetProgramString (_cg_gprogram, CG_COMPILED_PROGRAM);
01408       gobj_cat.debug() << geometry_program << "\n";
01409     }
01410   }
01411 
01412   //  // The following code is present to work around a bug in the Cg compiler.
01413   //  // It does not generate correct code for shadow map lookups when using arbfp1.
01414   //  // This is a particularly onerous limitation, given that arbfp1 is the only
01415   //  // Cg target that works on radeons.  I suspect this is an intentional
01416   //  // omission on nvidia's part.  The following code fetches the output listing,
01417   //  // detects the error, repairs the code, and resumbits the repaired code to Cg.
01418   //  if ((_cg_fprofile == CG_PROFILE_ARBFP1) && (gsghint->_supports_shadow_filter)) {
01419   //    bool shadowunit[32];
01420   //    bool anyshadow = false;
01421   //    memset(shadowunit, 0, sizeof(shadowunit));
01422   //    vector_string lines;
01423   //    tokenize(cgGetProgramString(_cg_program[SHADER_type_frag],
01424   //                                CG_COMPILED_PROGRAM), lines, "\n");
01425   //    // figure out which texture units contain shadow maps.
01426   //    for (int lineno=0; lineno<(int)lines.size(); lineno++) {
01427   //      if (lines[lineno].compare(0,21,"#var sampler2DSHADOW ")) {
01428   //        continue;
01429   //      }
01430   //      vector_string fields;
01431   //      tokenize(lines[lineno], fields, ":");
01432   //      if (fields.size()!=5) {
01433   //        continue;
01434   //      }
01435   //      vector_string words;
01436   //      tokenize(trim(fields[2]), words, " ");
01437   //      if (words.size()!=2) {
01438   //        continue;
01439   //      }
01440   //      int unit = atoi(words[1].c_str());
01441   //      if ((unit < 0)||(unit >= 32)) {
01442   //        continue;
01443   //      }
01444   //      anyshadow = true;
01445   //      shadowunit[unit] = true;
01446   //    }
01447   //    // modify all TEX statements that use the relevant texture units.
01448   //    if (anyshadow) {
01449   //      for (int lineno=0; lineno<(int)lines.size(); lineno++) {
01450   //        if (lines[lineno].compare(0,4,"TEX ")) {
01451   //          continue;
01452   //        }
01453   //        vector_string fields;
01454   //        tokenize(lines[lineno], fields, ",");
01455   //        if ((fields.size()!=4)||(trim(fields[3]) != "2D;")) {
01456   //          continue;
01457   //        }
01458   //        vector_string texunitf;
01459   //        tokenize(trim(fields[2]), texunitf, "[]");
01460   //        if ((texunitf.size()!=3)||(texunitf[0] != "texture")||(texunitf[2]!="")) {
01461   //          continue;
01462   //        }
01463   //        int unit = atoi(texunitf[1].c_str());
01464   //        if ((unit < 0) || (unit >= 32) || (shadowunit[unit]==false)) {
01465   //          continue;
01466   //        }
01467   //        lines[lineno] = fields[0]+","+fields[1]+","+fields[2]+", SHADOW2D;";
01468   //      }
01469   //      string result = "!!ARBfp1.0\nOPTION ARB_fragment_program_shadow;\n";
01470   //      for (int lineno=1; lineno<(int)lines.size(); lineno++) {
01471   //        result += (lines[lineno] + "\n");
01472   //      }
01473   //      _cg_program[2] = _cg_program[SHADER_type_frag];
01474   //      _cg_program[SHADER_type_frag] =
01475   //        cgCreateProgram(_cg_context, CG_OBJECT, result.c_str(),
01476   //                        _cg_profile[SHADER_type_frag], "fshader", (const char**)NULL);
01477   //      cg_report_errors(s->get_name(), _cg_context);
01478   //      if (_cg_program[SHADER_type_frag]==0) {
01479   //        release_resources();
01480   //        return false;
01481   //      }
01482   //    }
01483   //  }
01484 
01485   return true;
01486 }
01487 
01488 ////////////////////////////////////////////////////////////////////
01489 //     Function: Shader::cg_program_from_shadertype
01490 //       Access: Private
01491 //  Description: Returns the CGprogram of the given shadertype
01492 //               that belongs to this shader.
01493 ////////////////////////////////////////////////////////////////////
01494 CGprogram Shader::
01495 cg_program_from_shadertype(ShaderType type) {
01496   CGprogram prog = 0;
01497 
01498   switch(type) {
01499     case ST_vertex:
01500       prog = _cg_vprogram;
01501       break;
01502 
01503     case ST_fragment:
01504       prog = _cg_fprogram;
01505       break;
01506 
01507     case ST_geometry:
01508       prog = _cg_gprogram;
01509       break;
01510   };
01511 
01512   return prog;
01513 }
01514 
01515 ////////////////////////////////////////////////////////////////////
01516 //     Function: Shader::cg_compile_for
01517 //       Access: Public
01518 //  Description: This routine is used by the ShaderContext constructor
01519 //               to compile the shader.  The CGprogram
01520 //               objects are turned over to the ShaderContext, we no
01521 //               longer own them.
01522 ////////////////////////////////////////////////////////////////////
01523 bool Shader::
01524 cg_compile_for(const ShaderCaps &caps,
01525                CGcontext &ctx,
01526                CGprogram &vprogram,
01527                CGprogram &fprogram,
01528                CGprogram &gprogram,
01529                pvector<CGparameter> &map) {
01530 
01531   // Initialize the return values to empty.
01532 
01533   ctx = 0;
01534   vprogram = 0;
01535   fprogram = 0;
01536   gprogram = 0;
01537 
01538   map.clear();
01539 
01540   // Make sure the shader is compiled for the target caps.
01541   // Most of the time, it will already be - this is usually a no-op.
01542 
01543   _default_caps = caps;
01544   if (!cg_compile_shader(caps)) {
01545     return false;
01546   }
01547 
01548   // If the compile routine used the ultimate profile instead of the
01549   // active one, it means the active one isn't powerful enough to
01550   // compile the shader.
01551 
01552   if (_filename->_separate) {
01553     if (_cg_vprogram != 0 && _cg_vprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_vprogram) != caps._active_vprofile) {
01554       gobj_cat.error() << "Cg vprogram too complex for driver: "
01555         << get_filename(ST_vertex) << ". Try choosing a different profile.\n";
01556       return false;
01557     }
01558     if (_cg_fprogram != 0 && _cg_fprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_fprogram) != caps._active_fprofile) {
01559       gobj_cat.error() << "Cg fprogram too complex for driver: "
01560         << get_filename(ST_fragment) << ". Try choosing a different profile.\n";
01561       return false;
01562     }
01563     if (_cg_gprogram != 0 && _cg_gprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_gprogram) != caps._active_gprofile) {
01564       gobj_cat.error() << "Cg gprogram too complex for driver: "
01565         << get_filename(ST_geometry) << ". Try choosing a different profile.\n";
01566       return false;
01567     }
01568   } else {
01569     if ((_cg_vprogram != 0 && _cg_vprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_vprogram) != caps._active_vprofile) ||
01570         (_cg_fprogram != 0 && _cg_fprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_fprogram) != caps._active_fprofile) ||
01571         (_cg_gprogram != 0 && _cg_gprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_gprogram) != caps._active_gprofile)) {
01572       gobj_cat.error() << "Cg program too complex for driver: "
01573         << get_filename() << ". Try choosing a different profile.\n";
01574       return false;
01575     }
01576   }
01577 
01578   // Build a parameter map.
01579 
01580   int n_mat = (int)_mat_spec.size();
01581   int n_tex = (int)_tex_spec.size();
01582   int n_var = (int)_var_spec.size();
01583 
01584   map.resize(n_mat + n_tex + n_var);
01585 
01586   for (int i=0; i<n_mat; i++) {
01587     const ShaderArgId &id = _mat_spec[i]._id;
01588 
01589     CGprogram prog = cg_program_from_shadertype(id._type);  // CG2 CHANGE
01590     map[id._seqno] = cgGetNamedParameter(prog, id._name.c_str());
01591   }
01592   for (int i=0; i<n_tex; i++) {
01593     const ShaderArgId &id = _tex_spec[i]._id;
01594     CGprogram prog = cg_program_from_shadertype(id._type);  // CG2 CHANGE
01595     map[id._seqno] = cgGetNamedParameter(prog, id._name.c_str());
01596     if (cgGetParameterBaseResource(map[id._seqno]) == CG_UNDEFINED) {
01597       map[id._seqno] = 0;
01598     }
01599   }
01600   for (int i=0; i<n_var; i++) {
01601     const ShaderArgId &id = _var_spec[i]._id;
01602 
01603     CGprogram prog = cg_program_from_shadertype(id._type);      // CG2 CHANGE
01604     map[id._seqno] = cgGetNamedParameter(prog, id._name.c_str());
01605     if (cgGetParameterBaseResource(map[id._seqno]) == CG_UNDEFINED) {
01606       map[id._seqno] = 0;
01607     }
01608   }
01609 
01610   // Transfer ownership of the compiled shader.
01611 
01612   ctx = _cg_context;
01613   vprogram = _cg_vprogram;
01614   fprogram = _cg_fprogram;
01615   gprogram = _cg_gprogram;
01616 
01617   _cg_context = 0;
01618   _cg_vprogram = 0;
01619   _cg_fprogram = 0;
01620   _cg_gprogram = 0;
01621 
01622   _cg_last_caps.clear();
01623 
01624   return true;
01625 }
01626 #endif  // HAVE_CG
01627 
01628 ////////////////////////////////////////////////////////////////////
01629 //     Function: Shader::Constructor
01630 //       Access: Private
01631 //  Description: Construct a Shader.
01632 ////////////////////////////////////////////////////////////////////
01633 Shader::
01634 Shader(CPT(ShaderFile) filename, CPT(ShaderFile) text, const ShaderLanguage &lang) :
01635   _filename(filename),
01636   _text(text),
01637   _error_flag(true),
01638   _parse(0),
01639   _loaded(false),
01640   _language(lang)
01641 {
01642   _error_flag = false;
01643   
01644 #ifdef HAVE_CG
01645   _cg_context = 0;
01646   _cg_vprogram = 0;
01647   _cg_fprogram = 0;
01648   _cg_gprogram = 0;
01649   _cg_vprofile = CG_PROFILE_UNKNOWN;
01650   _cg_fprofile = CG_PROFILE_UNKNOWN;
01651   _cg_gprofile = CG_PROFILE_UNKNOWN;
01652   if (_default_caps._ultimate_vprofile == 0 || _default_caps._ultimate_vprofile == CG_PROFILE_UNKNOWN) {
01653     _default_caps._active_vprofile = CG_PROFILE_UNKNOWN;
01654     _default_caps._active_fprofile = CG_PROFILE_UNKNOWN;
01655     _default_caps._ultimate_vprofile = cgGetProfile("glslv");
01656     _default_caps._ultimate_fprofile = cgGetProfile("glslf");
01657     _default_caps._ultimate_gprofile = cgGetProfile("glslg");
01658     if (_default_caps._ultimate_gprofile == CG_PROFILE_UNKNOWN) {
01659       _default_caps._ultimate_gprofile = cgGetProfile("gp4gp");
01660     }
01661   }
01662 #endif
01663   
01664   // Determine which language the shader is written in.
01665   if (_language == SL_none) {
01666     string header;
01667     parse_init();
01668     parse_line(header, true, true);
01669     if (header == "//Cg") {
01670       _language = SL_Cg;
01671     } else if (header == "//GLSL") {
01672       _language = SL_GLSL;
01673     }
01674   }
01675   
01676   if (_language == SL_Cg) {
01677 #ifdef HAVE_CG
01678     if (!_text->_separate) {
01679       cg_get_profile_from_header(_default_caps);
01680     }
01681 
01682     if (!cg_analyze_shader(_default_caps)) {
01683       _error_flag = true;
01684     }
01685 #else
01686     gobj_cat.error()
01687       << "Tried to load Cg shader, but no Cg support is enabled.\n";
01688 #endif
01689   } else if (_language == SL_GLSL) {
01690     // All of the important stuff is done in glShaderContext,
01691     // to avoid gobj getting a dependency on OpenGL.
01692     if (!_text->_separate) {
01693       gobj_cat.error()
01694         << "GLSL shaders must have separate shader bodies!\n";
01695       _error_flag = true;
01696     }
01697   } else {
01698     gobj_cat.error()
01699       << "Shader is not in a supported shader-language.\n";
01700     _error_flag = true;
01701   }
01702   if (_error_flag) {
01703     gobj_cat.error()
01704       << "Shader encountered an error.\n";
01705   }
01706 }
01707 
01708 #ifdef HAVE_CG
01709 ////////////////////////////////////////////////////////////////////
01710 //  Function: Shader::cg_get_profile_from_header
01711 //  Access: Private
01712 //  Description: Determines the appropriate active shader profile settings
01713 //               based on any profile directives stored within the shader header
01714 ////////////////////////////////////////////////////////////////////
01715 void Shader::
01716 cg_get_profile_from_header(ShaderCaps& caps) {
01717   // Note this forces profile based on what is specified in the shader
01718   // header string.  Should probably be relying on card caps eventually.
01719 
01720   string buf;
01721   parse_init();
01722 
01723   // Assume that if parse doesn't extend after a parse line then
01724   // we've reached the end of _text
01725   int lastParse;
01726 
01727   do {
01728     lastParse = _parse;
01729     parse_line(buf, true, true);
01730     int profilePos = buf.find("//Cg profile");
01731     if (profilePos >= 0) {
01732       // Scan the line for known cg2 vertex program profiles
01733       if ((int)buf.find("gp4vp") >= 0)
01734         caps._active_vprofile = cgGetProfile("gp4vp");
01735 
01736       if ((int)buf.find("gp5vp") >= 0)
01737         caps._active_vprofile = cgGetProfile("gp5vp");
01738 
01739       if ((int)buf.find("glslv") >= 0)
01740         caps._active_vprofile = cgGetProfile("glslv");
01741 
01742       if ((int)buf.find("arbvp1") >= 0)
01743         caps._active_vprofile = cgGetProfile("arbvp1");
01744 
01745       if ((int)buf.find("vp40") >= 0)
01746         caps._active_vprofile = cgGetProfile("vp40");
01747 
01748       if ((int)buf.find("vp30") >= 0)
01749         caps._active_vprofile = cgGetProfile("vp30");
01750 
01751       if ((int)buf.find("vp20") >= 0)
01752         caps._active_vprofile = cgGetProfile("vp20");
01753 
01754       if ((int)buf.find("vs_1_1") >= 0)
01755         caps._active_vprofile = cgGetProfile("vs_1_1");
01756 
01757       if ((int)buf.find("vs_2_0") >= 0)
01758         caps._active_vprofile = cgGetProfile("vs_2_0");
01759 
01760       if ((int)buf.find("vs_2_x") >= 0)
01761         caps._active_vprofile = cgGetProfile("vs_2_x");
01762 
01763       if ((int)buf.find("vs_3_0") >= 0)
01764         caps._active_vprofile = cgGetProfile("vs_3_0");
01765 
01766       if ((int)buf.find("vs_4_0") >= 0)
01767         caps._active_vprofile = cgGetProfile("vs_4_0");
01768 
01769       if ((int)buf.find("vs_5_0") >= 0)
01770         caps._active_vprofile = cgGetProfile("vs_5_0");
01771 
01772       // Scan the line for known cg2 fragment program profiles
01773       if ((int)buf.find("gp4fp") >= 0)
01774         caps._active_fprofile = cgGetProfile("gp4fp");
01775 
01776       if ((int)buf.find("gp5fp") >= 0)
01777         caps._active_fprofile = cgGetProfile("gp5fp");
01778 
01779       if ((int)buf.find("glslf") >= 0)
01780         caps._active_fprofile = cgGetProfile("glslf");
01781 
01782       if ((int)buf.find("arbfp1") >= 0)
01783         caps._active_fprofile = cgGetProfile("arbfp1");
01784 
01785       if ((int)buf.find("fp40") >= 0)
01786         caps._active_fprofile = cgGetProfile("fp40");
01787 
01788       if ((int)buf.find("fp30") >= 0)
01789         caps._active_fprofile = cgGetProfile("fp30");
01790 
01791       if ((int)buf.find("fp20") >= 0)
01792         caps._active_fprofile = cgGetProfile("fp20");
01793 
01794       if ((int)buf.find("ps_1_1") >= 0)
01795         caps._active_fprofile = cgGetProfile("ps_1_1");
01796 
01797       if ((int)buf.find("ps_1_2") >= 0)
01798         caps._active_fprofile = cgGetProfile("ps_1_2");
01799 
01800       if ((int)buf.find("ps_1_3") >= 0)
01801         caps._active_fprofile = cgGetProfile("ps_1_3");
01802 
01803       if ((int)buf.find("ps_2_0") >= 0)
01804         caps._active_fprofile = cgGetProfile("ps_2_0");
01805 
01806       if ((int)buf.find("ps_2_x") >= 0)
01807         caps._active_fprofile = cgGetProfile("ps_2_x");
01808 
01809       if ((int)buf.find("ps_3_0") >= 0)
01810         caps._active_fprofile = cgGetProfile("ps_3_0");
01811 
01812       if ((int)buf.find("ps_4_0") >= 0)
01813         caps._active_fprofile = cgGetProfile("ps_4_0");
01814 
01815       if ((int)buf.find("ps_5_0") >= 0)
01816         caps._active_fprofile = cgGetProfile("ps_5_0");
01817 
01818       // Scan the line for known cg2 geometry program profiles
01819       if ((int)buf.find("gp4gp") >= 0)
01820         caps._active_gprofile = cgGetProfile("gp4gp");
01821 
01822       if ((int)buf.find("gp5gp") >= 0)
01823         caps._active_gprofile = cgGetProfile("gp5gp");
01824 
01825       if ((int)buf.find("glslg") >= 0)
01826         caps._active_gprofile = cgGetProfile("glslg");
01827 
01828       if ((int)buf.find("gs_4_0") >= 0)
01829         caps._active_gprofile = cgGetProfile("gs_4_0");
01830 
01831       if ((int)buf.find("gs_5_0") >= 0)
01832         caps._active_gprofile = cgGetProfile("gs_5_0");
01833     }
01834   } while(_parse > lastParse);
01835 
01836 }
01837 #endif
01838 
01839 ////////////////////////////////////////////////////////////////////
01840 //     Function: Shader::Destructor
01841 //       Access: Public
01842 //  Description: Delete the compiled code, if it exists.
01843 ////////////////////////////////////////////////////////////////////
01844 Shader::
01845 ~Shader() {
01846   release_all();
01847   if (_loaded) {
01848     _load_table.erase(_filename);
01849   } else {
01850     _make_table.erase(_text);
01851   }
01852 }
01853 
01854 ////////////////////////////////////////////////////////////////////
01855 //     Function: Shader::load
01856 //       Access: Published, Static
01857 //  Description: Loads the shader with the given filename.
01858 ////////////////////////////////////////////////////////////////////
01859 PT(Shader) Shader::
01860 load(const Filename &file, const ShaderLanguage &lang) {
01861   PT(ShaderFile) sfile =  new ShaderFile(file);
01862   ShaderTable::const_iterator i = _load_table.find(sfile);
01863   if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
01864     return i->second;
01865   }
01866   PT(ShaderFile) sbody = new ShaderFile("");
01867 
01868   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
01869   if (!vfs->read_file(file, sbody->_shared, true)) {
01870     gobj_cat.error() << "Could not read shader file: " << file << "\n";
01871     return NULL;
01872   }
01873   PT(Shader) result = new Shader(sfile, sbody, lang);
01874   result->_loaded = true;
01875   _load_table[sfile] = result;
01876   return result;
01877 }
01878 
01879 ////////////////////////////////////////////////////////////////////
01880 //     Function: Shader::load
01881 //       Access: Published, Static
01882 //  Description: This variant of Shader::load loads all shader
01883 //               programs separately.
01884 ////////////////////////////////////////////////////////////////////
01885 PT(Shader) Shader::
01886 load(const ShaderLanguage &lang, const Filename &vertex, const Filename &fragment, const Filename &geometry) {
01887   PT(ShaderFile) sfile = new ShaderFile(vertex, fragment, geometry);
01888   ShaderTable::const_iterator i = _load_table.find(sfile);
01889   if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
01890     return i->second;
01891   }
01892   PT(ShaderFile) sbody = new ShaderFile("", "", "");
01893   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
01894   if (!vertex.empty() && !vfs->read_file(vertex, sbody->_vertex, true)) {
01895     gobj_cat.error() << "Could not read vertex shader file: " << vertex << "\n";
01896     return NULL;
01897   }
01898   if (!fragment.empty() && !vfs->read_file(fragment, sbody->_fragment, true)) {
01899     gobj_cat.error() << "Could not read fragment shader file: " << vertex << "\n";
01900     return NULL;
01901   }
01902   if (!geometry.empty() && !vfs->read_file(geometry, sbody->_geometry, true)) {
01903     gobj_cat.error() << "Could not read geometry shader file: " << vertex << "\n";
01904     return NULL;
01905   }
01906   PT(Shader) result = new Shader(sfile, sbody, lang);
01907   result->_loaded = true;
01908   _load_table[sfile] = result;
01909   return result;
01910 }
01911 
01912 //////////////////////////////////////////////////////////////////////
01913 //     Function: Shader::make
01914 //       Access: Published, Static
01915 //  Description: Loads the shader, using the string as shader body.
01916 //////////////////////////////////////////////////////////////////////
01917 PT(Shader) Shader::
01918 make(const string &body, const ShaderLanguage &lang) {
01919   PT(ShaderFile) sbody = new ShaderFile(body);
01920   ShaderTable::const_iterator i = _make_table.find(sbody);
01921   if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
01922     return i->second;
01923   }
01924   PT(ShaderFile) sfile = new ShaderFile("created-shader");
01925   PT(Shader) result = new Shader(sfile, sbody, lang);
01926   _make_table[sbody] = result;
01927   if (dump_generated_shaders) {
01928     ostringstream fns;
01929     int index = _shaders_generated ++;
01930     fns << "genshader" << index;
01931     string fn = fns.str();
01932     gobj_cat.warning() << "Dumping shader: " << fn << "\n";
01933     pofstream s;
01934     s.open(fn.c_str());
01935     s << body;
01936     s.close();
01937   }
01938   return result;
01939 }
01940 
01941 //////////////////////////////////////////////////////////////////////
01942 //     Function: Shader::make
01943 //       Access: Published, Static
01944 //  Description: Loads the shader, using the strings as shader bodies.
01945 //////////////////////////////////////////////////////////////////////
01946 PT(Shader) Shader::
01947 make(const ShaderLanguage &lang, const string &vertex, const string &fragment, const string &geometry) {
01948   PT(ShaderFile) sbody = new ShaderFile(vertex, fragment, geometry);
01949   ShaderTable::const_iterator i = _make_table.find(sbody);
01950   if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
01951     return i->second;
01952   }
01953   PT(ShaderFile) sfile = new ShaderFile("created-shader");
01954   PT(Shader) result = new Shader(sfile, sbody, lang);
01955   _make_table[sbody] = result;
01956   return result;
01957 }
01958 
01959 ////////////////////////////////////////////////////////////////////
01960 //     Function: Shader::parse_init
01961 //       Access: Public
01962 //  Description: Set a 'parse pointer' to the beginning of the shader.
01963 ////////////////////////////////////////////////////////////////////
01964 void Shader::
01965 parse_init() {
01966   _parse = 0;
01967 }
01968 
01969 ////////////////////////////////////////////////////////////////////
01970 //     Function: Shader::parse_line
01971 //       Access: Public
01972 //  Description: Parse a line of text. If 'lt' is true, trim blanks
01973 //               from the left end of the line. If 'rt' is true, trim
01974 //               blanks from the right end (the newline is always
01975 //               trimmed).
01976 ////////////////////////////////////////////////////////////////////
01977 void Shader::
01978 parse_line(string &result, bool lt, bool rt) {
01979   nassertv(!_text->_separate);
01980   int len = _text->_shared.size();
01981   int head = _parse;
01982   int tail = head;
01983   while ((tail < len) && (_text->_shared[tail] != '\n')) {
01984     tail++;
01985   }
01986   if (tail < len) {
01987     _parse = tail+1;
01988   } else {
01989     _parse = tail;
01990   }
01991   if (lt) {
01992     while ((head < tail)&&(isspace(_text->_shared[head]))) head++;
01993     while ((tail > head)&&(isspace(_text->_shared[tail-1]))) tail--;
01994   }
01995   result = _text->_shared.substr(head, tail-head);
01996 }
01997 
01998 ////////////////////////////////////////////////////////////////////
01999 //     Function: Shader::parse_upto
02000 //       Access: Public
02001 //  Description: Parse lines until you read a line that matches the
02002 //               specified pattern.  Returns all the preceding lines,
02003 //               and if the include flag is set, returns the final
02004 //               line as well.
02005 ////////////////////////////////////////////////////////////////////
02006 void Shader::
02007 parse_upto(string &result, string pattern, bool include) {
02008   nassertv(!_text->_separate);
02009   GlobPattern endpat(pattern);
02010   int start = _parse;
02011   int last = _parse;
02012   while (_parse < (int)(_text->_shared.size())) {
02013     string t;
02014     parse_line(t, true, true);
02015     if (endpat.matches(t)) break;
02016     last = _parse;
02017   }
02018   if (include) {
02019     result = _text->_shared.substr(start, _parse - start);
02020   } else {
02021     result = _text->_shared.substr(start, last - start);
02022   }
02023 }
02024 
02025 ////////////////////////////////////////////////////////////////////
02026 //     Function: Shader::parse_rest
02027 //       Access: Public
02028 //  Description: Returns the rest of the text from the current
02029 //               parse location.
02030 ////////////////////////////////////////////////////////////////////
02031 void Shader::
02032 parse_rest(string &result) {
02033   nassertv(!_text->_separate);
02034   result = _text->_shared.substr(_parse, _text->_shared.size() - _parse);
02035 }
02036 
02037 ////////////////////////////////////////////////////////////////////
02038 //     Function: Shader::parse_eof
02039 //       Access: Public
02040 //  Description: Returns true if the parse pointer is at the end of
02041 //               the shader.
02042 ////////////////////////////////////////////////////////////////////
02043 bool Shader::
02044 parse_eof() {
02045   return (int)_text->_shared.size() == _parse;
02046 }
02047 
02048 ////////////////////////////////////////////////////////////////////
02049 //     Function: Shader::prepare
02050 //       Access: Published
02051 //  Description: Indicates that the shader should be enqueued to be
02052 //               prepared in the indicated prepared_objects at the
02053 //               beginning of the next frame.  This will ensure the
02054 //               texture is already loaded into texture memory if it
02055 //               is expected to be rendered soon.
02056 //
02057 //               Use this function instead of prepare_now() to preload
02058 //               textures from a user interface standpoint.
02059 ////////////////////////////////////////////////////////////////////
02060 void Shader::
02061 prepare(PreparedGraphicsObjects *prepared_objects) {
02062   prepared_objects->enqueue_shader(this);
02063 }
02064 
02065 ////////////////////////////////////////////////////////////////////
02066 //     Function: Shader::is_prepared
02067 //       Access: Published
02068 //  Description: Returns true if the shader has already been prepared
02069 //               or enqueued for preparation on the indicated GSG,
02070 //               false otherwise.
02071 ////////////////////////////////////////////////////////////////////
02072 bool Shader::
02073 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
02074   Contexts::const_iterator ci;
02075   ci = _contexts.find(prepared_objects);
02076   if (ci != _contexts.end()) {
02077     return true;
02078   }
02079   return prepared_objects->is_shader_queued(this);
02080 }
02081 
02082 ////////////////////////////////////////////////////////////////////
02083 //     Function: Shader::release
02084 //       Access: Published
02085 //  Description: Frees the texture context only on the indicated object,
02086 //               if it exists there.  Returns true if it was released,
02087 //               false if it had not been prepared.
02088 ////////////////////////////////////////////////////////////////////
02089 bool Shader::
02090 release(PreparedGraphicsObjects *prepared_objects) {
02091   Contexts::iterator ci;
02092   ci = _contexts.find(prepared_objects);
02093   if (ci != _contexts.end()) {
02094     ShaderContext *sc = (*ci).second;
02095     if (sc != (ShaderContext *)NULL) {
02096       prepared_objects->release_shader(sc);
02097     } else {
02098       _contexts.erase(ci);
02099     }
02100     return true;
02101   }
02102 
02103   // Maybe it wasn't prepared yet, but it's about to be.
02104   return prepared_objects->dequeue_shader(this);
02105 }
02106 
02107 ////////////////////////////////////////////////////////////////////
02108 //     Function: Shader::prepare_now
02109 //       Access: Published
02110 //  Description: Creates a context for the shader on the particular
02111 //               GSG, if it does not already exist.  Returns the new
02112 //               (or old) ShaderContext.  This assumes that the
02113 //               GraphicsStateGuardian is the currently active
02114 //               rendering context and that it is ready to accept new
02115 //               textures.  If this is not necessarily the case, you
02116 //               should use prepare() instead.
02117 //
02118 //               Normally, this is not called directly except by the
02119 //               GraphicsStateGuardian; a shader does not need to be
02120 //               explicitly prepared by the user before it may be
02121 //               rendered.
02122 ////////////////////////////////////////////////////////////////////
02123 ShaderContext *Shader::
02124 prepare_now(PreparedGraphicsObjects *prepared_objects,
02125             GraphicsStateGuardianBase *gsg) {
02126   Contexts::const_iterator ci;
02127   ci = _contexts.find(prepared_objects);
02128   if (ci != _contexts.end()) {
02129     return (*ci).second;
02130   }
02131 
02132   ShaderContext *tc = prepared_objects->prepare_shader_now(this, gsg);
02133   _contexts[prepared_objects] = tc;
02134 
02135   return tc;
02136 }
02137 
02138 ////////////////////////////////////////////////////////////////////
02139 //     Function: Shader::clear_prepared
02140 //       Access: Private
02141 //  Description: Removes the indicated PreparedGraphicsObjects table
02142 //               from the Shader's table, without actually releasing
02143 //               the texture.  This is intended to be called only from
02144 //               PreparedGraphicsObjects::release_texture(); it should
02145 //               never be called by user code.
02146 ////////////////////////////////////////////////////////////////////
02147 void Shader::
02148 clear_prepared(PreparedGraphicsObjects *prepared_objects) {
02149   Contexts::iterator ci;
02150   ci = _contexts.find(prepared_objects);
02151   if (ci != _contexts.end()) {
02152     _contexts.erase(ci);
02153   } else {
02154     // If this assertion fails, clear_prepared() was given a
02155     // prepared_objects which the texture didn't know about.
02156     nassertv(false);
02157   }
02158 }
02159 
02160 ////////////////////////////////////////////////////////////////////
02161 //     Function: Shader::release_all
02162 //       Access: Published
02163 //  Description: Frees the context allocated on all objects for which
02164 //               the texture has been declared.  Returns the number of
02165 //               contexts which have been freed.
02166 ////////////////////////////////////////////////////////////////////
02167 int Shader::
02168 release_all() {
02169   // We have to traverse a copy of the _contexts list, because the
02170   // PreparedGraphicsObjects object will call clear_prepared() in response
02171   // to each release_texture(), and we don't want to be modifying the
02172   // _contexts list while we're traversing it.
02173   Contexts temp = _contexts;
02174   int num_freed = (int)_contexts.size();
02175 
02176   Contexts::const_iterator ci;
02177   for (ci = temp.begin(); ci != temp.end(); ++ci) {
02178     PreparedGraphicsObjects *prepared_objects = (*ci).first;
02179     ShaderContext *sc = (*ci).second;
02180     if (sc != (ShaderContext *)NULL) {
02181       prepared_objects->release_shader(sc);
02182     }
02183   }
02184 
02185   // There might still be some outstanding contexts in the map, if
02186   // there were any NULL pointers there.  Eliminate them.
02187   _contexts.clear();
02188 
02189   return num_freed;
02190 }
02191 
02192 ////////////////////////////////////////////////////////////////////
02193 //     Function: Shader::ShaderCapabilities::clear()
02194 //       Access: Public
02195 //  Description:
02196 ////////////////////////////////////////////////////////////////////
02197 void Shader::ShaderCaps::
02198 clear() {
02199   _supports_glsl = false;
02200   
02201 #ifdef HAVE_CG
02202   _active_vprofile = CG_PROFILE_UNKNOWN;
02203   _active_fprofile = CG_PROFILE_UNKNOWN;
02204   _active_gprofile = CG_PROFILE_UNKNOWN;
02205   _ultimate_vprofile = CG_PROFILE_UNKNOWN;
02206   _ultimate_fprofile = CG_PROFILE_UNKNOWN;
02207   _ultimate_gprofile = CG_PROFILE_UNKNOWN;
02208 #endif
02209 }
02210 
02211 ////////////////////////////////////////////////////////////////////
02212 //     Function: Shader::register_with_read_factory
02213 //       Access: Public, Static
02214 //  Description:
02215 ////////////////////////////////////////////////////////////////////
02216 void Shader::
02217 register_with_read_factory() {
02218   // IMPLEMENT ME
02219 }
02220 
 All Classes Functions Variables Enumerations