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   default:           return Shader::SAT_unknown;
01089   }
01090 }
01091 
01092 ////////////////////////////////////////////////////////////////////
01093 //     Function: Shader::cg_parameter_dir
01094 //       Access: Private
01095 //  Description:
01096 ////////////////////////////////////////////////////////////////////
01097 Shader::ShaderArgDir Shader::
01098 cg_parameter_dir(CGparameter p) {
01099   switch (cgGetParameterDirection(p)) {
01100   case CG_IN:    return Shader::SAD_in;
01101   case CG_OUT:   return Shader::SAD_out;
01102   case CG_INOUT: return Shader::SAD_inout;
01103   default:       return Shader::SAD_unknown;
01104   }
01105 }
01106 
01107 ////////////////////////////////////////////////////////////////////
01108 //     Function: Shader::cg_release_resources
01109 //       Access: Private
01110 //  Description: xyz
01111 ////////////////////////////////////////////////////////////////////
01112 void Shader::
01113 cg_release_resources() {
01114   if (_cg_vprogram != 0) {
01115     cgDestroyProgram(_cg_vprogram);
01116     _cg_vprogram = 0;
01117   }
01118   if (_cg_fprogram != 0) {
01119     cgDestroyProgram(_cg_fprogram);
01120     _cg_fprogram = 0;
01121   }
01122   if (_cg_gprogram != 0) {
01123     cgDestroyProgram(_cg_gprogram);
01124     _cg_gprogram = 0;
01125   }
01126   if (_cg_context != 0) {
01127     cgDestroyContext(_cg_context);
01128     _cg_context = 0;
01129   }
01130 }
01131 
01132 ////////////////////////////////////////////////////////////////////
01133 //     Function: Shader::cg_compile_entry_point
01134 //       Access: Private
01135 //  Description: xyz
01136 ////////////////////////////////////////////////////////////////////
01137 CGprogram Shader::
01138 cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType type) {
01139   CGprogram prog;
01140   CGerror err;
01141   const char *compiler_args[100];
01142   const string text = get_text(type);
01143   int nargs = 0;
01144 
01145   int active, ultimate;
01146 
01147   switch(type) {
01148     case ST_vertex:
01149       active   = caps._active_vprofile;
01150       ultimate = caps._ultimate_vprofile;
01151       break;
01152 
01153     case ST_fragment:
01154       active   = caps._active_fprofile;
01155       ultimate = caps._ultimate_fprofile;
01156       break;
01157 
01158     case ST_geometry:
01159       active   = caps._active_gprofile;
01160       ultimate = caps._ultimate_gprofile;
01161       break;
01162   };
01163 
01164   cgGetError();
01165 
01166   if (type == ST_fragment && caps._bug_list.count(SBUG_ati_draw_buffers)) {
01167     compiler_args[nargs++] = "-po";
01168     compiler_args[nargs++] = "ATI_draw_buffers";
01169   }
01170   compiler_args[nargs] = 0;
01171 
01172   if ((active != (int)CG_PROFILE_UNKNOWN) && (active != ultimate)) {
01173     prog = cgCreateProgram(_cg_context, CG_SOURCE, text.c_str(),
01174                            (CGprofile)active, entry, (const char **)compiler_args);
01175     err = cgGetError();
01176     if (err == CG_NO_ERROR) {
01177       return prog;
01178     }
01179     if (prog != 0) {
01180       cgDestroyProgram(prog);
01181     }
01182   }
01183 
01184   prog = cgCreateProgram(_cg_context, CG_SOURCE, text.c_str(),
01185                          (CGprofile)ultimate, entry, (const char **)NULL);
01186   err = cgGetError();
01187   if (err == CG_NO_ERROR) {
01188     return prog;
01189   }
01190   if (err == CG_COMPILER_ERROR) {
01191     string listing = cgGetLastListing(_cg_context);
01192     vector_string errlines;
01193     tokenize(listing, errlines, "\n");
01194     for (int i=0; i<(int)errlines.size(); i++) {
01195       string line = trim(errlines[i]);
01196       if (line != "") {
01197         gobj_cat.error() << get_filename(type) << ": " << errlines[i] << "\n";
01198       }
01199     }
01200   } else {
01201     gobj_cat.error() << get_filename(type) << ": " << cgGetErrorString(err) << "\n";
01202   }
01203   if (prog != 0) {
01204     cgDestroyProgram(prog);
01205   }
01206 
01207   return 0;
01208 }
01209 
01210 ////////////////////////////////////////////////////////////////////
01211 //     Function: Shader::cg_compile_shader
01212 //       Access: Private
01213 //  Description: Compiles a Cg shader for a given set of capabilities.
01214 //               If successful, the shader is stored in the instance
01215 //               variables _cg_context, _cg_vprogram, _cg_fprogram.
01216 ////////////////////////////////////////////////////////////////////
01217 bool Shader::
01218 cg_compile_shader(const ShaderCaps &caps) {
01219 
01220   // If we already tried compiling for this set of caps, there's no point
01221   // trying again.  Just return the results of the previous compile.
01222   if (caps == _cg_last_caps) {
01223     if (_cg_context == 0) {
01224       return false;
01225     } else {
01226       return true;
01227     }
01228   }
01229 
01230   _cg_last_caps = caps;
01231 
01232   _cg_context = cgCreateContext();
01233 
01234   if (!_text->_separate) {
01235     gobj_cat.debug() << "Compiling Shader: \n" << _text << "\n";
01236   }
01237 
01238   if (_cg_context == 0) {
01239     gobj_cat.error() << "could not create a Cg context object.\n";
01240     return false;
01241   }
01242 
01243   if (!_text->_separate || !_text->_vertex.empty()) {
01244     _cg_vprogram = cg_compile_entry_point("vshader", caps, ST_vertex);
01245     if (_cg_vprogram == 0) {
01246       cg_release_resources();
01247       return false;
01248     }
01249   }
01250 
01251   if (!_text->_separate || !_text->_fragment.empty()) {
01252     _cg_fprogram = cg_compile_entry_point("fshader", caps, ST_fragment);
01253     if (_cg_fprogram == 0) {
01254       cg_release_resources();
01255       return false;
01256     }
01257   }
01258 
01259   if ((_text->_separate && !_text->_geometry.empty()) || (!_text->_separate && _text->_shared.find("gshader") != -1)) {
01260     _cg_gprogram = cg_compile_entry_point("gshader", caps, ST_geometry);
01261     if (_cg_gprogram == 0) {
01262       cg_release_resources();
01263       return false;
01264     }
01265   }
01266 
01267   if (_cg_vprogram == 0 && _cg_fprogram == 0 && _cg_gprogram == 0) {
01268     gobj_cat.error() << "Shader must at least have one program!\n";
01269     cg_release_resources();
01270     return false;
01271   }
01272 
01273   return true;
01274 }
01275 
01276 ////////////////////////////////////////////////////////////////////
01277 //     Function: Shader::cg_analyze_entry_point
01278 //       Access: Private
01279 //  Description:
01280 ////////////////////////////////////////////////////////////////////
01281 bool Shader::
01282 cg_analyze_entry_point(CGprogram prog, ShaderType type) {
01283   CGparameter parameter;
01284   bool success = true;
01285   for (parameter = cgGetFirstLeafParameter(prog, CG_PROGRAM);
01286        parameter != 0;
01287        parameter = cgGetNextLeafParameter(parameter)) {
01288     CGenum vbl = cgGetParameterVariability(parameter);
01289 
01290     if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) {
01291       ShaderArgId id;
01292       id._name = cgGetParameterName(parameter);
01293 
01294       id._type  = type;
01295       id._seqno = -1;
01296       success &= compile_parameter(id,
01297                                    cg_parameter_type(parameter),
01298                                    cg_parameter_dir(parameter),
01299                                    (vbl == CG_VARYING),
01300                                    gobj_cat.get_safe_ptr());
01301     }
01302   }
01303   return success;
01304 }
01305 
01306 
01307 ////////////////////////////////////////////////////////////////////
01308 //     Function: Shader::cg_analyze_shader
01309 //       Access: Private
01310 //  Description: This subroutine analyzes the parameters of a Cg
01311 //               shader. The output is stored in instance variables:
01312 //               _mat_spec, _var_spec, and _tex_spec.
01313 //
01314 //               In order to do this, it is necessary to compile the
01315 //               shader.  It would be a waste of CPU time to compile
01316 //               the shader, analyze the parameters, and then discard
01317 //               the compiled shader.  This would force us to compile it
01318 //               again later, when we need to build the ShaderContext.
01319 //               Instead, we cache the compiled Cg program in instance
01320 //               variables.  Later, a ShaderContext can pull the
01321 //               compiled shader from these instance vars.
01322 //
01323 //               To compile a shader, you need to first choose a profile.
01324 //               There are two contradictory objectives:
01325 //
01326 //               1. If you don't use the gsg's active profile,
01327 //               then the cached compiled shader will not be useful to
01328 //               the ShaderContext.
01329 //
01330 //               2. If you use too weak a profile, then the shader may
01331 //               not compile.  So to guarantee success, you should use
01332 //               the ultimate profile.
01333 //
01334 //               To resolve this conflict, we try the active profile
01335 //               first, and if that doesn't work, we try the ultimate
01336 //               profile.
01337 //
01338 ////////////////////////////////////////////////////////////////////
01339 bool Shader::
01340 cg_analyze_shader(const ShaderCaps &caps) {
01341 
01342   if (!cg_compile_shader(caps)) {
01343     return false;
01344   }
01345 
01346   if (_cg_fprogram != 0) {
01347      if (!cg_analyze_entry_point(_cg_fprogram, ST_fragment)) {
01348       cg_release_resources();
01349       clear_parameters();
01350       return false;
01351     }
01352   }
01353 
01354   if (_var_spec.size() != 0) {
01355     gobj_cat.error() << "Cannot use vtx parameters in an fshader\n";
01356     cg_release_resources();
01357     clear_parameters();
01358     return false;
01359   }
01360 
01361   if (_cg_vprogram != 0) {
01362     if (!cg_analyze_entry_point(_cg_vprogram, ST_vertex)) {
01363       cg_release_resources();
01364       clear_parameters();
01365       return false;
01366     }
01367   }
01368 
01369   if (_cg_gprogram != 0) {
01370     if (!cg_analyze_entry_point(_cg_gprogram, ST_geometry)) {
01371       cg_release_resources();
01372       clear_parameters();
01373       return false;
01374     }
01375   }
01376 
01377   // Assign sequence numbers to all parameters.
01378   int seqno = 0;
01379   for (int i=0; i<(int)_mat_spec.size(); i++) {
01380     _mat_spec[i]._id._seqno = seqno++;
01381   }
01382   for (int i=0; i<(int)_tex_spec.size(); i++) {
01383     _tex_spec[i]._id._seqno = seqno++;
01384   }
01385   for (int i=0; i<(int)_var_spec.size(); i++) {
01386     _var_spec[i]._id._seqno = seqno++;
01387   }
01388 
01389   // DEBUG: output the generated program
01390   if (gobj_cat.is_debug()) {
01391     const char *vertex_program;
01392     const char *pixel_program;
01393     const char *geometry_program;
01394 
01395     if (_cg_vprogram != 0) {
01396       vertex_program   = cgGetProgramString (_cg_vprogram, CG_COMPILED_PROGRAM);
01397       gobj_cat.debug() << vertex_program << "\n";
01398     }
01399     if (_cg_fprogram != 0) {
01400       pixel_program    = cgGetProgramString (_cg_fprogram, CG_COMPILED_PROGRAM);
01401       gobj_cat.debug() << pixel_program << "\n";
01402     }
01403     if (_cg_gprogram != 0) {
01404       geometry_program = cgGetProgramString (_cg_gprogram, CG_COMPILED_PROGRAM);
01405       gobj_cat.debug() << geometry_program << "\n";
01406     }
01407   }
01408 
01409   //  // The following code is present to work around a bug in the Cg compiler.
01410   //  // It does not generate correct code for shadow map lookups when using arbfp1.
01411   //  // This is a particularly onerous limitation, given that arbfp1 is the only
01412   //  // Cg target that works on radeons.  I suspect this is an intentional
01413   //  // omission on nvidia's part.  The following code fetches the output listing,
01414   //  // detects the error, repairs the code, and resumbits the repaired code to Cg.
01415   //  if ((_cg_fprofile == CG_PROFILE_ARBFP1) && (gsghint->_supports_shadow_filter)) {
01416   //    bool shadowunit[32];
01417   //    bool anyshadow = false;
01418   //    memset(shadowunit, 0, sizeof(shadowunit));
01419   //    vector_string lines;
01420   //    tokenize(cgGetProgramString(_cg_program[SHADER_type_frag],
01421   //                                CG_COMPILED_PROGRAM), lines, "\n");
01422   //    // figure out which texture units contain shadow maps.
01423   //    for (int lineno=0; lineno<(int)lines.size(); lineno++) {
01424   //      if (lines[lineno].compare(0,21,"#var sampler2DSHADOW ")) {
01425   //        continue;
01426   //      }
01427   //      vector_string fields;
01428   //      tokenize(lines[lineno], fields, ":");
01429   //      if (fields.size()!=5) {
01430   //        continue;
01431   //      }
01432   //      vector_string words;
01433   //      tokenize(trim(fields[2]), words, " ");
01434   //      if (words.size()!=2) {
01435   //        continue;
01436   //      }
01437   //      int unit = atoi(words[1].c_str());
01438   //      if ((unit < 0)||(unit >= 32)) {
01439   //        continue;
01440   //      }
01441   //      anyshadow = true;
01442   //      shadowunit[unit] = true;
01443   //    }
01444   //    // modify all TEX statements that use the relevant texture units.
01445   //    if (anyshadow) {
01446   //      for (int lineno=0; lineno<(int)lines.size(); lineno++) {
01447   //        if (lines[lineno].compare(0,4,"TEX ")) {
01448   //          continue;
01449   //        }
01450   //        vector_string fields;
01451   //        tokenize(lines[lineno], fields, ",");
01452   //        if ((fields.size()!=4)||(trim(fields[3]) != "2D;")) {
01453   //          continue;
01454   //        }
01455   //        vector_string texunitf;
01456   //        tokenize(trim(fields[2]), texunitf, "[]");
01457   //        if ((texunitf.size()!=3)||(texunitf[0] != "texture")||(texunitf[2]!="")) {
01458   //          continue;
01459   //        }
01460   //        int unit = atoi(texunitf[1].c_str());
01461   //        if ((unit < 0) || (unit >= 32) || (shadowunit[unit]==false)) {
01462   //          continue;
01463   //        }
01464   //        lines[lineno] = fields[0]+","+fields[1]+","+fields[2]+", SHADOW2D;";
01465   //      }
01466   //      string result = "!!ARBfp1.0\nOPTION ARB_fragment_program_shadow;\n";
01467   //      for (int lineno=1; lineno<(int)lines.size(); lineno++) {
01468   //        result += (lines[lineno] + "\n");
01469   //      }
01470   //      _cg_program[2] = _cg_program[SHADER_type_frag];
01471   //      _cg_program[SHADER_type_frag] =
01472   //        cgCreateProgram(_cg_context, CG_OBJECT, result.c_str(),
01473   //                        _cg_profile[SHADER_type_frag], "fshader", (const char**)NULL);
01474   //      cg_report_errors(s->get_name(), _cg_context);
01475   //      if (_cg_program[SHADER_type_frag]==0) {
01476   //        release_resources();
01477   //        return false;
01478   //      }
01479   //    }
01480   //  }
01481 
01482   return true;
01483 }
01484 
01485 ////////////////////////////////////////////////////////////////////
01486 //     Function: Shader::cg_program_from_shadertype
01487 //       Access: Private
01488 //  Description: Returns the CGprogram of the given shadertype
01489 //               that belongs to this shader.
01490 ////////////////////////////////////////////////////////////////////
01491 CGprogram Shader::
01492 cg_program_from_shadertype(ShaderType type) {
01493   CGprogram prog = 0;
01494 
01495   switch(type) {
01496     case ST_vertex:
01497       prog = _cg_vprogram;
01498       break;
01499 
01500     case ST_fragment:
01501       prog = _cg_fprogram;
01502       break;
01503 
01504     case ST_geometry:
01505       prog = _cg_gprogram;
01506       break;
01507   };
01508 
01509   return prog;
01510 }
01511 
01512 ////////////////////////////////////////////////////////////////////
01513 //     Function: Shader::cg_compile_for
01514 //       Access: Public
01515 //  Description: This routine is used by the ShaderContext constructor
01516 //               to compile the shader.  The CGprogram
01517 //               objects are turned over to the ShaderContext, we no
01518 //               longer own them.
01519 ////////////////////////////////////////////////////////////////////
01520 bool Shader::
01521 cg_compile_for(const ShaderCaps &caps,
01522                CGcontext &ctx,
01523                CGprogram &vprogram,
01524                CGprogram &fprogram,
01525                CGprogram &gprogram,
01526                pvector<CGparameter> &map) {
01527 
01528   // Initialize the return values to empty.
01529 
01530   ctx = 0;
01531   vprogram = 0;
01532   fprogram = 0;
01533   gprogram = 0;
01534 
01535   map.clear();
01536 
01537   // Make sure the shader is compiled for the target caps.
01538   // Most of the time, it will already be - this is usually a no-op.
01539 
01540   _default_caps = caps;
01541   if (!cg_compile_shader(caps)) {
01542     return false;
01543   }
01544 
01545   // If the compile routine used the ultimate profile instead of the
01546   // active one, it means the active one isn't powerful enough to
01547   // compile the shader.
01548 
01549   if (_filename->_separate) {
01550     if (_cg_vprogram != 0 && _cg_vprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_vprogram) != caps._active_vprofile) {
01551       gobj_cat.error() << "Cg vprogram too complex for driver: "
01552         << get_filename(ST_vertex) << ". Try choosing a different profile.\n";
01553       return false;
01554     }
01555     if (_cg_fprogram != 0 && _cg_fprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_fprogram) != caps._active_fprofile) {
01556       gobj_cat.error() << "Cg fprogram too complex for driver: "
01557         << get_filename(ST_fragment) << ". Try choosing a different profile.\n";
01558       return false;
01559     }
01560     if (_cg_gprogram != 0 && _cg_gprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_gprogram) != caps._active_gprofile) {
01561       gobj_cat.error() << "Cg gprogram too complex for driver: "
01562         << get_filename(ST_geometry) << ". Try choosing a different profile.\n";
01563       return false;
01564     }
01565   } else {
01566     if ((_cg_vprogram != 0 && _cg_vprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_vprogram) != caps._active_vprofile) ||
01567         (_cg_fprogram != 0 && _cg_fprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_fprogram) != caps._active_fprofile) ||
01568         (_cg_gprogram != 0 && _cg_gprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_gprogram) != caps._active_gprofile)) {
01569       gobj_cat.error() << "Cg program too complex for driver: "
01570         << get_filename() << ". Try choosing a different profile.\n";
01571       return false;
01572     }
01573   }
01574 
01575   // Build a parameter map.
01576 
01577   int n_mat = (int)_mat_spec.size();
01578   int n_tex = (int)_tex_spec.size();
01579   int n_var = (int)_var_spec.size();
01580 
01581   map.resize(n_mat + n_tex + n_var);
01582 
01583   for (int i=0; i<n_mat; i++) {
01584     const ShaderArgId &id = _mat_spec[i]._id;
01585 
01586     CGprogram prog = cg_program_from_shadertype(id._type);  // CG2 CHANGE
01587     map[id._seqno] = cgGetNamedParameter(prog, id._name.c_str());
01588   }
01589   for (int i=0; i<n_tex; i++) {
01590     const ShaderArgId &id = _tex_spec[i]._id;
01591     CGprogram prog = cg_program_from_shadertype(id._type);  // CG2 CHANGE
01592     map[id._seqno] = cgGetNamedParameter(prog, id._name.c_str());
01593     if (cgGetParameterBaseResource(map[id._seqno]) == CG_UNDEFINED) {
01594       map[id._seqno] = 0;
01595     }
01596   }
01597   for (int i=0; i<n_var; i++) {
01598     const ShaderArgId &id = _var_spec[i]._id;
01599 
01600     CGprogram prog = cg_program_from_shadertype(id._type);      // CG2 CHANGE
01601     map[id._seqno] = cgGetNamedParameter(prog, id._name.c_str());
01602     if (cgGetParameterBaseResource(map[id._seqno]) == CG_UNDEFINED) {
01603       map[id._seqno] = 0;
01604     }
01605   }
01606 
01607   // Transfer ownership of the compiled shader.
01608 
01609   ctx = _cg_context;
01610   vprogram = _cg_vprogram;
01611   fprogram = _cg_fprogram;
01612   gprogram = _cg_gprogram;
01613 
01614   _cg_context = 0;
01615   _cg_vprogram = 0;
01616   _cg_fprogram = 0;
01617   _cg_gprogram = 0;
01618 
01619   _cg_last_caps.clear();
01620 
01621   return true;
01622 }
01623 #endif  // HAVE_CG
01624 
01625 ////////////////////////////////////////////////////////////////////
01626 //     Function: Shader::Constructor
01627 //       Access: Private
01628 //  Description: Construct a Shader.
01629 ////////////////////////////////////////////////////////////////////
01630 Shader::
01631 Shader(CPT(ShaderFile) filename, CPT(ShaderFile) text, const ShaderLanguage &lang) :
01632   _filename(filename),
01633   _text(text),
01634   _error_flag(true),
01635   _parse(0),
01636   _loaded(false),
01637   _language(lang)
01638 {
01639   _error_flag = false;
01640   
01641 #ifdef HAVE_CG
01642   _cg_context = 0;
01643   _cg_vprogram = 0;
01644   _cg_fprogram = 0;
01645   _cg_gprogram = 0;
01646   _cg_vprofile = CG_PROFILE_UNKNOWN;
01647   _cg_fprofile = CG_PROFILE_UNKNOWN;
01648   _cg_gprofile = CG_PROFILE_UNKNOWN;
01649   if (_default_caps._ultimate_vprofile == 0 || _default_caps._ultimate_vprofile == CG_PROFILE_UNKNOWN) {
01650     _default_caps._active_vprofile = CG_PROFILE_UNKNOWN;
01651     _default_caps._active_fprofile = CG_PROFILE_UNKNOWN;
01652     _default_caps._ultimate_vprofile = cgGetProfile("glslv");
01653     _default_caps._ultimate_fprofile = cgGetProfile("glslf");
01654     _default_caps._ultimate_gprofile = cgGetProfile("glslg");
01655     if (_default_caps._ultimate_gprofile == CG_PROFILE_UNKNOWN) {
01656       _default_caps._ultimate_gprofile = cgGetProfile("gp4gp");
01657     }
01658   }
01659 #endif
01660   
01661   // Determine which language the shader is written in.
01662   if (_language == SL_none) {
01663     string header;
01664     parse_init();
01665     parse_line(header, true, true);
01666     if (header == "//Cg") {
01667       _language = SL_Cg;
01668     } else if (header == "//GLSL") {
01669       _language = SL_GLSL;
01670     }
01671   }
01672   
01673   if (_language == SL_Cg) {
01674 #ifdef HAVE_CG
01675     if (!_text->_separate) {
01676       cg_get_profile_from_header(_default_caps);
01677     }
01678 
01679     if (!cg_analyze_shader(_default_caps)) {
01680       _error_flag = true;
01681     }
01682 #else
01683     gobj_cat.error()
01684       << "Tried to load Cg shader, but no Cg support is enabled.\n";
01685 #endif
01686   } else if (_language == SL_GLSL) {
01687     // All of the important stuff is done in glShaderContext,
01688     // to avoid gobj getting a dependency on OpenGL.
01689     if (!_text->_separate) {
01690       gobj_cat.error()
01691         << "GLSL shaders must have separate shader bodies!\n";
01692       _error_flag = true;
01693     }
01694   } else {
01695     gobj_cat.error()
01696       << "Shader is not in a supported shader-language.\n";
01697     _error_flag = true;
01698   }
01699   if (_error_flag) {
01700     gobj_cat.error()
01701       << "Shader encountered an error.\n";
01702   }
01703 }
01704 
01705 #ifdef HAVE_CG
01706 ////////////////////////////////////////////////////////////////////
01707 //  Function: Shader::cg_get_profile_from_header
01708 //  Access: Private
01709 //  Description: Determines the appropriate active shader profile settings
01710 //               based on any profile directives stored within the shader header
01711 ////////////////////////////////////////////////////////////////////
01712 void Shader::
01713 cg_get_profile_from_header(ShaderCaps& caps) {
01714   // Note this forces profile based on what is specified in the shader
01715   // header string.  Should probably be relying on card caps eventually.
01716 
01717   string buf;
01718   parse_init();
01719 
01720   // Assume that if parse doesn't extend after a parse line then
01721   // we've reached the end of _text
01722   int lastParse;
01723 
01724   do {
01725     lastParse = _parse;
01726     parse_line(buf, true, true);
01727     int profilePos = buf.find("//Cg profile");
01728     if (profilePos >= 0) {
01729       // Scan the line for known cg2 vertex program profiles
01730       if ((int)buf.find("gp4vp") >= 0)
01731         caps._active_vprofile = cgGetProfile("gp4vp");
01732 
01733       if ((int)buf.find("gp5vp") >= 0)
01734         caps._active_vprofile = cgGetProfile("gp5vp");
01735 
01736       if ((int)buf.find("glslv") >= 0)
01737         caps._active_vprofile = cgGetProfile("glslv");
01738 
01739       if ((int)buf.find("arbvp1") >= 0)
01740         caps._active_vprofile = cgGetProfile("arbvp1");
01741 
01742       if ((int)buf.find("vp40") >= 0)
01743         caps._active_vprofile = cgGetProfile("vp40");
01744 
01745       if ((int)buf.find("vp30") >= 0)
01746         caps._active_vprofile = cgGetProfile("vp30");
01747 
01748       if ((int)buf.find("vp20") >= 0)
01749         caps._active_vprofile = cgGetProfile("vp20");
01750 
01751       if ((int)buf.find("vs_1_1") >= 0)
01752         caps._active_vprofile = cgGetProfile("vs_1_1");
01753 
01754       if ((int)buf.find("vs_2_0") >= 0)
01755         caps._active_vprofile = cgGetProfile("vs_2_0");
01756 
01757       if ((int)buf.find("vs_2_x") >= 0)
01758         caps._active_vprofile = cgGetProfile("vs_2_x");
01759 
01760       if ((int)buf.find("vs_3_0") >= 0)
01761         caps._active_vprofile = cgGetProfile("vs_3_0");
01762 
01763       if ((int)buf.find("vs_4_0") >= 0)
01764         caps._active_vprofile = cgGetProfile("vs_4_0");
01765 
01766       if ((int)buf.find("vs_5_0") >= 0)
01767         caps._active_vprofile = cgGetProfile("vs_5_0");
01768 
01769       // Scan the line for known cg2 fragment program profiles
01770       if ((int)buf.find("gp4fp") >= 0)
01771         caps._active_fprofile = cgGetProfile("gp4fp");
01772 
01773       if ((int)buf.find("gp5fp") >= 0)
01774         caps._active_fprofile = cgGetProfile("gp5fp");
01775 
01776       if ((int)buf.find("glslf") >= 0)
01777         caps._active_fprofile = cgGetProfile("glslf");
01778 
01779       if ((int)buf.find("arbfp1") >= 0)
01780         caps._active_fprofile = cgGetProfile("arbfp1");
01781 
01782       if ((int)buf.find("fp40") >= 0)
01783         caps._active_fprofile = cgGetProfile("fp40");
01784 
01785       if ((int)buf.find("fp30") >= 0)
01786         caps._active_fprofile = cgGetProfile("fp30");
01787 
01788       if ((int)buf.find("fp20") >= 0)
01789         caps._active_fprofile = cgGetProfile("fp20");
01790 
01791       if ((int)buf.find("ps_1_1") >= 0)
01792         caps._active_fprofile = cgGetProfile("ps_1_1");
01793 
01794       if ((int)buf.find("ps_1_2") >= 0)
01795         caps._active_fprofile = cgGetProfile("ps_1_2");
01796 
01797       if ((int)buf.find("ps_1_3") >= 0)
01798         caps._active_fprofile = cgGetProfile("ps_1_3");
01799 
01800       if ((int)buf.find("ps_2_0") >= 0)
01801         caps._active_fprofile = cgGetProfile("ps_2_0");
01802 
01803       if ((int)buf.find("ps_2_x") >= 0)
01804         caps._active_fprofile = cgGetProfile("ps_2_x");
01805 
01806       if ((int)buf.find("ps_3_0") >= 0)
01807         caps._active_fprofile = cgGetProfile("ps_3_0");
01808 
01809       if ((int)buf.find("ps_4_0") >= 0)
01810         caps._active_fprofile = cgGetProfile("ps_4_0");
01811 
01812       if ((int)buf.find("ps_5_0") >= 0)
01813         caps._active_fprofile = cgGetProfile("ps_5_0");
01814 
01815       // Scan the line for known cg2 geometry program profiles
01816       if ((int)buf.find("gp4gp") >= 0)
01817         caps._active_gprofile = cgGetProfile("gp4gp");
01818 
01819       if ((int)buf.find("gp5gp") >= 0)
01820         caps._active_gprofile = cgGetProfile("gp5gp");
01821 
01822       if ((int)buf.find("glslg") >= 0)
01823         caps._active_gprofile = cgGetProfile("glslg");
01824 
01825       if ((int)buf.find("gs_4_0") >= 0)
01826         caps._active_gprofile = cgGetProfile("gs_4_0");
01827 
01828       if ((int)buf.find("gs_5_0") >= 0)
01829         caps._active_gprofile = cgGetProfile("gs_5_0");
01830     }
01831   } while(_parse > lastParse);
01832 
01833 }
01834 #endif
01835 
01836 ////////////////////////////////////////////////////////////////////
01837 //     Function: Shader::Destructor
01838 //       Access: Public
01839 //  Description: Delete the compiled code, if it exists.
01840 ////////////////////////////////////////////////////////////////////
01841 Shader::
01842 ~Shader() {
01843   release_all();
01844   if (_loaded) {
01845     _load_table.erase(_filename);
01846   } else {
01847     _make_table.erase(_text);
01848   }
01849 }
01850 
01851 ////////////////////////////////////////////////////////////////////
01852 //     Function: Shader::load
01853 //       Access: Published, Static
01854 //  Description: Loads the shader with the given filename.
01855 ////////////////////////////////////////////////////////////////////
01856 PT(Shader) Shader::
01857 load(const Filename &file, const ShaderLanguage &lang) {
01858   PT(ShaderFile) sfile =  new ShaderFile(file);
01859   ShaderTable::const_iterator i = _load_table.find(sfile);
01860   if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
01861     return i->second;
01862   }
01863   PT(ShaderFile) sbody = new ShaderFile("");
01864 
01865   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
01866   if (!vfs->read_file(file, sbody->_shared, true)) {
01867     gobj_cat.error() << "Could not read shader file: " << file << "\n";
01868     return NULL;
01869   }
01870   PT(Shader) result = new Shader(sfile, sbody, lang);
01871   result->_loaded = true;
01872   _load_table[sfile] = result;
01873   return result;
01874 }
01875 
01876 ////////////////////////////////////////////////////////////////////
01877 //     Function: Shader::load
01878 //       Access: Published, Static
01879 //  Description: This variant of Shader::load loads all shader
01880 //               programs separately.
01881 ////////////////////////////////////////////////////////////////////
01882 PT(Shader) Shader::
01883 load(const ShaderLanguage &lang, const Filename &vertex, const Filename &fragment, const Filename &geometry) {
01884   PT(ShaderFile) sfile = new ShaderFile(vertex, fragment, geometry);
01885   ShaderTable::const_iterator i = _load_table.find(sfile);
01886   if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
01887     return i->second;
01888   }
01889   PT(ShaderFile) sbody = new ShaderFile("", "", "");
01890   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
01891   if (!vertex.empty() && !vfs->read_file(vertex, sbody->_vertex, true)) {
01892     gobj_cat.error() << "Could not read vertex shader file: " << vertex << "\n";
01893     return NULL;
01894   }
01895   if (!fragment.empty() && !vfs->read_file(fragment, sbody->_fragment, true)) {
01896     gobj_cat.error() << "Could not read fragment shader file: " << vertex << "\n";
01897     return NULL;
01898   }
01899   if (!geometry.empty() && !vfs->read_file(geometry, sbody->_geometry, true)) {
01900     gobj_cat.error() << "Could not read geometry shader file: " << vertex << "\n";
01901     return NULL;
01902   }
01903   PT(Shader) result = new Shader(sfile, sbody, lang);
01904   result->_loaded = true;
01905   _load_table[sfile] = result;
01906   return result;
01907 }
01908 
01909 //////////////////////////////////////////////////////////////////////
01910 //     Function: Shader::make
01911 //       Access: Published, Static
01912 //  Description: Loads the shader, using the string as shader body.
01913 //////////////////////////////////////////////////////////////////////
01914 PT(Shader) Shader::
01915 make(const string &body, const ShaderLanguage &lang) {
01916   PT(ShaderFile) sbody = new ShaderFile(body);
01917   ShaderTable::const_iterator i = _make_table.find(sbody);
01918   if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
01919     return i->second;
01920   }
01921   PT(ShaderFile) sfile = new ShaderFile("created-shader");
01922   PT(Shader) result = new Shader(sfile, sbody, lang);
01923   _make_table[sbody] = result;
01924   if (dump_generated_shaders) {
01925     ostringstream fns;
01926     int index = _shaders_generated ++;
01927     fns << "genshader" << index;
01928     string fn = fns.str();
01929     gobj_cat.warning() << "Dumping shader: " << fn << "\n";
01930     pofstream s;
01931     s.open(fn.c_str());
01932     s << body;
01933     s.close();
01934   }
01935   return result;
01936 }
01937 
01938 //////////////////////////////////////////////////////////////////////
01939 //     Function: Shader::make
01940 //       Access: Published, Static
01941 //  Description: Loads the shader, using the strings as shader bodies.
01942 //////////////////////////////////////////////////////////////////////
01943 PT(Shader) Shader::
01944 make(const ShaderLanguage &lang, const string &vertex, const string &fragment, const string &geometry) {
01945   PT(ShaderFile) sbody = new ShaderFile(vertex, fragment, geometry);
01946   ShaderTable::const_iterator i = _make_table.find(sbody);
01947   if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
01948     return i->second;
01949   }
01950   PT(ShaderFile) sfile = new ShaderFile("created-shader");
01951   PT(Shader) result = new Shader(sfile, sbody, lang);
01952   _make_table[sbody] = result;
01953   return result;
01954 }
01955 
01956 ////////////////////////////////////////////////////////////////////
01957 //     Function: Shader::parse_init
01958 //       Access: Public
01959 //  Description: Set a 'parse pointer' to the beginning of the shader.
01960 ////////////////////////////////////////////////////////////////////
01961 void Shader::
01962 parse_init() {
01963   _parse = 0;
01964 }
01965 
01966 ////////////////////////////////////////////////////////////////////
01967 //     Function: Shader::parse_line
01968 //       Access: Public
01969 //  Description: Parse a line of text. If 'lt' is true, trim blanks
01970 //               from the left end of the line. If 'rt' is true, trim
01971 //               blanks from the right end (the newline is always
01972 //               trimmed).
01973 ////////////////////////////////////////////////////////////////////
01974 void Shader::
01975 parse_line(string &result, bool lt, bool rt) {
01976   nassertv(!_text->_separate);
01977   int len = _text->_shared.size();
01978   int head = _parse;
01979   int tail = head;
01980   while ((tail < len) && (_text->_shared[tail] != '\n')) {
01981     tail++;
01982   }
01983   if (tail < len) {
01984     _parse = tail+1;
01985   } else {
01986     _parse = tail;
01987   }
01988   if (lt) {
01989     while ((head < tail)&&(isspace(_text->_shared[head]))) head++;
01990     while ((tail > head)&&(isspace(_text->_shared[tail-1]))) tail--;
01991   }
01992   result = _text->_shared.substr(head, tail-head);
01993 }
01994 
01995 ////////////////////////////////////////////////////////////////////
01996 //     Function: Shader::parse_upto
01997 //       Access: Public
01998 //  Description: Parse lines until you read a line that matches the
01999 //               specified pattern.  Returns all the preceding lines,
02000 //               and if the include flag is set, returns the final
02001 //               line as well.
02002 ////////////////////////////////////////////////////////////////////
02003 void Shader::
02004 parse_upto(string &result, string pattern, bool include) {
02005   nassertv(!_text->_separate);
02006   GlobPattern endpat(pattern);
02007   int start = _parse;
02008   int last = _parse;
02009   while (_parse < (int)(_text->_shared.size())) {
02010     string t;
02011     parse_line(t, true, true);
02012     if (endpat.matches(t)) break;
02013     last = _parse;
02014   }
02015   if (include) {
02016     result = _text->_shared.substr(start, _parse - start);
02017   } else {
02018     result = _text->_shared.substr(start, last - start);
02019   }
02020 }
02021 
02022 ////////////////////////////////////////////////////////////////////
02023 //     Function: Shader::parse_rest
02024 //       Access: Public
02025 //  Description: Returns the rest of the text from the current
02026 //               parse location.
02027 ////////////////////////////////////////////////////////////////////
02028 void Shader::
02029 parse_rest(string &result) {
02030   nassertv(!_text->_separate);
02031   result = _text->_shared.substr(_parse, _text->_shared.size() - _parse);
02032 }
02033 
02034 ////////////////////////////////////////////////////////////////////
02035 //     Function: Shader::parse_eof
02036 //       Access: Public
02037 //  Description: Returns true if the parse pointer is at the end of
02038 //               the shader.
02039 ////////////////////////////////////////////////////////////////////
02040 bool Shader::
02041 parse_eof() {
02042   return (int)_text->_shared.size() == _parse;
02043 }
02044 
02045 ////////////////////////////////////////////////////////////////////
02046 //     Function: Shader::prepare
02047 //       Access: Published
02048 //  Description: Indicates that the shader should be enqueued to be
02049 //               prepared in the indicated prepared_objects at the
02050 //               beginning of the next frame.  This will ensure the
02051 //               texture is already loaded into texture memory if it
02052 //               is expected to be rendered soon.
02053 //
02054 //               Use this function instead of prepare_now() to preload
02055 //               textures from a user interface standpoint.
02056 ////////////////////////////////////////////////////////////////////
02057 void Shader::
02058 prepare(PreparedGraphicsObjects *prepared_objects) {
02059   prepared_objects->enqueue_shader(this);
02060 }
02061 
02062 ////////////////////////////////////////////////////////////////////
02063 //     Function: Shader::is_prepared
02064 //       Access: Published
02065 //  Description: Returns true if the shader has already been prepared
02066 //               or enqueued for preparation on the indicated GSG,
02067 //               false otherwise.
02068 ////////////////////////////////////////////////////////////////////
02069 bool Shader::
02070 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
02071   Contexts::const_iterator ci;
02072   ci = _contexts.find(prepared_objects);
02073   if (ci != _contexts.end()) {
02074     return true;
02075   }
02076   return prepared_objects->is_shader_queued(this);
02077 }
02078 
02079 ////////////////////////////////////////////////////////////////////
02080 //     Function: Shader::release
02081 //       Access: Published
02082 //  Description: Frees the texture context only on the indicated object,
02083 //               if it exists there.  Returns true if it was released,
02084 //               false if it had not been prepared.
02085 ////////////////////////////////////////////////////////////////////
02086 bool Shader::
02087 release(PreparedGraphicsObjects *prepared_objects) {
02088   Contexts::iterator ci;
02089   ci = _contexts.find(prepared_objects);
02090   if (ci != _contexts.end()) {
02091     ShaderContext *sc = (*ci).second;
02092     if (sc != (ShaderContext *)NULL) {
02093       prepared_objects->release_shader(sc);
02094     } else {
02095       _contexts.erase(ci);
02096     }
02097     return true;
02098   }
02099 
02100   // Maybe it wasn't prepared yet, but it's about to be.
02101   return prepared_objects->dequeue_shader(this);
02102 }
02103 
02104 ////////////////////////////////////////////////////////////////////
02105 //     Function: Shader::prepare_now
02106 //       Access: Published
02107 //  Description: Creates a context for the shader on the particular
02108 //               GSG, if it does not already exist.  Returns the new
02109 //               (or old) ShaderContext.  This assumes that the
02110 //               GraphicsStateGuardian is the currently active
02111 //               rendering context and that it is ready to accept new
02112 //               textures.  If this is not necessarily the case, you
02113 //               should use prepare() instead.
02114 //
02115 //               Normally, this is not called directly except by the
02116 //               GraphicsStateGuardian; a shader does not need to be
02117 //               explicitly prepared by the user before it may be
02118 //               rendered.
02119 ////////////////////////////////////////////////////////////////////
02120 ShaderContext *Shader::
02121 prepare_now(PreparedGraphicsObjects *prepared_objects,
02122             GraphicsStateGuardianBase *gsg) {
02123   Contexts::const_iterator ci;
02124   ci = _contexts.find(prepared_objects);
02125   if (ci != _contexts.end()) {
02126     return (*ci).second;
02127   }
02128 
02129   ShaderContext *tc = prepared_objects->prepare_shader_now(this, gsg);
02130   _contexts[prepared_objects] = tc;
02131 
02132   return tc;
02133 }
02134 
02135 ////////////////////////////////////////////////////////////////////
02136 //     Function: Shader::clear_prepared
02137 //       Access: Private
02138 //  Description: Removes the indicated PreparedGraphicsObjects table
02139 //               from the Shader's table, without actually releasing
02140 //               the texture.  This is intended to be called only from
02141 //               PreparedGraphicsObjects::release_texture(); it should
02142 //               never be called by user code.
02143 ////////////////////////////////////////////////////////////////////
02144 void Shader::
02145 clear_prepared(PreparedGraphicsObjects *prepared_objects) {
02146   Contexts::iterator ci;
02147   ci = _contexts.find(prepared_objects);
02148   if (ci != _contexts.end()) {
02149     _contexts.erase(ci);
02150   } else {
02151     // If this assertion fails, clear_prepared() was given a
02152     // prepared_objects which the texture didn't know about.
02153     nassertv(false);
02154   }
02155 }
02156 
02157 ////////////////////////////////////////////////////////////////////
02158 //     Function: Shader::release_all
02159 //       Access: Published
02160 //  Description: Frees the context allocated on all objects for which
02161 //               the texture has been declared.  Returns the number of
02162 //               contexts which have been freed.
02163 ////////////////////////////////////////////////////////////////////
02164 int Shader::
02165 release_all() {
02166   // We have to traverse a copy of the _contexts list, because the
02167   // PreparedGraphicsObjects object will call clear_prepared() in response
02168   // to each release_texture(), and we don't want to be modifying the
02169   // _contexts list while we're traversing it.
02170   Contexts temp = _contexts;
02171   int num_freed = (int)_contexts.size();
02172 
02173   Contexts::const_iterator ci;
02174   for (ci = temp.begin(); ci != temp.end(); ++ci) {
02175     PreparedGraphicsObjects *prepared_objects = (*ci).first;
02176     ShaderContext *sc = (*ci).second;
02177     if (sc != (ShaderContext *)NULL) {
02178       prepared_objects->release_shader(sc);
02179     }
02180   }
02181 
02182   // There might still be some outstanding contexts in the map, if
02183   // there were any NULL pointers there.  Eliminate them.
02184   _contexts.clear();
02185 
02186   return num_freed;
02187 }
02188 
02189 ////////////////////////////////////////////////////////////////////
02190 //     Function: Shader::ShaderCapabilities::clear()
02191 //       Access: Public
02192 //  Description:
02193 ////////////////////////////////////////////////////////////////////
02194 void Shader::ShaderCaps::
02195 clear() {
02196   _supports_glsl = false;
02197   
02198 #ifdef HAVE_CG
02199   _active_vprofile = CG_PROFILE_UNKNOWN;
02200   _active_fprofile = CG_PROFILE_UNKNOWN;
02201   _active_gprofile = CG_PROFILE_UNKNOWN;
02202   _ultimate_vprofile = CG_PROFILE_UNKNOWN;
02203   _ultimate_fprofile = CG_PROFILE_UNKNOWN;
02204   _ultimate_gprofile = CG_PROFILE_UNKNOWN;
02205 #endif
02206 }
02207 
02208 ////////////////////////////////////////////////////////////////////
02209 //     Function: Shader::register_with_read_factory
02210 //       Access: Public, Static
02211 //  Description:
02212 ////////////////////////////////////////////////////////////////////
02213 void Shader::
02214 register_with_read_factory() {
02215   // IMPLEMENT ME
02216 }
02217 
 All Classes Functions Variables Enumerations