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