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