16 #include "pandabase.h" 18 #include "preparedGraphicsObjects.h" 19 #include "virtualFileSystem.h" 20 #include "config_util.h" 30 int Shader::_shaders_generated;
31 ShaderUtilization Shader::_shader_utilization = SUT_unspecified;
34 CGcontext Shader::_cg_context = 0;
53 string dstr =
"unknown ";
54 if (p._direction == SAD_in) {
56 }
else if (p._direction == SAD_out) {
58 }
else if (p._direction == SAD_inout) {
62 string tstr =
"invalid ";
64 case SAT_scalar: tstr =
"scalar ";
break;
65 case SAT_vec1: tstr =
"vec1 ";
break;
66 case SAT_vec2: tstr =
"vec2 ";
break;
67 case SAT_vec3: tstr =
"vec3 ";
break;
68 case SAT_vec4: tstr =
"vec4 ";
break;
69 case SAT_mat1x1: tstr =
"mat1x1 ";
break;
70 case SAT_mat1x2: tstr =
"mat1x2 ";
break;
71 case SAT_mat1x3: tstr =
"mat1x3 ";
break;
72 case SAT_mat1x4: tstr =
"mat1x4 ";
break;
73 case SAT_mat2x1: tstr =
"mat2x1 ";
break;
74 case SAT_mat2x2: tstr =
"mat2x2 ";
break;
75 case SAT_mat2x3: tstr =
"mat2x3 ";
break;
76 case SAT_mat2x4: tstr =
"mat2x4 ";
break;
77 case SAT_mat3x1: tstr =
"mat3x1 ";
break;
78 case SAT_mat3x2: tstr =
"mat3x2 ";
break;
79 case SAT_mat3x3: tstr =
"mat3x3 ";
break;
80 case SAT_mat3x4: tstr =
"mat3x4 ";
break;
81 case SAT_mat4x1: tstr =
"mat4x1 ";
break;
82 case SAT_mat4x2: tstr =
"mat4x2 ";
break;
83 case SAT_mat4x3: tstr =
"mat4x3 ";
break;
84 case SAT_mat4x4: tstr =
"mat4x4 ";
break;
85 case SAT_sampler1d: tstr =
"sampler1d ";
break;
86 case SAT_sampler2d: tstr =
"sampler2d ";
break;
87 case SAT_sampler3d: tstr =
"sampler3d ";
break;
88 case SAT_sampler2dArray: tstr =
"sampler2dArray ";
break;
89 case SAT_samplercube: tstr =
"samplercube ";
break;
90 default: tstr =
"unknown ";
break;
93 string cstr =
"invalid";
95 case SAC_scalar: cstr =
"scalar ";
break;
96 case SAC_vector: cstr =
"vector ";
break;
97 case SAC_matrix: cstr =
"matrix ";
break;
98 case SAC_sampler: cstr =
"sampler ";
break;
99 case SAC_array: cstr =
"array ";
break;
100 default: cstr =
"unknown ";
break;
104 p._cat->
error() << fn <<
": " << vstr << dstr << tstr <<
105 p._id._name <<
": " << msg <<
"\n";
119 tokenize(p._id._name, words,
"_");
120 if ((
int)words.size() != len) {
137 if (p._direction != SAD_in) {
190 case SAT_scalar: nfloat = 1;
break;
191 case SAT_vec2: nfloat = 2;
break;
192 case SAT_vec3: nfloat = 3;
break;
193 case SAT_vec4: nfloat = 4;
break;
194 case SAT_mat3x3: nfloat = 9;
break;
195 case SAT_mat4x4: nfloat = 16;
break;
196 default: nfloat = 0;
break;
198 if ((nfloat < lo)||(nfloat > hi)) {
199 string msg =
"wrong type for parameter:";
214 case SAC_scalar:
return true;
215 case SAC_vector:
return true;
216 case SAC_matrix:
return true;
218 switch (p._subclass) {
219 case SAC_scalar:
return true;
220 case SAC_vector:
return true;
221 case SAC_matrix:
return true;
223 string msg =
"unsupported array subclass.";
228 string msg =
"unsupported class.";
244 if ((p._type!=SAT_sampler1d)&&
245 (p._type!=SAT_sampler2d)&&
246 (p._type!=SAT_sampler3d)&&
247 (p._type!=SAT_sampler2dArray)&&
248 (p._type!=SAT_samplercube)) {
262 if (words[next] !=
"") {
276 if ((words[next] !=
"to")&&(words[next] !=
"rel")) {
292 const string &nword = words[next];
293 if ((nword ==
"")||(nword ==
"to")||(nword ==
"rel")) {
308 vector_string &pieces,
int &next,
312 if (pieces[next] ==
"of") next++;
315 ShaderMatInput from_single;
316 ShaderMatInput from_double;
317 ShaderMatInput to_single;
318 ShaderMatInput to_double;
323 }
else if (word1 ==
"world") {
324 from_single = SMO_world_to_view;
325 from_double = SMO_INVALID;
326 to_single = SMO_view_to_world;
327 to_double = SMO_INVALID;
328 }
else if (word1 ==
"model") {
329 from_single = SMO_model_to_view;
330 from_double = SMO_view_x_to_view;
331 to_single = SMO_view_to_model;
332 to_double = SMO_view_to_view_x;
333 }
else if (word1 ==
"clip") {
334 from_single = SMO_clip_to_view;
335 from_double = SMO_clip_x_to_view;
336 to_single = SMO_view_to_clip;
337 to_double = SMO_view_to_clip_x;
338 }
else if (word1 ==
"view") {
339 from_single = SMO_identity;
340 from_double = SMO_view_x_to_view;
341 to_single = SMO_identity;
342 to_double = SMO_view_to_view_x;
343 }
else if (word1 ==
"apiview") {
344 from_single = SMO_apiview_to_view;
345 from_double = SMO_apiview_x_to_view;
346 to_single = SMO_view_to_apiview;
347 to_double = SMO_view_to_apiview_x;
348 }
else if (word1 ==
"apiclip") {
349 from_single = SMO_apiclip_to_view;
350 from_double = SMO_apiclip_x_to_view;
351 to_single = SMO_view_to_apiclip;
352 to_double = SMO_view_to_apiclip_x;
354 from_single = SMO_view_x_to_view;
355 from_double = SMO_view_x_to_view;
356 to_single = SMO_view_to_view_x;
357 to_double = SMO_view_to_view_x;
363 bind._part[0] = from_single;
366 if (from_double == SMO_INVALID) {
370 bind._part[0] = from_double;
371 bind._arg[0] = InternalName::make(word2);
375 bind._part[1] = to_single;
378 if (to_double == SMO_INVALID) {
382 bind._part[1] = to_double;
383 bind._arg[1] = InternalName::make(word2);
399 int dep = SSD_general;
401 if (inp == SMO_INVALID) {
404 if (inp == SMO_attr_material) {
407 if (inp == SMO_attr_color) {
410 if (inp == SMO_attr_colorscale) {
411 dep |= SSD_colorscale;
413 if (inp == SMO_attr_fog || inp == SMO_attr_fogcolor) {
416 if ((inp == SMO_model_to_view) ||
417 (inp == SMO_view_to_model) ||
418 (inp == SMO_model_to_apiview) ||
419 (inp == SMO_apiview_to_model)) {
420 dep |= SSD_transform;
422 if ((inp == SMO_texpad_x) ||
423 (inp == SMO_texpix_x) ||
424 (inp == SMO_alight_x) ||
425 (inp == SMO_dlight_x) ||
426 (inp == SMO_plight_x) ||
427 (inp == SMO_slight_x) ||
428 (inp == SMO_satten_x) ||
429 (inp == SMO_mat_constant_x) ||
430 (inp == SMO_vec_constant_x) ||
431 (inp == SMO_vec_constant_x_attrib) ||
432 (inp == SMO_view_x_to_view) ||
433 (inp == SMO_view_to_view_x) ||
434 (inp == SMO_apiview_x_to_view) ||
435 (inp == SMO_view_to_apiview_x) ||
436 (inp == SMO_clip_x_to_view) ||
437 (inp == SMO_view_to_clip_x) ||
438 (inp == SMO_apiclip_x_to_view) ||
439 (inp == SMO_view_to_apiclip_x)) {
440 dep |= SSD_shaderinputs;
442 if ((inp == SMO_light_ambient) ||
443 (inp == SMO_light_source_i_attrib)) {
446 if ((inp == SMO_light_product_i_ambient) ||
447 (inp == SMO_light_product_i_diffuse) ||
448 (inp == SMO_light_product_i_specular)) {
449 dep |= (SSD_light | SSD_material);
451 if ((inp == SMO_clipplane_x) ||
452 (inp == SMO_apiview_clipplane_i)) {
453 dep |= SSD_clip_planes;
473 if (spec._func == SMF_first) {
474 spec._part[1] = SMO_INVALID;
477 if (spec._func == SMF_compose) {
478 if (spec._part[1] == SMO_identity) {
479 spec._func = SMF_first;
482 if (spec._func == SMF_compose) {
483 if (spec._part[0] == SMO_identity) {
484 spec._func = SMF_first;
485 spec._part[0] = spec._part[1];
486 spec._arg[0] = spec._arg[1];
491 if (spec._part[0] == SMO_model_to_view &&
492 spec._part[1] == SMO_view_to_apiclip) {
493 spec._part[0] = SMO_model_to_apiview;
494 spec._part[1] = SMO_apiview_to_apiclip;
496 }
else if (spec._part[0] == SMO_apiclip_to_view &&
497 spec._part[1] == SMO_view_to_model) {
498 spec._part[0] = SMO_apiclip_to_apiview;
499 spec._part[1] = SMO_apiview_to_model;
501 }
else if (spec._part[0] == SMO_apiview_to_view &&
502 spec._part[1] == SMO_view_to_apiclip) {
503 spec._func = SMF_first;
504 spec._part[0] = SMO_apiview_to_apiclip;
505 spec._part[1] = SMO_identity;
507 }
else if (spec._part[0] == SMO_apiclip_to_view &&
508 spec._part[1] == SMO_view_to_apiview) {
509 spec._func = SMF_first;
510 spec._part[0] = SMO_apiclip_to_apiview;
511 spec._part[1] = SMO_identity;
513 }
else if (spec._part[0] == SMO_apiview_to_view &&
514 spec._part[1] == SMO_view_to_model) {
515 spec._func = SMF_first;
516 spec._part[0] = SMO_apiview_to_model;
517 spec._part[1] = SMO_identity;
519 }
else if (spec._part[0] == SMO_model_to_view &&
520 spec._part[1] == SMO_view_to_apiview) {
521 spec._func = SMF_first;
522 spec._part[0] = SMO_model_to_apiview;
523 spec._part[1] = SMO_identity;
540 cg_recurse_parameters(CGparameter parameter,
const ShaderType &type,
543 if (parameter == 0) {
548 if (cgIsParameterReferenced(parameter)) {
549 int arg_dim[] = {1,0,0};
550 ShaderArgDir arg_dir = cg_parameter_dir(parameter);
551 ShaderArgType arg_type = cg_parameter_type(parameter);
552 ShaderArgClass arg_class = cg_parameter_class(parameter);
553 ShaderArgClass arg_subclass = arg_class;
555 CGenum vbl = cgGetParameterVariability(parameter);
557 if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) {
558 switch (cgGetParameterType(parameter)) {
560 cg_recurse_parameters(
561 cgGetFirstStructParameter(parameter), type, success);
565 arg_type = cg_parameter_type(cgGetArrayParameter(parameter, 0));
566 arg_subclass = cg_parameter_class(cgGetArrayParameter(parameter, 0));
568 arg_dim[0] = cgGetArraySize(parameter, 0);
571 arg_dim[1] = cgGetParameterRows(parameter);
572 arg_dim[2] = cgGetParameterColumns(parameter);
575 id._name = cgGetParameterName(parameter);
579 arg_dir, (vbl == CG_VARYING), arg_dim, shader_cat.get_safe_ptr());
break;
583 }
else if (shader_cat.is_debug()) {
585 <<
"Parameter " << cgGetParameterName(parameter)
586 <<
" is unreferenced within shader " <<
get_filename(type) <<
"\n";
588 }
while((parameter = cgGetNextParameter(parameter))!= 0);
605 const ShaderArgClass &arg_class,
606 const ShaderArgClass &arg_subclass,
607 const ShaderArgType &arg_type,
608 const ShaderArgDir &arg_direction,
615 p._class = arg_class;
616 p._subclass = arg_subclass;
618 p._direction = arg_direction;
619 p._varying = arg_varying;
622 if (p._id._name.size() == 0)
return true;
623 if (p._id._name[0] ==
'$')
return true;
627 size_t loc = p._id._name.find_last_of(
'.');
629 string basename (p._id._name);
630 string struct_name (
"");
632 if (loc < string::npos) {
633 basename = p._id._name.substr(loc + 1);
634 struct_name = p._id._name.substr(0,loc+1);
638 vector_string pieces;
639 tokenize(basename, pieces,
"_");
641 if (basename.size() >= 2 && basename.substr(0, 2) ==
"__") {
646 if (pieces[0] ==
"vtx") {
654 bind._append_uv = -1;
655 bind._integer =
false;
657 if (pieces.size() == 2) {
658 if (pieces[1] ==
"position") {
659 bind._name = InternalName::get_vertex();
660 bind._append_uv = -1;
661 _var_spec.push_back(bind);
664 if (pieces[1].substr(0, 8) ==
"texcoord") {
665 bind._name = InternalName::get_texcoord();
666 if (pieces[1].size() > 8) {
667 bind._append_uv = atoi(pieces[1].c_str() + 8);
669 _var_spec.push_back(bind);
672 if (pieces[1].substr(0, 7) ==
"tangent") {
673 bind._name = InternalName::get_tangent();
674 if (pieces[1].size() > 7) {
675 bind._append_uv = atoi(pieces[1].c_str() + 7);
677 _var_spec.push_back(bind);
680 if (pieces[1].substr(0, 8) ==
"binormal") {
681 bind._name = InternalName::get_binormal();
682 if (pieces[1].size() > 8) {
683 bind._append_uv = atoi(pieces[1].c_str() + 8);
685 _var_spec.push_back(bind);
690 bind._name = InternalName::get_root();
691 for (
size_t i = 1; i < pieces.size(); ++i) {
692 bind._name = bind._name->append(pieces[i]);
694 _var_spec.push_back(bind);
701 if (pieces[0] ==
"mstrans") {
703 pieces.push_back(
"to");
704 pieces.push_back(
"model");
706 if (pieces[0] ==
"wstrans") {
708 pieces.push_back(
"to");
709 pieces.push_back(
"world");
711 if (pieces[0] ==
"vstrans") {
713 pieces.push_back(
"to");
714 pieces.push_back(
"view");
716 if (pieces[0] ==
"cstrans") {
718 pieces.push_back(
"to");
719 pieces.push_back(
"clip");
721 if (pieces[0] ==
"mspos") {
723 pieces.push_back(
"to");
724 pieces.push_back(
"model");
726 if (pieces[0] ==
"wspos") {
728 pieces.push_back(
"to");
729 pieces.push_back(
"world");
731 if (pieces[0] ==
"vspos") {
733 pieces.push_back(
"to");
734 pieces.push_back(
"view");
736 if (pieces[0] ==
"cspos") {
738 pieces.push_back(
"to");
739 pieces.push_back(
"clip");
744 if ((pieces[0] ==
"mat")||(pieces[0] ==
"inv")||
745 (pieces[0] ==
"tps")||(pieces[0] ==
"itp")) {
749 string trans = pieces[0];
750 string matrix = pieces[1];
752 if (matrix ==
"modelview") {
753 tokenize(
"trans_model_to_apiview", pieces,
"_");
754 }
else if (matrix ==
"projection") {
755 tokenize(
"trans_apiview_to_apiclip", pieces,
"_");
756 }
else if (matrix ==
"modelproj") {
757 tokenize(
"trans_model_to_apiclip", pieces,
"_");
764 }
else if (trans==
"inv") {
765 string t = pieces[1];
766 pieces[1] = pieces[3];
768 }
else if (trans==
"tps") {
770 }
else if (trans==
"itp") {
771 string t = pieces[1];
772 pieces[1] = pieces[3];
780 if ((pieces[0]==
"trans")||
781 (pieces[0]==
"tpose")||
782 (pieces[0]==
"row0")||
783 (pieces[0]==
"row1")||
784 (pieces[0]==
"row2")||
785 (pieces[0]==
"row3")||
786 (pieces[0]==
"col0")||
787 (pieces[0]==
"col1")||
788 (pieces[0]==
"col2")||
789 (pieces[0]==
"col3")) {
797 bind._func = SMF_compose;
800 pieces.push_back(
"");
803 if (pieces[0]==
"trans") bind._piece = SMP_whole;
804 else if (pieces[0]==
"tpose") bind._piece = SMP_transpose;
805 else if (pieces[0]==
"row0") bind._piece = SMP_row0;
806 else if (pieces[0]==
"row1") bind._piece = SMP_row1;
807 else if (pieces[0]==
"row2") bind._piece = SMP_row2;
808 else if (pieces[0]==
"row3") bind._piece = SMP_row3;
809 else if (pieces[0]==
"col0") bind._piece = SMP_col0;
810 else if (pieces[0]==
"col1") bind._piece = SMP_col1;
811 else if (pieces[0]==
"col2") bind._piece = SMP_col2;
812 else if (pieces[0]==
"col3") bind._piece = SMP_col3;
813 if ((bind._piece == SMP_whole)||(bind._piece == SMP_transpose)) {
814 if (p._type == SAT_mat3x3) {
817 if (bind._piece == SMP_transpose) {
818 bind._piece = SMP_transpose3x3;
820 bind._piece = SMP_upper3x3;
842 _mat_spec.push_back(bind);
848 if (pieces[0] ==
"attr") {
855 if (pieces[1] ==
"material") {
860 bind._piece = SMP_transpose;
861 bind._func = SMF_first;
862 bind._part[0] = SMO_attr_material;
864 bind._part[1] = SMO_identity;
866 }
else if (pieces[1] ==
"color") {
871 bind._piece = SMP_row3;
872 bind._func = SMF_first;
873 bind._part[0] = SMO_attr_color;
875 bind._part[1] = SMO_identity;
877 }
else if (pieces[1] ==
"colorscale") {
882 bind._piece = SMP_row3;
883 bind._func = SMF_first;
884 bind._part[0] = SMO_attr_colorscale;
886 bind._part[1] = SMO_identity;
888 }
else if (pieces[1] ==
"fog") {
893 bind._piece = SMP_row3;
894 bind._func = SMF_first;
895 bind._part[0] = SMO_attr_fog;
897 bind._part[1] = SMO_identity;
899 }
else if (pieces[1] ==
"fogcolor") {
904 bind._piece = SMP_row3;
905 bind._func = SMF_first;
906 bind._part[0] = SMO_attr_fogcolor;
908 bind._part[1] = SMO_identity;
916 _mat_spec.push_back(bind);
920 if (pieces[0] ==
"color") {
929 _mat_spec.push_back(bind);
935 if (pieces[0] ==
"alight") {
944 bind._piece = SMP_row3;
945 bind._func = SMF_first;
946 bind._part[0] = SMO_alight_x;
947 bind._arg[0] = InternalName::make(pieces[1]);
948 bind._part[1] = SMO_identity;
952 _mat_spec.push_back(bind);
956 if (pieces[0] ==
"satten") {
965 bind._piece = SMP_row3;
966 bind._func = SMF_first;
967 bind._part[0] = SMO_satten_x;
968 bind._arg[0] = InternalName::make(pieces[1]);
969 bind._part[1] = SMO_identity;
973 _mat_spec.push_back(bind);
977 if ((pieces[0]==
"dlight")||(pieces[0]==
"plight")||(pieces[0]==
"slight")) {
985 bind._piece = SMP_transpose;
987 pieces.push_back(
"");
988 if (pieces[next] ==
"") {
992 if (pieces[0] ==
"dlight") {
993 bind._func = SMF_transform_dlight;
994 bind._part[0] = SMO_dlight_x;
995 }
else if (pieces[0] ==
"plight") {
996 bind._func = SMF_transform_plight;
997 bind._part[0] = SMO_plight_x;
998 }
else if (pieces[0] ==
"slight") {
999 bind._func = SMF_transform_slight;
1000 bind._part[0] = SMO_slight_x;
1002 bind._arg[0] = InternalName::make(pieces[next]);
1014 _mat_spec.push_back(bind);
1018 if (pieces[0] ==
"texmat") {
1027 bind._piece = SMP_whole;
1028 bind._func = SMF_first;
1029 bind._part[0] = SMO_texmat_x;
1030 bind._arg[0] = InternalName::make(pieces[1]);
1031 bind._part[1] = SMO_identity;
1032 bind._arg[1] = NULL;
1035 _mat_spec.push_back(bind);
1039 if (pieces[0] ==
"plane") {
1048 bind._piece = SMP_row3;
1049 bind._func = SMF_first;
1050 bind._part[0] = SMO_plane_x;
1051 bind._arg[0] = InternalName::make(pieces[1]);
1052 bind._part[1] = SMO_identity;
1053 bind._arg[1] = NULL;
1056 _mat_spec.push_back(bind);
1060 if (pieces[0] ==
"clipplane") {
1069 bind._piece = SMP_row3;
1070 bind._func = SMF_first;
1071 bind._part[0] = SMO_clipplane_x;
1072 bind._arg[0] = InternalName::make(pieces[1]);
1073 bind._part[1] = SMO_identity;
1074 bind._arg[1] = NULL;
1077 _mat_spec.push_back(bind);
1083 if (pieces[0] ==
"sys") {
1091 bind._piece = SMP_row3;
1092 bind._func = SMF_first;
1093 bind._part[1] = SMO_identity;
1094 bind._arg[1] = NULL;
1095 if (pieces[1] ==
"pixelsize") {
1099 bind._part[0] = SMO_pixel_size;
1100 bind._arg[0] = NULL;
1102 }
else if (pieces[1] ==
"windowsize") {
1106 bind._part[0] = SMO_window_size;
1107 bind._arg[0] = NULL;
1109 }
else if (pieces[1] ==
"time") {
1113 bind._piece = SMP_row3x1;
1114 bind._part[0] = SMO_frame_time;
1115 bind._arg[0] = NULL;
1123 _mat_spec.push_back(bind);
1129 if (pieces[0] ==
"tex") {
1134 if ((pieces.size() != 2)&&(pieces.size() != 3)) {
1141 bind._stage = atoi(pieces[1].c_str());
1143 case SAT_sampler1d: bind._desired_type = Texture::TT_1d_texture;
break;
1144 case SAT_sampler2d: bind._desired_type = Texture::TT_2d_texture;
break;
1145 case SAT_sampler3d: bind._desired_type = Texture::TT_3d_texture;
break;
1146 case SAT_sampler2dArray: bind._desired_type = Texture::TT_2d_texture_array;
break;
1147 case SAT_samplercube: bind._desired_type = Texture::TT_cube_map;
break;
1152 if (pieces.size() == 3) {
1153 bind._suffix = InternalName::make(((
string)
"-") + pieces[2]);
1154 shader_cat.warning()
1155 <<
"Parameter " << p._id._name <<
": use of a texture suffix is deprecated.\n";
1157 _tex_spec.push_back(bind);
1163 if (pieces[0] ==
"texpad") {
1172 bind._piece = SMP_row3;
1173 bind._func = SMF_first;
1174 bind._part[0] = SMO_texpad_x;
1175 bind._arg[0] = InternalName::make(pieces[1]);
1176 bind._part[1] = SMO_identity;
1177 bind._arg[1] = NULL;
1179 _mat_spec.push_back(bind);
1183 if (pieces[0] ==
"texpix") {
1192 bind._piece = SMP_row3;
1193 bind._func = SMF_first;
1194 bind._part[0] = SMO_texpix_x;
1195 bind._arg[0] = InternalName::make(pieces[1]);
1196 bind._part[1] = SMO_identity;
1197 bind._arg[1] = NULL;
1199 _mat_spec.push_back(bind);
1203 if (pieces[0] ==
"l") {
1208 if (pieces[0] ==
"o") {
1219 bool k_prefix =
false;
1222 if (pieces[0] ==
"k") {
1224 basename = basename.substr(2);
1227 PT(InternalName) kinputname = InternalName::make(struct_name + basename);
1234 if (!cp_errchk_parameter_ptr(p))
1239 bind._arg = kinputname;
1241 bind._dep[0] = SSD_general | SSD_shaderinputs;
1242 bind._dep[1] = SSD_general | SSD_NONE;
1244 memcpy(bind._dim,arg_dim,
sizeof(
int)*3);
1247 if (k_prefix) bind._dim[0] = -1;
1248 _ptr_spec.push_back(bind);
1254 case SAT_sampler1d: {
1257 bind._name = kinputname;
1258 bind._desired_type = Texture::TT_1d_texture;
1259 _tex_spec.push_back(bind);
1262 case SAT_sampler2d: {
1265 bind._name = kinputname;
1266 bind._desired_type = Texture::TT_2d_texture;
1267 _tex_spec.push_back(bind);
1270 case SAT_sampler3d: {
1273 bind._name = kinputname;
1274 bind._desired_type = Texture::TT_3d_texture;
1275 _tex_spec.push_back(bind);
1278 case SAT_sampler2dArray: {
1281 bind._name = kinputname;
1282 bind._desired_type = Texture::TT_2d_texture_array;
1283 _tex_spec.push_back(bind);
1286 case SAT_samplercube: {
1289 bind._name = kinputname;
1290 bind._desired_type = Texture::TT_cube_map;
1291 _tex_spec.push_back(bind);
1315 clear_parameters() {
1327 Shader::ShaderArgType Shader::
1328 cg_parameter_type(CGparameter p) {
1329 switch (cgGetParameterClass(p)) {
1330 case CG_PARAMETERCLASS_SCALAR:
return SAT_scalar;
1331 case CG_PARAMETERCLASS_VECTOR:
1332 switch (cgGetParameterColumns(p)) {
1333 case 1:
return SAT_vec1;
1334 case 2:
return SAT_vec2;
1335 case 3:
return SAT_vec3;
1336 case 4:
return SAT_vec4;
1337 default:
return SAT_unknown;
1339 case CG_PARAMETERCLASS_MATRIX:
1340 switch (cgGetParameterRows(p)) {
1342 switch (cgGetParameterColumns(p)) {
1343 case 1:
return SAT_mat1x1;
1344 case 2:
return SAT_mat1x2;
1345 case 3:
return SAT_mat1x3;
1346 case 4:
return SAT_mat1x4;
1347 default:
return SAT_unknown;
1350 switch (cgGetParameterColumns(p)) {
1351 case 1:
return SAT_mat2x1;
1352 case 2:
return SAT_mat2x2;
1353 case 3:
return SAT_mat2x3;
1354 case 4:
return SAT_mat2x4;
1355 default:
return SAT_unknown;
1358 switch (cgGetParameterColumns(p)) {
1359 case 1:
return SAT_mat3x1;
1360 case 2:
return SAT_mat3x2;
1361 case 3:
return SAT_mat3x3;
1362 case 4:
return SAT_mat3x4;
1363 default:
return SAT_unknown;
1366 switch (cgGetParameterColumns(p)) {
1367 case 1:
return SAT_mat4x1;
1368 case 2:
return SAT_mat4x2;
1369 case 3:
return SAT_mat4x3;
1370 case 4:
return SAT_mat4x4;
1371 default:
return SAT_unknown;
1373 default:
return SAT_unknown;
1375 case CG_PARAMETERCLASS_SAMPLER:
1376 switch (cgGetParameterType(p)) {
1377 case CG_SAMPLER1D:
return Shader::SAT_sampler1d;
1378 case CG_SAMPLER2D:
return Shader::SAT_sampler2d;
1379 case CG_SAMPLER3D:
return Shader::SAT_sampler3d;
1380 case CG_SAMPLER2DARRAY:
return Shader::SAT_sampler2dArray;
1381 case CG_SAMPLERCUBE:
return Shader::SAT_samplercube;
1383 case 1313:
return Shader::SAT_sampler1d;
1384 case 1314:
return Shader::SAT_sampler2d;
1385 default:
return SAT_unknown;
1387 case CG_PARAMETERCLASS_ARRAY:
return SAT_unknown;
1388 default:
return SAT_unknown;
1397 Shader::ShaderArgClass Shader::cg_parameter_class(CGparameter p) {
1398 switch (cgGetParameterClass(p)) {
1399 case CG_PARAMETERCLASS_SCALAR:
return Shader::SAC_scalar;
1400 case CG_PARAMETERCLASS_VECTOR:
return Shader::SAC_vector;
1401 case CG_PARAMETERCLASS_MATRIX:
return Shader::SAC_matrix;
1402 case CG_PARAMETERCLASS_SAMPLER:
return Shader::SAC_sampler;
1403 case CG_PARAMETERCLASS_ARRAY:
return Shader::SAC_array;
1404 default:
return Shader::SAC_unknown;
1413 Shader::ShaderArgDir Shader::
1414 cg_parameter_dir(CGparameter p) {
1415 switch (cgGetParameterDirection(p)) {
1416 case CG_IN:
return Shader::SAD_in;
1417 case CG_OUT:
return Shader::SAD_out;
1418 case CG_INOUT:
return Shader::SAD_inout;
1419 default:
return Shader::SAD_unknown;
1429 cg_release_resources() {
1430 if (_cg_vprogram != 0) {
1431 cgDestroyProgram(_cg_vprogram);
1434 if (_cg_fprogram != 0) {
1435 cgDestroyProgram(_cg_fprogram);
1438 if (_cg_gprogram != 0) {
1439 cgDestroyProgram(_cg_gprogram);
1450 cg_compile_entry_point(
const char *entry,
const ShaderCaps &caps,
1451 CGcontext context, ShaderType type) {
1454 const char *compiler_args[100];
1455 const string text =
get_text(type);
1458 int active, ultimate;
1462 active = caps._active_vprofile;
1463 ultimate = caps._ultimate_vprofile;
1467 active = caps._active_fprofile;
1468 ultimate = caps._ultimate_fprofile;
1472 active = caps._active_gprofile;
1473 ultimate = caps._ultimate_gprofile;
1476 case ST_tess_evaluation:
1477 case ST_tess_control:
1478 active = caps._active_tprofile;
1479 ultimate = caps._ultimate_tprofile;
1484 active = CG_PROFILE_UNKNOWN;
1485 ultimate = CG_PROFILE_UNKNOWN;
1490 if (type == ST_fragment && caps._bug_list.count(SBUG_ati_draw_buffers)) {
1491 compiler_args[nargs++] =
"-po";
1492 compiler_args[nargs++] =
"ATI_draw_buffers";
1496 if (!cg_glsl_version.empty() && active != CG_PROFILE_UNKNOWN &&
1497 cgGetProfileProperty((CGprofile) active, CG_IS_GLSL_PROFILE)) {
1499 version_arg =
"version=";
1500 version_arg += cg_glsl_version;
1502 compiler_args[nargs++] =
"-po";
1503 compiler_args[nargs++] = version_arg.c_str();
1506 compiler_args[nargs] = 0;
1508 if ((active != (
int)CG_PROFILE_UNKNOWN) && (active != ultimate)) {
1510 if (shader_cat.is_debug()) {
1512 <<
"Compiling Cg shader " <<
get_filename(type) <<
" with entry point " << entry
1513 <<
" and active profile " << cgGetProfileString((CGprofile) active) <<
"\n";
1516 shader_cat.debug() <<
"Using compiler arguments:";
1517 for (
int i = 0; i < nargs; ++i) {
1518 shader_cat.debug(
false) <<
" " << compiler_args[i];
1520 shader_cat.debug(
false) <<
"\n";
1525 prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
1526 (CGprofile)active, entry, (
const char **)compiler_args);
1528 if (err == CG_NO_ERROR) {
1532 cgDestroyProgram(prog);
1534 if (shader_cat.is_debug()) {
1536 <<
"Compilation with active profile failed: " << cgGetErrorString(err) <<
"\n";
1540 if (shader_cat.is_debug()) {
1542 <<
"Compiling Cg shader " <<
get_filename(type) <<
" with entry point " << entry
1543 <<
" and ultimate profile " << cgGetProfileString((CGprofile) ultimate) <<
"\n";
1547 prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
1548 (CGprofile)ultimate, entry, (
const char **)NULL);
1552 const char *listing = cgGetLastListing(context);
1554 if (err == CG_NO_ERROR && listing != NULL && strlen(listing) > 1) {
1555 shader_cat.warning()
1556 <<
"Encountered warnings during compilation of " <<
get_filename(type)
1557 <<
":\n" << listing;
1559 }
else if (err == CG_COMPILER_ERROR) {
1561 <<
"Failed to compile Cg shader " <<
get_filename(type);
1562 if (listing != NULL) {
1563 shader_cat.error(
false) <<
":\n" << listing;
1565 shader_cat.error(
false) <<
"!\n";
1569 if (err == CG_NO_ERROR) {
1574 cgDestroyProgram(prog);
1587 cg_compile_shader(
const ShaderCaps &caps, CGcontext context) {
1588 _cg_last_caps = caps;
1590 if (!_text._separate || !_text._vertex.empty()) {
1591 _cg_vprogram = cg_compile_entry_point(
"vshader", caps, context, ST_vertex);
1592 if (_cg_vprogram == 0) {
1593 cg_release_resources();
1596 _cg_vprofile = cgGetProgramProfile(_cg_vprogram);
1599 if (!_text._separate || !_text._fragment.empty()) {
1600 _cg_fprogram = cg_compile_entry_point(
"fshader", caps, context, ST_fragment);
1601 if (_cg_fprogram == 0) {
1602 cg_release_resources();
1605 _cg_fprofile = cgGetProgramProfile(_cg_fprogram);
1608 if ((_text._separate && !_text._geometry.empty()) || (!_text._separate && _text._shared.find(
"gshader") != string::npos)) {
1609 _cg_gprogram = cg_compile_entry_point(
"gshader", caps, context, ST_geometry);
1610 if (_cg_gprogram == 0) {
1611 cg_release_resources();
1614 _cg_gprofile = cgGetProgramProfile(_cg_gprogram);
1617 if (_cg_vprogram == 0 && _cg_fprogram == 0 && _cg_gprogram == 0) {
1618 shader_cat.error() <<
"Shader must at least have one program!\n";
1619 cg_release_resources();
1627 if (_cg_fprofile == CG_PROFILE_PS_2_0 ||
1628 _cg_fprofile == CG_PROFILE_PS_2_X ||
1629 _cg_fprofile == CG_PROFILE_PS_3_0) {
1630 vector_string lines;
1631 tokenize(cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM), lines,
"\n");
1634 int num_modified = 0;
1636 for (
size_t i = 0; i < lines.size(); ++i) {
1637 const string &line = lines[i];
1639 size_t space = line.find(
' ');
1640 if (space == string::npos) {
1641 out << line <<
'\n';
1645 string instr = line.substr(0, space);
1648 if (instr.compare(0, 5,
"texld") == 0 &&
1649 instr.compare(instr.size() - 4, 4,
"_sat") == 0) {
1651 string reg = line.substr(space + 1, line.find(
',', space) - space - 1);
1654 instr.resize(instr.size() - 4);
1655 out << instr <<
' ' << line.substr(space + 1) <<
'\n';
1656 out <<
"mov_sat " << reg <<
", " << reg <<
'\n';
1659 out << line <<
'\n';
1663 if (num_modified > 0) {
1664 string result = out.str();
1665 CGprogram new_program;
1666 new_program = cgCreateProgram(context, CG_OBJECT, result.c_str(),
1667 (CGprofile)_cg_fprofile,
"fshader",
1668 (
const char**)NULL);
1670 cgDestroyProgram(_cg_fprogram);
1671 _cg_fprogram = new_program;
1673 if (shader_cat.is_debug()) {
1675 <<
"Replaced " << num_modified <<
" invalid texld_sat instruction" 1676 << ((num_modified == 1) ?
"" :
"s") <<
" in compiled shader\n";
1679 shader_cat.warning()
1680 <<
"Failed to load shader with fixed texld_sat instructions: " 1681 << cgGetErrorString(cgGetError()) <<
"\n";
1687 if (shader_cat.is_debug()) {
1688 const char *vertex_program;
1689 const char *fragment_program;
1690 const char *geometry_program;
1692 if (_cg_vprogram != 0) {
1694 <<
"Cg vertex profile: " << cgGetProfileString((CGprofile)_cg_vprofile) <<
"\n";
1695 vertex_program = cgGetProgramString(_cg_vprogram, CG_COMPILED_PROGRAM);
1696 shader_cat.debug() << vertex_program <<
"\n";
1698 if (_cg_fprogram != 0) {
1700 <<
"Cg fragment profile: " << cgGetProfileString((CGprofile)_cg_fprofile) <<
"\n";
1701 fragment_program = cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM);
1702 shader_cat.debug() << fragment_program <<
"\n";
1704 if (_cg_gprogram != 0) {
1706 <<
"Cg geometry profile: " << cgGetProfileString((CGprofile)_cg_gprofile) <<
"\n";
1707 geometry_program = cgGetProgramString(_cg_gprogram, CG_COMPILED_PROGRAM);
1708 shader_cat.debug() << geometry_program <<
"\n";
1721 cg_analyze_entry_point(CGprogram prog, ShaderType type) {
1722 bool success =
true;
1724 cg_recurse_parameters(cgGetFirstParameter(prog, CG_PROGRAM), type, success);
1764 if (_cg_context == 0) {
1765 _cg_context = cgCreateContext();
1766 if (_cg_context == 0) {
1768 <<
"Could not create a Cg context object: " 1769 << cgGetErrorString(cgGetError()) <<
"\n";
1774 if (!cg_compile_shader(caps, _cg_context)) {
1778 if (_cg_fprogram != 0) {
1779 if (!cg_analyze_entry_point(_cg_fprogram, ST_fragment)) {
1780 cg_release_resources();
1786 if (_var_spec.size() != 0) {
1787 shader_cat.error() <<
"Cannot use vtx parameters in an fshader\n";
1788 cg_release_resources();
1793 if (_cg_vprogram != 0) {
1794 if (!cg_analyze_entry_point(_cg_vprogram, ST_vertex)) {
1795 cg_release_resources();
1801 if (_cg_gprogram != 0) {
1802 if (!cg_analyze_entry_point(_cg_gprogram, ST_geometry)) {
1803 cg_release_resources();
1811 for (
int i=0; i<(int)_mat_spec.size(); i++) {
1812 _mat_spec[i]._id._seqno = seqno++;
1814 for (
int i=0; i<(int)_tex_spec.size(); i++) {
1815 _tex_spec[i]._id._seqno = seqno++;
1817 for (
int i=0; i<(int)_var_spec.size(); i++) {
1818 _var_spec[i]._id._seqno = seqno++;
1821 for (
int i=0; i<(int)_ptr_spec.size(); i++) {
1822 _ptr_spec[i]._id._seqno = seqno++;
1823 _ptr_spec[i]._info._id = _ptr_spec[i]._id;
1899 cg_release_resources();
1910 cg_program_from_shadertype(ShaderType type) {
1913 return _cg_vprogram;
1916 return _cg_fprogram;
1919 return _cg_gprogram;
1935 cg_compile_for(
const ShaderCaps &caps, CGcontext context,
1939 combined_program = 0;
1945 _default_caps = caps;
1946 if (!cg_compile_shader(caps, context)) {
1953 if (_cg_vprogram != 0 && _cg_vprofile != caps._active_vprofile) {
1954 shader_cat.error() <<
"Cg vertex program not supported by profile " 1955 << cgGetProfileString((CGprofile) caps._active_vprofile) <<
": " 1956 <<
get_filename(ST_vertex) <<
". Try choosing a different profile.\n";
1959 if (_cg_fprogram != 0 && _cg_fprofile != caps._active_fprofile) {
1960 shader_cat.error() <<
"Cg fragment program not supported by profile " 1961 << cgGetProfileString((CGprofile) caps._active_fprofile) <<
": " 1962 <<
get_filename(ST_fragment) <<
". Try choosing a different profile.\n";
1965 if (_cg_gprogram != 0 && _cg_gprofile != caps._active_gprofile) {
1966 shader_cat.error() <<
"Cg geometry program not supported by profile " 1967 << cgGetProfileString((CGprofile) caps._active_gprofile) <<
": " 1968 <<
get_filename(ST_geometry) <<
". Try choosing a different profile.\n";
1974 if (_cg_vprogram != 0) {
1975 programs.push_back(_cg_vprogram);
1977 if (_cg_fprogram != 0) {
1978 programs.push_back(_cg_fprogram);
1980 if (_cg_gprogram != 0) {
1981 programs.push_back(_cg_gprogram);
1987 combined_program = cgCombinePrograms(programs.size(), &programs[0]);
1990 int n_mat = (int)_mat_spec.size();
1991 int n_tex = (int)_tex_spec.size();
1992 int n_var = (int)_var_spec.size();
1993 int n_ptr = (int)_ptr_spec.size();
1995 map.resize(n_mat + n_tex + n_var + n_ptr);
1999 CGprogram programs_by_type[ST_COUNT];
2000 for (
int i = 0; i < cgGetNumProgramDomains(combined_program); ++i) {
2002 CGprogram program = cgGetProgramDomainProgram(combined_program, i);
2003 programs_by_type[cgGetProgramDomain(program)] = program;
2006 for (
int i = 0; i < n_mat; ++i) {
2008 map[
id._seqno] = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
2011 for (
int i = 0; i < n_tex; ++i) {
2013 CGparameter p = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
2015 if (shader_cat.is_debug()) {
2016 const char *resource = cgGetParameterResourceName(p);
2017 if (resource != NULL) {
2018 shader_cat.debug() <<
"Texture parameter " <<
id._name
2019 <<
" is bound to resource " << resource <<
"\n";
2025 for (
int i = 0; i < n_var; ++i) {
2027 CGparameter p = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
2029 const char *resource = cgGetParameterResourceName(p);
2030 if (shader_cat.is_debug() && resource != NULL) {
2032 <<
"Varying parameter " <<
id._name <<
" is bound to resource " 2033 << cgGetParameterResourceName(p) <<
"\n";
2036 if (cgGetParameterBaseResource(p) == CG_UNDEFINED) {
2042 <<
"Varying parameter " <<
id._name;
2044 const char *semantic = cgGetParameterSemantic(p);
2045 if (semantic != NULL) {
2046 shader_cat.error(
false) <<
" : " << semantic;
2048 if (resource != NULL) {
2049 shader_cat.error(
false) <<
" (bound to resource " << resource <<
")";
2051 shader_cat.error(
false) <<
" is invalid!\n";
2055 if (semantic != NULL) {
2056 if (strcmp(semantic,
"POSITION0") == 0) {
2057 shader_cat.error() <<
"Try using the semantic POSITION instead of POSITION0.\n";
2058 }
else if (strcmp(semantic,
"NORMAL0") == 0) {
2059 shader_cat.error() <<
"Try using the semantic NORMAL instead of NORMAL0.\n";
2060 }
else if (strcmp(semantic,
"DIFFUSE0") == 0) {
2061 shader_cat.error() <<
"Try using the semantic DIFFUSE instead of DIFFUSE0.\n";
2062 }
else if (strcmp(semantic,
"SPECULAR0") == 0) {
2063 shader_cat.error() <<
"Try using the semantic SPECULAR instead of SPECULAR0.\n";
2064 }
else if (strcmp(semantic,
"FOGCOORD0") == 0) {
2065 shader_cat.error() <<
"Try using the semantic FOGCOORD instead of FOGCOORD0.\n";
2066 }
else if (strcmp(semantic,
"PSIZE0") == 0) {
2067 shader_cat.error() <<
"Try using the semantic PSIZE instead of PSIZE0.\n";
2076 for (
int i = 0; i < n_ptr; ++i) {
2078 map[
id._seqno] = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
2082 if (_cg_vprogram != 0) {
2083 cgDestroyProgram(_cg_vprogram);
2086 if (_cg_fprogram != 0) {
2087 cgDestroyProgram(_cg_fprogram);
2090 if (_cg_gprogram != 0) {
2091 cgDestroyProgram(_cg_gprogram);
2095 _cg_last_caps.clear();
2108 Shader(ShaderLanguage lang) :
2119 _cg_vprofile = CG_PROFILE_UNKNOWN;
2120 _cg_fprofile = CG_PROFILE_UNKNOWN;
2121 _cg_gprofile = CG_PROFILE_UNKNOWN;
2122 if (_default_caps._ultimate_vprofile == 0 || _default_caps._ultimate_vprofile == CG_PROFILE_UNKNOWN) {
2123 _default_caps._active_vprofile = CG_PROFILE_UNKNOWN;
2124 _default_caps._active_fprofile = CG_PROFILE_UNKNOWN;
2125 _default_caps._active_gprofile = CG_PROFILE_UNKNOWN;
2126 _default_caps._ultimate_vprofile = cgGetProfile(
"glslv");
2127 _default_caps._ultimate_fprofile = cgGetProfile(
"glslf");
2128 _default_caps._ultimate_gprofile = cgGetProfile(
"glslg");
2129 if (_default_caps._ultimate_gprofile == CG_PROFILE_UNKNOWN) {
2130 _default_caps._ultimate_gprofile = cgGetProfile(
"gp4gp");
2144 _text._separate = sfile._separate;
2146 if (sfile._separate) {
2147 if (_language == SL_none) {
2149 <<
"No shader language was specified!\n";
2153 if (!sfile._vertex.empty() && !do_read_source(_text._vertex, sfile._vertex)) {
2156 if (!sfile._fragment.empty() && !do_read_source(_text._fragment, sfile._fragment)) {
2159 if (!sfile._geometry.empty() && !do_read_source(_text._geometry, sfile._geometry)) {
2162 if (!sfile._tess_control.empty() && !do_read_source(_text._tess_control, sfile._tess_control)) {
2165 if (!sfile._tess_evaluation.empty() && !do_read_source(_text._tess_evaluation, sfile._tess_evaluation)) {
2168 if (!sfile._compute.empty() && !do_read_source(_text._compute, sfile._compute)) {
2174 if (!do_read_source(_text._shared, sfile._shared)) {
2180 if (_language == SL_none) {
2184 if (header ==
"//Cg") {
2188 <<
"Unable to determine shader language of " << sfile._shared <<
"\n";
2191 }
else if (_language == SL_GLSL) {
2193 <<
"GLSL shaders must have separate shader bodies!\n";
2198 if (_language == SL_Cg) {
2200 cg_get_profile_from_header(_default_caps);
2202 if (!cg_analyze_shader(_default_caps)) {
2204 <<
"Shader encountered an error.\n";
2209 <<
"Tried to load Cg shader, but no Cg support is enabled.\n";
2213 <<
"Shader is not in a supported shader-language.\n";
2232 do_read_source(
string &into,
const Filename &fn) {
2233 if (_language == SL_GLSL && glsl_preprocess) {
2235 set<Filename> open_files;
2237 if (!r_preprocess_source(sstr, fn,
Filename(), open_files)) {
2243 shader_cat.info() <<
"Reading shader file: " << fn <<
"\n";
2249 <<
"Could not find shader file: " << fn <<
"\n";
2253 if (!vf->read_file(into,
true)) {
2255 <<
"Could not read shader file: " << fn <<
"\n";
2259 _last_modified = max(_last_modified, vf->get_timestamp());
2260 _source_files.push_back(vf->get_filename());
2275 r_preprocess_source(ostream &out,
const Filename &fn,
2277 set<Filename> &once_files,
int depth) {
2279 if (depth > glsl_include_recursion_limit) {
2281 <<
"#pragma include nested too deeply\n";
2286 if (!source_dir.empty()) {
2294 <<
"Could not find shader file: " << fn <<
"\n";
2298 Filename full_fn = vf->get_filename();
2299 if (once_files.find(full_fn) != once_files.end()) {
2304 istream *source = vf->open_read_file(
true);
2305 if (source == NULL) {
2307 <<
"Could not open shader file: " << fn <<
"\n";
2311 _last_modified = max(_last_modified, vf->get_timestamp());
2312 _source_files.push_back(full_fn);
2323 fileno = 2048 + _included_files.size();
2327 _included_files.push_back(fn);
2329 out <<
"#line 1 " << fileno <<
" // " << fn <<
"\n";
2330 if (shader_cat.is_debug()) {
2332 <<
"Preprocessing shader include " << fileno <<
": " << fn <<
"\n";
2336 <<
"Preprocessing shader file: " << fn <<
"\n";
2341 bool had_include =
false;
2343 while (getline(*source, line)) {
2348 if (line.size() < 8 ||
2349 sscanf(line.c_str(),
" # pragma %63s", pragma) != 1) {
2351 out << line <<
"\n";
2357 if (had_include && sscanf(line.c_str(),
" # endif %n", &nread) == 0 && nread >= 6) {
2358 out <<
"#line " << (lineno + 1) <<
" " << fileno <<
"\n";
2364 if (strcmp(pragma,
"include") == 0) {
2369 if (sscanf(line.c_str(),
" # pragma%*[ \t]include \"%2047[^\"]\" %n", incfile, &nread) == 1
2370 && nread == line.size()) {
2375 }
else if (sscanf(line.c_str(),
" # pragma%*[ \t]include <%2047[^\"]> %n", incfile, &nread) == 1
2376 && nread == line.size()) {
2384 <<
"Malformed #pragma include at line " << lineno
2385 <<
" of file " << fn <<
":\n " << line <<
"\n";
2391 if (!r_preprocess_source(out, incfn, source_dir, once_files, depth + 1)) {
2393 shader_cat.error(
false) <<
"included at line " 2394 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
2399 out <<
"#line " << (lineno + 1) <<
" " << fileno <<
" // " << fn <<
"\n";
2402 }
else if (strcmp(pragma,
"once") == 0) {
2404 if (sscanf(line.c_str(),
" # pragma%*[ \t]once %n", &nread) != 0 ||
2405 nread != line.size()) {
2407 <<
"Malformed #pragma once at line " << lineno
2408 <<
" of file " << fn <<
":\n " << line <<
"\n";
2412 once_files.insert(full_fn);
2414 }
else if (strcmp(pragma,
"optionNV") == 0) {
2416 out << line <<
"\n";
2420 out << line <<
"\n";
2421 shader_cat.warning()
2422 <<
"Ignoring unknown pragma directive \"" << pragma <<
"\" at line " 2423 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
2427 vf->close_read_file(source);
2438 check_modified()
const {
2442 for (it = _source_files.begin(); it != _source_files.end(); ++it) {
2446 if (vfile == (
VirtualFile *)NULL || vfile->get_timestamp() > _last_modified) {
2462 cg_get_profile_from_header(
ShaderCaps& caps) {
2476 int profilePos = buf.find(
"//Cg profile");
2477 if (profilePos >= 0) {
2479 if ((
int)buf.find(
"gp4vp") >= 0)
2480 caps._active_vprofile = cgGetProfile(
"gp4vp");
2482 if ((
int)buf.find(
"gp5vp") >= 0)
2483 caps._active_vprofile = cgGetProfile(
"gp5vp");
2485 if ((
int)buf.find(
"glslv") >= 0)
2486 caps._active_vprofile = cgGetProfile(
"glslv");
2488 if ((
int)buf.find(
"arbvp1") >= 0)
2489 caps._active_vprofile = cgGetProfile(
"arbvp1");
2491 if ((
int)buf.find(
"vp40") >= 0)
2492 caps._active_vprofile = cgGetProfile(
"vp40");
2494 if ((
int)buf.find(
"vp30") >= 0)
2495 caps._active_vprofile = cgGetProfile(
"vp30");
2497 if ((
int)buf.find(
"vp20") >= 0)
2498 caps._active_vprofile = cgGetProfile(
"vp20");
2500 if ((
int)buf.find(
"vs_1_1") >= 0)
2501 caps._active_vprofile = cgGetProfile(
"vs_1_1");
2503 if ((
int)buf.find(
"vs_2_0") >= 0)
2504 caps._active_vprofile = cgGetProfile(
"vs_2_0");
2506 if ((
int)buf.find(
"vs_2_x") >= 0)
2507 caps._active_vprofile = cgGetProfile(
"vs_2_x");
2509 if ((
int)buf.find(
"vs_3_0") >= 0)
2510 caps._active_vprofile = cgGetProfile(
"vs_3_0");
2512 if ((
int)buf.find(
"vs_4_0") >= 0)
2513 caps._active_vprofile = cgGetProfile(
"vs_4_0");
2515 if ((
int)buf.find(
"vs_5_0") >= 0)
2516 caps._active_vprofile = cgGetProfile(
"vs_5_0");
2519 if ((
int)buf.find(
"gp4fp") >= 0)
2520 caps._active_fprofile = cgGetProfile(
"gp4fp");
2522 if ((
int)buf.find(
"gp5fp") >= 0)
2523 caps._active_fprofile = cgGetProfile(
"gp5fp");
2525 if ((
int)buf.find(
"glslf") >= 0)
2526 caps._active_fprofile = cgGetProfile(
"glslf");
2528 if ((
int)buf.find(
"arbfp1") >= 0)
2529 caps._active_fprofile = cgGetProfile(
"arbfp1");
2531 if ((
int)buf.find(
"fp40") >= 0)
2532 caps._active_fprofile = cgGetProfile(
"fp40");
2534 if ((
int)buf.find(
"fp30") >= 0)
2535 caps._active_fprofile = cgGetProfile(
"fp30");
2537 if ((
int)buf.find(
"fp20") >= 0)
2538 caps._active_fprofile = cgGetProfile(
"fp20");
2540 if ((
int)buf.find(
"ps_1_1") >= 0)
2541 caps._active_fprofile = cgGetProfile(
"ps_1_1");
2543 if ((
int)buf.find(
"ps_1_2") >= 0)
2544 caps._active_fprofile = cgGetProfile(
"ps_1_2");
2546 if ((
int)buf.find(
"ps_1_3") >= 0)
2547 caps._active_fprofile = cgGetProfile(
"ps_1_3");
2549 if ((
int)buf.find(
"ps_2_0") >= 0)
2550 caps._active_fprofile = cgGetProfile(
"ps_2_0");
2552 if ((
int)buf.find(
"ps_2_x") >= 0)
2553 caps._active_fprofile = cgGetProfile(
"ps_2_x");
2555 if ((
int)buf.find(
"ps_3_0") >= 0)
2556 caps._active_fprofile = cgGetProfile(
"ps_3_0");
2558 if ((
int)buf.find(
"ps_4_0") >= 0)
2559 caps._active_fprofile = cgGetProfile(
"ps_4_0");
2561 if ((
int)buf.find(
"ps_5_0") >= 0)
2562 caps._active_fprofile = cgGetProfile(
"ps_5_0");
2565 if ((
int)buf.find(
"gp4gp") >= 0)
2566 caps._active_gprofile = cgGetProfile(
"gp4gp");
2568 if ((
int)buf.find(
"gp5gp") >= 0)
2569 caps._active_gprofile = cgGetProfile(
"gp5gp");
2571 if ((
int)buf.find(
"glslg") >= 0)
2572 caps._active_gprofile = cgGetProfile(
"glslg");
2574 if ((
int)buf.find(
"gs_4_0") >= 0)
2575 caps._active_gprofile = cgGetProfile(
"gs_4_0");
2577 if ((
int)buf.find(
"gs_5_0") >= 0)
2578 caps._active_gprofile = cgGetProfile(
"gs_5_0");
2580 }
while(_parse > lastParse);
2609 load(
const Filename &file, ShaderLanguage lang) {
2611 ShaderTable::const_iterator i = _load_table.find(sfile);
2612 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
2614 if (i->second->check_modified()) {
2616 <<
"Shader " << file <<
" was modified on disk, reloading.\n";
2619 <<
"Shader " << file <<
" was found in shader cache.\n";
2625 if (!shader->read(sfile)) {
2629 _load_table[sfile] = shader;
2640 load(ShaderLanguage lang,
const Filename &vertex,
2643 ShaderFile sfile(vertex, fragment, geometry, tess_control, tess_evaluation);
2644 ShaderTable::const_iterator i = _load_table.find(sfile);
2645 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
2647 if (i->second->check_modified()) {
2649 <<
"Shader was modified on disk, reloading.\n";
2652 <<
"Shader was found in shader cache.\n";
2658 if (!shader->read(sfile)) {
2662 _load_table[sfile] = shader;
2672 load_compute(ShaderLanguage lang,
const Filename &fn) {
2673 if (lang != SL_GLSL) {
2675 <<
"Only GLSL compute shaders are currently supported.\n";
2680 sfile._separate =
true;
2681 sfile._compute = fn;
2683 ShaderTable::const_iterator i = _load_table.find(sfile);
2684 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
2686 if (i->second->check_modified()) {
2688 <<
"Compute shader " << fn <<
" was modified on disk, reloading.\n";
2691 <<
"Compute shader " << fn <<
" was found in shader cache.\n";
2697 if (!shader->read(sfile)) {
2701 _load_table[sfile] = shader;
2711 make(
const string &body, ShaderLanguage lang) {
2712 if (lang == SL_GLSL) {
2714 <<
"GLSL shaders must have separate shader bodies!\n";
2717 }
else if (lang == SL_none) {
2718 shader_cat.warning()
2719 <<
"Shader::make() now requires an explicit shader language. Assuming Cg.\n";
2723 if (lang == SL_Cg) {
2724 shader_cat.error() <<
"Support for Cg shaders is not enabled.\n";
2731 if (cache_generated_shaders) {
2732 ShaderTable::const_iterator i = _make_table.find(sbody);
2733 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
2739 shader->_filename =
ShaderFile(
"created-shader");
2740 shader->_text = sbody;
2743 if (lang == SL_Cg) {
2744 shader->cg_get_profile_from_header(_default_caps);
2746 if (!shader->cg_analyze_shader(_default_caps)) {
2748 <<
"Shader encountered an error.\n";
2754 if (cache_generated_shaders) {
2755 _make_table[sbody] = shader;
2758 if (dump_generated_shaders) {
2760 int index = _shaders_generated ++;
2761 fns <<
"genshader" << index;
2762 string fn = fns.str();
2763 shader_cat.warning() <<
"Dumping shader: " << fn <<
"\n";
2766 s.open(fn.c_str(), ios::out | ios::trunc);
2779 make(ShaderLanguage lang,
const string &vertex,
const string &fragment,
2780 const string &geometry,
const string &tess_control,
2781 const string &tess_evaluation) {
2783 if (lang == SL_Cg) {
2784 shader_cat.error() <<
"Support for Cg shaders is not enabled.\n";
2788 if (lang == SL_none) {
2790 <<
"Shader::make() requires an explicit shader language.\n";
2794 ShaderFile sbody(vertex, fragment, geometry, tess_control, tess_evaluation);
2796 if (cache_generated_shaders) {
2797 ShaderTable::const_iterator i = _make_table.find(sbody);
2798 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
2804 shader->_filename =
ShaderFile(
"created-shader");
2805 shader->_text = sbody;
2808 if (lang == SL_Cg) {
2809 if (!shader->cg_analyze_shader(_default_caps)) {
2811 <<
"Shader encountered an error.\n";
2817 if (cache_generated_shaders) {
2818 _make_table[sbody] = shader;
2830 make_compute(ShaderLanguage lang,
const string &body) {
2831 if (lang != SL_GLSL) {
2833 <<
"Only GLSL compute shaders are currently supported.\n";
2838 sbody._separate =
true;
2839 sbody._compute = body;
2842 if (cache_generated_shaders) {
2843 ShaderTable::const_iterator i = _make_table.find(sbody);
2844 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
2850 shader->_filename =
ShaderFile(
"created-shader");
2851 shader->_text = sbody;
2853 if (cache_generated_shaders) {
2854 _make_table[sbody] = shader;
2880 nassertv(!_text._separate);
2881 int len = _text._shared.size();
2884 while ((tail < len) && (_text._shared[tail] !=
'\n')) {
2893 while ((head < tail)&&(isspace(_text._shared[head]))) head++;
2894 while ((tail > head)&&(isspace(_text._shared[tail-1]))) tail--;
2896 result = _text._shared.substr(head, tail-head);
2909 nassertv(!_text._separate);
2913 while (_parse < (
int)(_text._shared.size())) {
2920 result = _text._shared.substr(start, _parse - start);
2922 result = _text._shared.substr(start, last - start);
2934 nassertv(!_text._separate);
2935 result = _text._shared.substr(_parse, _text._shared.size() - _parse);
2946 return (
int)_text._shared.size() == _parse;
2975 Contexts::const_iterator ci;
2976 ci = _contexts.find(prepared_objects);
2977 if (ci != _contexts.end()) {
2992 Contexts::iterator ci;
2993 ci = _contexts.find(prepared_objects);
2994 if (ci != _contexts.end()) {
2999 _contexts.erase(ci);
3027 Contexts::const_iterator ci;
3028 ci = _contexts.find(prepared_objects);
3029 if (ci != _contexts.end()) {
3030 return (*ci).second;
3034 _contexts[prepared_objects] = tc;
3050 Contexts::iterator ci;
3051 ci = _contexts.find(prepared_objects);
3052 if (ci != _contexts.end()) {
3053 _contexts.erase(ci);
3075 int num_freed = (int)_contexts.size();
3077 Contexts::const_iterator ci;
3078 for (ci = temp.begin(); ci != temp.end(); ++ci) {
3098 void Shader::ShaderCaps::
3100 _supports_glsl =
false;
3103 _active_vprofile = CG_PROFILE_UNKNOWN;
3104 _active_fprofile = CG_PROFILE_UNKNOWN;
3105 _active_gprofile = CG_PROFILE_UNKNOWN;
3106 _active_fprofile = CG_PROFILE_UNKNOWN;
3107 _ultimate_vprofile = CG_PROFILE_UNKNOWN;
3108 _ultimate_fprofile = CG_PROFILE_UNKNOWN;
3109 _ultimate_gprofile = CG_PROFILE_UNKNOWN;
3110 _ultimate_fprofile = CG_PROFILE_UNKNOWN;
3153 parse_params(params, scan, manager);
3154 attrib->fillin(scan, manager);
3167 _language = (ShaderLanguage) scan.
get_uint8();
string get_dirname() const
Returns the directory part of the filename.
PointerTo< VirtualFile > find_file(const Filename &filename, const DSearchPath &searchpath, bool status_only=false) const
Uses the indicated search path to find the file within the file system.
bool matches(const string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
void add_uint8(PN_uint8 value)
Adds an unsigned 8-bit integer to the datagram.
void release_shader(ShaderContext *sc)
Indicates that a shader context, created by a previous call to prepare_shader(), is no longer needed...
bool cp_errchk_parameter_varying(ShaderArgInfo &arg)
Make sure the provided parameter has the correct variance.
This is our own Panda specialization on the default STL map.
bool get_bool()
Extracts a boolean value.
static void register_with_read_factory()
Tells the BamReader how to create objects of type Shader.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS's file system.
Base class for objects that can be written to and read from Bam files.
void enqueue_shader(Shader *shader)
Indicates that a shader would like to be put on the list to be prepared when the GSG is next ready to...
int cp_dependency(ShaderMatInput inp)
Given ShaderMatInput, returns an indication of what part or parts of the state_and_transform the Shad...
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
bool cp_errchk_parameter_sampler(ShaderArgInfo &arg)
Make sure the provided parameter has a texture type.
PN_uint8 get_uint8()
Extracts an unsigned 8-bit integer.
The abstract base class for a file or directory within the VirtualFileSystem.
A table of objects that are saved within the graphics context for reference by handle later...
void parse_init()
Set a 'parse pointer' to the beginning of the shader.
bool cp_parse_eol(ShaderArgInfo &arg, vector_string &pieces, int &next)
Make sure the next thing on the word list is EOL.
void cp_optimize_mat_spec(ShaderMatSpec &spec)
Analyzes a ShaderMatSpec and decides what it should use its cache for.
The ShaderContext is meant to contain the compiled version of a shader string.
A particular category of error messages.
This is our own Panda specialization on the default STL vector.
ShaderContext * prepare_shader_now(Shader *shader, GraphicsStateGuardianBase *gsg)
Immediately creates a new ShaderContext for the indicated shader and returns it.
void read_datagram(DatagramIterator &source)
Reads the object from a Datagram.
bool cp_errchk_parameter_uniform(ShaderArgInfo &arg)
Make sure the provided parameter has the correct variance.
void parse_upto(string &result, string pattern, bool include)
Parse lines until you read a line that matches the specified pattern.
void add_bool(bool value)
Adds a boolean value to the datagram.
ostream & error(bool prefix=true) const
A shorthand way to write out(NS_error).
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
The name of a file, such as a texture file or an Egg file.
void write_datagram(Datagram &dg) const
Writes the contents of this object to the datagram for shipping out to a Bam file.
void parse_rest(string &result)
Returns the rest of the text from the current parse location.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
bool cp_parse_coord_sys(ShaderArgInfo &arg, vector_string &pieces, int &next, ShaderMatSpec &spec, bool fromflag)
Convert a single-word coordinate system name into a PART/ARG of a ShaderMatSpec.
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
~Shader()
Delete the compiled code, if it exists.
void cp_report_error(ShaderArgInfo &arg, const string &msg)
Generate an error message including a description of the specified parameter.
bool dequeue_shader(Shader *shader)
Removes a shader from the queued list of shaders to be prepared.
string cp_parse_non_delimiter(vector_string &pieces, int &next)
Pop a non-delimiter word from the word list.
void prepare(PreparedGraphicsObjects *prepared_objects)
Indicates that the shader should be enqueued to be prepared in the indicated prepared_objects at the ...
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
const string & get_text(const ShaderType &type=ST_none) const
Return the Shader's text for the given shader type.
Filename get_filename(const ShaderType &type=ST_none) const
Return the Shader's filename for the given shader type.
int release_all()
Frees the context allocated on all objects for which the texture has been declared.
bool cp_errchk_parameter_in(ShaderArgInfo &arg)
Make sure the provided parameter has the 'in' direction.
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const
Returns true if the shader has already been prepared or enqueued for preparation on the indicated GSG...
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the texture context only on the indicated object, if it exists there.
This class stores a list of directories that can be searched, in order, to locate a particular file...
void parse_line(string &result, bool rt, bool lt)
Parse a line of text.
bool compile_parameter(const ShaderArgId &arg_id, const ShaderArgClass &arg_class, const ShaderArgClass &arg_subclass, const ShaderArgType &arg_type, const ShaderArgDir &arg_direction, bool arg_varying, int *arg_dim, NotifyCategory *arg_cat)
Analyzes a parameter and decides how to bind the parameter to some part of panda's internal state...
void prepend_directory(const Filename &directory)
Adds a new directory to the front of the search list.
A class to retrieve the individual data elements previously stored in a Datagram. ...
TypeHandle is the identifier used to differentiate C++ class types.
bool parse_eof()
Returns true if the parse pointer is at the end of the shader.
bool cp_errchk_parameter_words(ShaderArgInfo &arg, int len)
Make sure the provided parameter contains the specified number of words.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
ShaderContext * prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the shader on the particular GSG, if it does not already exist.
bool cp_parse_delimiter(ShaderArgInfo &arg, vector_string &pieces, int &next)
Pop a delimiter ('to' or 'rel') from the word list.
This class can be used to test for string matches against standard Unix-shell filename globbing conve...
bool is_shader_queued(const Shader *shader) const
Returns true if the shader has been queued on this GSG, false otherwise.
bool cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi)
Make sure the provided parameter has a floating point type.