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:";
212 cp_errchk_parameter_ptr(ShaderArgInfo &p) {
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";
1495 char version_arg[16];
1496 if (!cg_glsl_version.empty() && cgGetProfileProperty((CGprofile) active, CG_IS_GLSL_PROFILE)) {
1497 snprintf(version_arg, 16,
"version=%s", cg_glsl_version.c_str());
1498 compiler_args[nargs++] =
"-po";
1499 compiler_args[nargs++] = version_arg;
1502 compiler_args[nargs] = 0;
1504 if ((active != (
int)CG_PROFILE_UNKNOWN) && (active != ultimate)) {
1506 if (shader_cat.is_debug()) {
1508 <<
"Compiling Cg shader " <<
get_filename(type) <<
" with entry point " << entry
1509 <<
" and active profile " << cgGetProfileString((CGprofile) active) <<
"\n";
1512 shader_cat.debug() <<
"Using compiler arguments:";
1513 for (
int i = 0; i < nargs; ++i) {
1514 shader_cat.debug(
false) <<
" " << compiler_args[i];
1516 shader_cat.debug(
false) <<
"\n";
1521 prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
1522 (CGprofile)active, entry, (
const char **)compiler_args);
1524 if (err == CG_NO_ERROR) {
1528 cgDestroyProgram(prog);
1530 if (shader_cat.is_debug()) {
1532 <<
"Compilation with active profile failed: " << cgGetErrorString(err) <<
"\n";
1536 if (shader_cat.is_debug()) {
1538 <<
"Compiling Cg shader " <<
get_filename(type) <<
" with entry point " << entry
1539 <<
" and ultimate profile " << cgGetProfileString((CGprofile) ultimate) <<
"\n";
1543 prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
1544 (CGprofile)ultimate, entry, (
const char **)NULL);
1548 const char *listing = cgGetLastListing(context);
1550 if (err == CG_NO_ERROR && listing != NULL && strlen(listing) > 1) {
1551 shader_cat.warning()
1552 <<
"Encountered warnings during compilation of " <<
get_filename(type)
1553 <<
":\n" << listing;
1555 }
else if (err == CG_COMPILER_ERROR) {
1557 <<
"Failed to compile Cg shader " <<
get_filename(type);
1558 if (listing != NULL) {
1559 shader_cat.error(
false) <<
":\n" << listing;
1561 shader_cat.error(
false) <<
"!\n";
1565 if (err == CG_NO_ERROR) {
1570 cgDestroyProgram(prog);
1583 cg_compile_shader(
const ShaderCaps &caps, CGcontext context) {
1584 _cg_last_caps = caps;
1586 if (!_text._separate || !_text._vertex.empty()) {
1587 _cg_vprogram = cg_compile_entry_point(
"vshader", caps, context, ST_vertex);
1588 if (_cg_vprogram == 0) {
1589 cg_release_resources();
1592 _cg_vprofile = cgGetProgramProfile(_cg_vprogram);
1595 if (!_text._separate || !_text._fragment.empty()) {
1596 _cg_fprogram = cg_compile_entry_point(
"fshader", caps, context, ST_fragment);
1597 if (_cg_fprogram == 0) {
1598 cg_release_resources();
1601 _cg_fprofile = cgGetProgramProfile(_cg_fprogram);
1604 if ((_text._separate && !_text._geometry.empty()) || (!_text._separate && _text._shared.find(
"gshader") != string::npos)) {
1605 _cg_gprogram = cg_compile_entry_point(
"gshader", caps, context, ST_geometry);
1606 if (_cg_gprogram == 0) {
1607 cg_release_resources();
1610 _cg_gprofile = cgGetProgramProfile(_cg_gprogram);
1613 if (_cg_vprogram == 0 && _cg_fprogram == 0 && _cg_gprogram == 0) {
1614 shader_cat.error() <<
"Shader must at least have one program!\n";
1615 cg_release_resources();
1620 if (shader_cat.is_debug()) {
1621 const char *vertex_program;
1622 const char *fragment_program;
1623 const char *geometry_program;
1625 if (_cg_vprogram != 0) {
1627 <<
"Cg vertex profile: " << cgGetProfileString((CGprofile)_cg_vprofile) <<
"\n";
1628 vertex_program = cgGetProgramString(_cg_vprogram, CG_COMPILED_PROGRAM);
1629 shader_cat.debug() << vertex_program <<
"\n";
1631 if (_cg_fprogram != 0) {
1633 <<
"Cg fragment profile: " << cgGetProfileString((CGprofile)_cg_fprofile) <<
"\n";
1634 fragment_program = cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM);
1635 shader_cat.debug() << fragment_program <<
"\n";
1637 if (_cg_gprogram != 0) {
1639 <<
"Cg geometry profile: " << cgGetProfileString((CGprofile)_cg_gprofile) <<
"\n";
1640 geometry_program = cgGetProgramString(_cg_gprogram, CG_COMPILED_PROGRAM);
1641 shader_cat.debug() << geometry_program <<
"\n";
1654 cg_analyze_entry_point(CGprogram prog, ShaderType type) {
1655 bool success =
true;
1657 cg_recurse_parameters(cgGetFirstParameter(prog, CG_PROGRAM), type, success);
1694 cg_analyze_shader(
const ShaderCaps &caps) {
1697 if (_cg_context == 0) {
1698 _cg_context = cgCreateContext();
1699 if (_cg_context == 0) {
1701 <<
"Could not create a Cg context object: "
1702 << cgGetErrorString(cgGetError()) <<
"\n";
1707 if (!cg_compile_shader(caps, _cg_context)) {
1711 if (_cg_fprogram != 0) {
1712 if (!cg_analyze_entry_point(_cg_fprogram, ST_fragment)) {
1713 cg_release_resources();
1719 if (_var_spec.size() != 0) {
1720 shader_cat.error() <<
"Cannot use vtx parameters in an fshader\n";
1721 cg_release_resources();
1726 if (_cg_vprogram != 0) {
1727 if (!cg_analyze_entry_point(_cg_vprogram, ST_vertex)) {
1728 cg_release_resources();
1734 if (_cg_gprogram != 0) {
1735 if (!cg_analyze_entry_point(_cg_gprogram, ST_geometry)) {
1736 cg_release_resources();
1744 for (
int i=0; i<(int)_mat_spec.size(); i++) {
1745 _mat_spec[i]._id._seqno = seqno++;
1747 for (
int i=0; i<(int)_tex_spec.size(); i++) {
1748 _tex_spec[i]._id._seqno = seqno++;
1750 for (
int i=0; i<(int)_var_spec.size(); i++) {
1751 _var_spec[i]._id._seqno = seqno++;
1754 for (
int i=0; i<(int)_ptr_spec.size(); i++) {
1755 _ptr_spec[i]._id._seqno = seqno++;
1756 _ptr_spec[i]._info._id = _ptr_spec[i]._id;
1832 cg_release_resources();
1843 cg_program_from_shadertype(ShaderType type) {
1846 return _cg_vprogram;
1849 return _cg_fprogram;
1852 return _cg_gprogram;
1868 cg_compile_for(
const ShaderCaps &caps, CGcontext context,
1872 combined_program = 0;
1878 _default_caps = caps;
1879 if (!cg_compile_shader(caps, context)) {
1886 if (_cg_vprogram != 0 && _cg_vprofile != caps._active_vprofile) {
1887 shader_cat.error() <<
"Cg vertex program not supported by profile "
1888 << cgGetProfileString((CGprofile) caps._active_vprofile) <<
": "
1889 <<
get_filename(ST_vertex) <<
". Try choosing a different profile.\n";
1892 if (_cg_fprogram != 0 && _cg_fprofile != caps._active_fprofile) {
1893 shader_cat.error() <<
"Cg fragment program not supported by profile "
1894 << cgGetProfileString((CGprofile) caps._active_fprofile) <<
": "
1895 <<
get_filename(ST_fragment) <<
". Try choosing a different profile.\n";
1898 if (_cg_gprogram != 0 && _cg_gprofile != caps._active_gprofile) {
1899 shader_cat.error() <<
"Cg geometry program not supported by profile "
1900 << cgGetProfileString((CGprofile) caps._active_gprofile) <<
": "
1901 <<
get_filename(ST_geometry) <<
". Try choosing a different profile.\n";
1907 if (_cg_vprogram != 0) {
1908 programs.push_back(_cg_vprogram);
1910 if (_cg_fprogram != 0) {
1911 programs.push_back(_cg_fprogram);
1913 if (_cg_gprogram != 0) {
1914 programs.push_back(_cg_gprogram);
1920 combined_program = cgCombinePrograms(programs.size(), &programs[0]);
1923 int n_mat = (int)_mat_spec.size();
1924 int n_tex = (int)_tex_spec.size();
1925 int n_var = (int)_var_spec.size();
1926 int n_ptr = (int)_ptr_spec.size();
1928 map.resize(n_mat + n_tex + n_var + n_ptr);
1932 CGprogram programs_by_type[ST_COUNT];
1933 for (
int i = 0; i < cgGetNumProgramDomains(combined_program); ++i) {
1935 CGprogram program = cgGetProgramDomainProgram(combined_program, i);
1936 programs_by_type[cgGetProgramDomain(program)] = program;
1939 for (
int i = 0; i < n_mat; ++i) {
1940 const ShaderArgId &
id = _mat_spec[i]._id;
1941 map[
id._seqno] = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
1944 for (
int i = 0; i < n_tex; ++i) {
1945 const ShaderArgId &
id = _tex_spec[i]._id;
1946 CGparameter p = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
1948 if (shader_cat.is_debug()) {
1949 const char *resource = cgGetParameterResourceName(p);
1950 if (resource != NULL) {
1951 shader_cat.debug() <<
"Texture parameter " <<
id._name
1952 <<
" is bound to resource " << resource <<
"\n";
1958 for (
int i = 0; i < n_var; ++i) {
1959 const ShaderArgId &
id = _var_spec[i]._id;
1960 CGparameter p = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
1962 const char *resource = cgGetParameterResourceName(p);
1963 if (shader_cat.is_debug() && resource != NULL) {
1965 <<
"Varying parameter " <<
id._name <<
" is bound to resource "
1966 << cgGetParameterResourceName(p) <<
"\n";
1969 if (cgGetParameterBaseResource(p) == CG_UNDEFINED) {
1975 <<
"Varying parameter " <<
id._name;
1977 const char *semantic = cgGetParameterSemantic(p);
1978 if (semantic != NULL) {
1979 shader_cat.error(
false) <<
" : " << semantic;
1981 if (resource != NULL) {
1982 shader_cat.error(
false) <<
" (bound to resource " << resource <<
")";
1984 shader_cat.error(
false) <<
" is invalid!\n";
1988 if (semantic != NULL) {
1989 if (strcmp(semantic,
"POSITION0") == 0) {
1990 shader_cat.error() <<
"Try using the semantic POSITION instead of POSITION0.\n";
1991 }
else if (strcmp(semantic,
"NORMAL0") == 0) {
1992 shader_cat.error() <<
"Try using the semantic NORMAL instead of NORMAL0.\n";
1993 }
else if (strcmp(semantic,
"DIFFUSE0") == 0) {
1994 shader_cat.error() <<
"Try using the semantic DIFFUSE instead of DIFFUSE0.\n";
1995 }
else if (strcmp(semantic,
"SPECULAR0") == 0) {
1996 shader_cat.error() <<
"Try using the semantic SPECULAR instead of SPECULAR0.\n";
1997 }
else if (strcmp(semantic,
"FOGCOORD0") == 0) {
1998 shader_cat.error() <<
"Try using the semantic FOGCOORD instead of FOGCOORD0.\n";
1999 }
else if (strcmp(semantic,
"PSIZE0") == 0) {
2000 shader_cat.error() <<
"Try using the semantic PSIZE instead of PSIZE0.\n";
2009 for (
int i = 0; i < n_ptr; ++i) {
2010 const ShaderArgId &
id = _ptr_spec[i]._id;
2011 map[
id._seqno] = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
2015 if (_cg_vprogram != 0) {
2016 cgDestroyProgram(_cg_vprogram);
2019 if (_cg_fprogram != 0) {
2020 cgDestroyProgram(_cg_fprogram);
2023 if (_cg_gprogram != 0) {
2024 cgDestroyProgram(_cg_gprogram);
2028 _cg_last_caps.clear();
2041 Shader(ShaderLanguage lang) :
2052 _cg_vprofile = CG_PROFILE_UNKNOWN;
2053 _cg_fprofile = CG_PROFILE_UNKNOWN;
2054 _cg_gprofile = CG_PROFILE_UNKNOWN;
2055 if (_default_caps._ultimate_vprofile == 0 || _default_caps._ultimate_vprofile == CG_PROFILE_UNKNOWN) {
2056 _default_caps._active_vprofile = CG_PROFILE_UNKNOWN;
2057 _default_caps._active_fprofile = CG_PROFILE_UNKNOWN;
2058 _default_caps._active_gprofile = CG_PROFILE_UNKNOWN;
2059 _default_caps._ultimate_vprofile = cgGetProfile(
"glslv");
2060 _default_caps._ultimate_fprofile = cgGetProfile(
"glslf");
2061 _default_caps._ultimate_gprofile = cgGetProfile(
"glslg");
2062 if (_default_caps._ultimate_gprofile == CG_PROFILE_UNKNOWN) {
2063 _default_caps._ultimate_gprofile = cgGetProfile(
"gp4gp");
2076 read(
const ShaderFile &sfile) {
2077 _text._separate = sfile._separate;
2079 if (sfile._separate) {
2080 if (_language == SL_none) {
2082 <<
"No shader language was specified!\n";
2086 if (!sfile._vertex.empty() && !do_read_source(_text._vertex, sfile._vertex)) {
2089 if (!sfile._fragment.empty() && !do_read_source(_text._fragment, sfile._fragment)) {
2092 if (!sfile._geometry.empty() && !do_read_source(_text._geometry, sfile._geometry)) {
2095 if (!sfile._tess_control.empty() && !do_read_source(_text._tess_control, sfile._tess_control)) {
2098 if (!sfile._tess_evaluation.empty() && !do_read_source(_text._tess_evaluation, sfile._tess_evaluation)) {
2101 if (!sfile._compute.empty() && !do_read_source(_text._compute, sfile._compute)) {
2107 if (!do_read_source(_text._shared, sfile._shared)) {
2113 if (_language == SL_none) {
2117 if (header ==
"//Cg") {
2121 <<
"Unable to determine shader language of " << sfile._shared <<
"\n";
2124 }
else if (_language == SL_GLSL) {
2126 <<
"GLSL shaders must have separate shader bodies!\n";
2131 if (_language == SL_Cg) {
2133 cg_get_profile_from_header(_default_caps);
2135 if (!cg_analyze_shader(_default_caps)) {
2137 <<
"Shader encountered an error.\n";
2142 <<
"Tried to load Cg shader, but no Cg support is enabled.\n";
2146 <<
"Shader is not in a supported shader-language.\n";
2165 do_read_source(
string &into,
const Filename &fn) {
2166 if (_language == SL_GLSL && glsl_preprocess) {
2168 set<Filename> open_files;
2170 if (!r_preprocess_source(sstr, fn,
Filename(), open_files)) {
2176 shader_cat.info() <<
"Reading shader file: " << fn <<
"\n";
2179 PT(
VirtualFile) vf = vfs->find_file(fn, get_model_path());
2182 <<
"Could not find shader file: " << fn <<
"\n";
2186 if (!vf->read_file(into,
true)) {
2188 <<
"Could not read shader file: " << fn <<
"\n";
2192 _last_modified = max(_last_modified, vf->get_timestamp());
2193 _source_files.push_back(vf->get_filename());
2208 r_preprocess_source(ostream &out,
const Filename &fn,
2210 set<Filename> &once_files,
int depth) {
2212 if (depth > glsl_include_recursion_limit) {
2214 <<
"#pragma include nested too deeply\n";
2219 if (!source_dir.empty()) {
2220 path.prepend_directory(source_dir);
2227 <<
"Could not find shader file: " << fn <<
"\n";
2231 Filename full_fn = vf->get_filename();
2232 if (once_files.find(full_fn) != once_files.end()) {
2237 istream *source = vf->open_read_file(
true);
2238 if (source == NULL) {
2240 <<
"Could not open shader file: " << fn <<
"\n";
2244 _last_modified = max(_last_modified, vf->get_timestamp());
2245 _source_files.push_back(full_fn);
2256 fileno = 2048 + _included_files.size();
2260 _included_files.push_back(fn);
2262 out <<
"#line 1 " << fileno <<
" // " << fn <<
"\n";
2263 if (shader_cat.is_debug()) {
2265 <<
"Preprocessing shader include " << fileno <<
": " << fn <<
"\n";
2269 <<
"Preprocessing shader file: " << fn <<
"\n";
2274 bool had_include =
false;
2276 while (getline(*source, line)) {
2280 out << line <<
"\n";
2284 if (line.size() < 8 ||
2285 sscanf(line.c_str(),
" # pragma %63s", pragma) != 1) {
2291 if (had_include && sscanf(line.c_str(),
" # endif %n", &nread) == 0 && nread >= 6) {
2292 out <<
"#line " << (lineno + 1) <<
" " << fileno <<
"\n";
2298 if (strcmp(pragma,
"include") == 0) {
2303 if (sscanf(line.c_str(),
" # pragma%*[ \t]include \"%2047[^\"]\" %n", incfile, &nread) == 1
2304 && nread == line.size()) {
2309 }
else if (sscanf(line.c_str(),
" # pragma%*[ \t]include <%2047[^\"]> %n", incfile, &nread) == 1
2310 && nread == line.size()) {
2318 <<
"Malformed #pragma include at line " << lineno
2319 <<
" of file " << fn <<
":\n " << line <<
"\n";
2325 if (!r_preprocess_source(out, incfn, source_dir, once_files, depth + 1)) {
2327 shader_cat.error(
false) <<
"included at line "
2328 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
2333 out <<
"#line " << (lineno + 1) <<
" " << fileno <<
" // " << fn <<
"\n";
2336 }
else if (strcmp(pragma,
"once") == 0) {
2338 if (sscanf(line.c_str(),
" # pragma%*[ \t]once %n", &nread) != 0 ||
2339 nread != line.size()) {
2341 <<
"Malformed #pragma once at line " << lineno
2342 <<
" of file " << fn <<
":\n " << line <<
"\n";
2346 once_files.insert(full_fn);
2348 }
else if (strcmp(pragma,
"optionNV") == 0) {
2352 shader_cat.warning()
2353 <<
"Ignoring unknown pragma directive \"" << pragma <<
"\" at line "
2354 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
2358 vf->close_read_file(source);
2369 check_modified()
const {
2373 for (it = _source_files.begin(); it != _source_files.end(); ++it) {
2377 if (vfile == (
VirtualFile *)NULL || vfile->get_timestamp() > _last_modified) {
2393 cg_get_profile_from_header(ShaderCaps& caps) {
2407 int profilePos = buf.find(
"//Cg profile");
2408 if (profilePos >= 0) {
2410 if ((
int)buf.find(
"gp4vp") >= 0)
2411 caps._active_vprofile = cgGetProfile(
"gp4vp");
2413 if ((
int)buf.find(
"gp5vp") >= 0)
2414 caps._active_vprofile = cgGetProfile(
"gp5vp");
2416 if ((
int)buf.find(
"glslv") >= 0)
2417 caps._active_vprofile = cgGetProfile(
"glslv");
2419 if ((
int)buf.find(
"arbvp1") >= 0)
2420 caps._active_vprofile = cgGetProfile(
"arbvp1");
2422 if ((
int)buf.find(
"vp40") >= 0)
2423 caps._active_vprofile = cgGetProfile(
"vp40");
2425 if ((
int)buf.find(
"vp30") >= 0)
2426 caps._active_vprofile = cgGetProfile(
"vp30");
2428 if ((
int)buf.find(
"vp20") >= 0)
2429 caps._active_vprofile = cgGetProfile(
"vp20");
2431 if ((
int)buf.find(
"vs_1_1") >= 0)
2432 caps._active_vprofile = cgGetProfile(
"vs_1_1");
2434 if ((
int)buf.find(
"vs_2_0") >= 0)
2435 caps._active_vprofile = cgGetProfile(
"vs_2_0");
2437 if ((
int)buf.find(
"vs_2_x") >= 0)
2438 caps._active_vprofile = cgGetProfile(
"vs_2_x");
2440 if ((
int)buf.find(
"vs_3_0") >= 0)
2441 caps._active_vprofile = cgGetProfile(
"vs_3_0");
2443 if ((
int)buf.find(
"vs_4_0") >= 0)
2444 caps._active_vprofile = cgGetProfile(
"vs_4_0");
2446 if ((
int)buf.find(
"vs_5_0") >= 0)
2447 caps._active_vprofile = cgGetProfile(
"vs_5_0");
2450 if ((
int)buf.find(
"gp4fp") >= 0)
2451 caps._active_fprofile = cgGetProfile(
"gp4fp");
2453 if ((
int)buf.find(
"gp5fp") >= 0)
2454 caps._active_fprofile = cgGetProfile(
"gp5fp");
2456 if ((
int)buf.find(
"glslf") >= 0)
2457 caps._active_fprofile = cgGetProfile(
"glslf");
2459 if ((
int)buf.find(
"arbfp1") >= 0)
2460 caps._active_fprofile = cgGetProfile(
"arbfp1");
2462 if ((
int)buf.find(
"fp40") >= 0)
2463 caps._active_fprofile = cgGetProfile(
"fp40");
2465 if ((
int)buf.find(
"fp30") >= 0)
2466 caps._active_fprofile = cgGetProfile(
"fp30");
2468 if ((
int)buf.find(
"fp20") >= 0)
2469 caps._active_fprofile = cgGetProfile(
"fp20");
2471 if ((
int)buf.find(
"ps_1_1") >= 0)
2472 caps._active_fprofile = cgGetProfile(
"ps_1_1");
2474 if ((
int)buf.find(
"ps_1_2") >= 0)
2475 caps._active_fprofile = cgGetProfile(
"ps_1_2");
2477 if ((
int)buf.find(
"ps_1_3") >= 0)
2478 caps._active_fprofile = cgGetProfile(
"ps_1_3");
2480 if ((
int)buf.find(
"ps_2_0") >= 0)
2481 caps._active_fprofile = cgGetProfile(
"ps_2_0");
2483 if ((
int)buf.find(
"ps_2_x") >= 0)
2484 caps._active_fprofile = cgGetProfile(
"ps_2_x");
2486 if ((
int)buf.find(
"ps_3_0") >= 0)
2487 caps._active_fprofile = cgGetProfile(
"ps_3_0");
2489 if ((
int)buf.find(
"ps_4_0") >= 0)
2490 caps._active_fprofile = cgGetProfile(
"ps_4_0");
2492 if ((
int)buf.find(
"ps_5_0") >= 0)
2493 caps._active_fprofile = cgGetProfile(
"ps_5_0");
2496 if ((
int)buf.find(
"gp4gp") >= 0)
2497 caps._active_gprofile = cgGetProfile(
"gp4gp");
2499 if ((
int)buf.find(
"gp5gp") >= 0)
2500 caps._active_gprofile = cgGetProfile(
"gp5gp");
2502 if ((
int)buf.find(
"glslg") >= 0)
2503 caps._active_gprofile = cgGetProfile(
"glslg");
2505 if ((
int)buf.find(
"gs_4_0") >= 0)
2506 caps._active_gprofile = cgGetProfile(
"gs_4_0");
2508 if ((
int)buf.find(
"gs_5_0") >= 0)
2509 caps._active_gprofile = cgGetProfile(
"gs_5_0");
2511 }
while(_parse > lastParse);
2540 load(const
Filename &file, ShaderLanguage lang) {
2541 ShaderFile sfile(file);
2542 ShaderTable::const_iterator i = _load_table.find(sfile);
2543 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
2545 if (i->second->check_modified()) {
2547 <<
"Shader " << file <<
" was modified on disk, reloading.\n";
2550 <<
"Shader " << file <<
" was found in shader cache.\n";
2556 if (!shader->read(sfile)) {
2560 _load_table[sfile] = shader;
2571 load(ShaderLanguage lang, const
Filename &vertex,
2574 ShaderFile sfile(vertex, fragment, geometry, tess_control, tess_evaluation);
2575 ShaderTable::const_iterator i = _load_table.find(sfile);
2576 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
2578 if (i->second->check_modified()) {
2580 <<
"Shader was modified on disk, reloading.\n";
2583 <<
"Shader was found in shader cache.\n";
2589 if (!shader->read(sfile)) {
2593 _load_table[sfile] = shader;
2603 load_compute(ShaderLanguage lang, const
Filename &fn) {
2604 if (lang != SL_GLSL) {
2606 <<
"Only GLSL compute shaders are currently supported.\n";
2611 sfile._separate =
true;
2612 sfile._compute = fn;
2614 ShaderTable::const_iterator i = _load_table.find(sfile);
2615 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
2617 if (i->second->check_modified()) {
2619 <<
"Compute shader " << fn <<
" was modified on disk, reloading.\n";
2622 <<
"Compute shader " << fn <<
" was found in shader cache.\n";
2628 if (!shader->read(sfile)) {
2632 _load_table[sfile] = shader;
2642 make(const
string &body, ShaderLanguage lang) {
2643 if (lang == SL_GLSL) {
2645 <<
"GLSL shaders must have separate shader bodies!\n";
2648 }
else if (lang == SL_none) {
2649 shader_cat.warning()
2650 <<
"Shader::make() now requires an explicit shader language. Assuming Cg.\n";
2654 if (lang == SL_Cg) {
2655 shader_cat.error() <<
"Support for Cg shaders is not enabled.\n";
2660 ShaderFile sbody(body);
2662 if (cache_generated_shaders) {
2663 ShaderTable::const_iterator i = _make_table.find(sbody);
2664 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
2670 shader->_filename = ShaderFile("created-shader");
2671 shader->_text = sbody;
2674 if (lang == SL_Cg) {
2675 shader->cg_get_profile_from_header(_default_caps);
2677 if (!shader->cg_analyze_shader(_default_caps)) {
2679 <<
"Shader encountered an error.\n";
2685 if (cache_generated_shaders) {
2686 _make_table[sbody] = shader;
2689 if (dump_generated_shaders) {
2691 int index = _shaders_generated ++;
2692 fns <<
"genshader" << index;
2693 string fn = fns.str();
2694 shader_cat.warning() <<
"Dumping shader: " << fn <<
"\n";
2697 s.open(fn.c_str(), ios::out | ios::trunc);
2710 make(ShaderLanguage lang, const
string &vertex, const
string &fragment,
2711 const
string &geometry, const
string &tess_control,
2712 const
string &tess_evaluation) {
2714 if (lang == SL_Cg) {
2715 shader_cat.error() <<
"Support for Cg shaders is not enabled.\n";
2719 if (lang == SL_none) {
2721 <<
"Shader::make() requires an explicit shader language.\n";
2725 ShaderFile sbody(vertex, fragment, geometry, tess_control, tess_evaluation);
2727 if (cache_generated_shaders) {
2728 ShaderTable::const_iterator i = _make_table.find(sbody);
2729 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
2735 shader->_filename = ShaderFile("created-shader");
2736 shader->_text = sbody;
2739 if (lang == SL_Cg) {
2740 if (!shader->cg_analyze_shader(_default_caps)) {
2742 <<
"Shader encountered an error.\n";
2748 if (cache_generated_shaders) {
2749 _make_table[sbody] = shader;
2761 make_compute(ShaderLanguage lang, const
string &body) {
2762 if (lang != SL_GLSL) {
2764 <<
"Only GLSL compute shaders are currently supported.\n";
2769 sbody._separate =
true;
2770 sbody._compute = body;
2773 if (cache_generated_shaders) {
2774 ShaderTable::const_iterator i = _make_table.find(sbody);
2775 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
2781 shader->_filename = ShaderFile("created-shader");
2782 shader->_text = sbody;
2784 if (cache_generated_shaders) {
2785 _make_table[sbody] = shader;
2811 nassertv(!_text._separate);
2812 int len = _text._shared.size();
2815 while ((tail < len) && (_text._shared[tail] !=
'\n')) {
2824 while ((head < tail)&&(isspace(_text._shared[head]))) head++;
2825 while ((tail > head)&&(isspace(_text._shared[tail-1]))) tail--;
2827 result = _text._shared.substr(head, tail-head);
2840 nassertv(!_text._separate);
2844 while (_parse < (
int)(_text._shared.size())) {
2851 result = _text._shared.substr(start, _parse - start);
2853 result = _text._shared.substr(start, last - start);
2865 nassertv(!_text._separate);
2866 result = _text._shared.substr(_parse, _text._shared.size() - _parse);
2877 return (
int)_text._shared.size() == _parse;
2906 Contexts::const_iterator ci;
2907 ci = _contexts.find(prepared_objects);
2908 if (ci != _contexts.end()) {
2923 Contexts::iterator ci;
2924 ci = _contexts.find(prepared_objects);
2925 if (ci != _contexts.end()) {
2930 _contexts.erase(ci);
2958 Contexts::const_iterator ci;
2959 ci = _contexts.find(prepared_objects);
2960 if (ci != _contexts.end()) {
2961 return (*ci).second;
2965 _contexts[prepared_objects] = tc;
2981 Contexts::iterator ci;
2982 ci = _contexts.find(prepared_objects);
2983 if (ci != _contexts.end()) {
2984 _contexts.erase(ci);
3006 int num_freed = (int)_contexts.size();
3008 Contexts::const_iterator ci;
3009 for (ci = temp.begin(); ci != temp.end(); ++ci) {
3029 void Shader::ShaderCaps::
3031 _supports_glsl =
false;
3034 _active_vprofile = CG_PROFILE_UNKNOWN;
3035 _active_fprofile = CG_PROFILE_UNKNOWN;
3036 _active_gprofile = CG_PROFILE_UNKNOWN;
3037 _active_fprofile = CG_PROFILE_UNKNOWN;
3038 _ultimate_vprofile = CG_PROFILE_UNKNOWN;
3039 _ultimate_fprofile = CG_PROFILE_UNKNOWN;
3040 _ultimate_gprofile = CG_PROFILE_UNKNOWN;
3041 _ultimate_fprofile = CG_PROFILE_UNKNOWN;
3084 parse_params(params, scan, manager);
3085 attrib->fillin(scan, manager);
3098 _language = (ShaderLanguage) scan.
get_uint8();
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 is_prepared(PreparedGraphicsObjects *prepared_objects) const
Returns true if the shader has already been prepared or enqueued for preparation on the indicated GSG...
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.
Filename get_filename(const ShaderType &type=ST_none) const
Return the Shader's filename for the given shader type.
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 matches(const string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
string get_dirname() const
Returns the directory part of the filename.
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 write_datagram(Datagram &dg) const
Writes the contents of this object to the datagram for shipping out to a Bam file.
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.
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 parse_rest(string &result)
Returns the rest of the text from the current parse location.
const string & get_text(const ShaderType &type=ST_none) const
Return the Shader's text for the given shader type.
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.
~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...
ostream & error(bool prefix=true) const
A shorthand way to write out(NS_error).
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 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...
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.
bool is_shader_queued(const Shader *shader) const
Returns true if the shader has been queued on this GSG, false otherwise.
This class can be used to test for string matches against standard Unix-shell filename globbing conve...
bool cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi)
Make sure the provided parameter has a floating point type.