Panda3D
|
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