Panda3D

shader.cxx

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