32using std::ostringstream;
39int Shader::_shaders_generated;
42CGcontext Shader::_cg_context = 0;
59 string dstr =
"unknown ";
60 if (p._direction == SAD_in) {
62 }
else if (p._direction == SAD_out) {
64 }
else if (p._direction == SAD_inout) {
68 string tstr =
"invalid ";
70 case SAT_scalar: tstr =
"scalar ";
break;
71 case SAT_vec1: tstr =
"vec1 ";
break;
72 case SAT_vec2: tstr =
"vec2 ";
break;
73 case SAT_vec3: tstr =
"vec3 ";
break;
74 case SAT_vec4: tstr =
"vec4 ";
break;
75 case SAT_mat1x1: tstr =
"mat1x1 ";
break;
76 case SAT_mat1x2: tstr =
"mat1x2 ";
break;
77 case SAT_mat1x3: tstr =
"mat1x3 ";
break;
78 case SAT_mat1x4: tstr =
"mat1x4 ";
break;
79 case SAT_mat2x1: tstr =
"mat2x1 ";
break;
80 case SAT_mat2x2: tstr =
"mat2x2 ";
break;
81 case SAT_mat2x3: tstr =
"mat2x3 ";
break;
82 case SAT_mat2x4: tstr =
"mat2x4 ";
break;
83 case SAT_mat3x1: tstr =
"mat3x1 ";
break;
84 case SAT_mat3x2: tstr =
"mat3x2 ";
break;
85 case SAT_mat3x3: tstr =
"mat3x3 ";
break;
86 case SAT_mat3x4: tstr =
"mat3x4 ";
break;
87 case SAT_mat4x1: tstr =
"mat4x1 ";
break;
88 case SAT_mat4x2: tstr =
"mat4x2 ";
break;
89 case SAT_mat4x3: tstr =
"mat4x3 ";
break;
90 case SAT_mat4x4: tstr =
"mat4x4 ";
break;
91 case SAT_sampler1d: tstr =
"sampler1D ";
break;
92 case SAT_sampler2d: tstr =
"sampler2D ";
break;
93 case SAT_sampler3d: tstr =
"sampler3D ";
break;
94 case SAT_sampler2d_array: tstr =
"sampler2DARRAY ";
break;
95 case SAT_sampler_cube: tstr =
"samplerCUBE ";
break;
96 case SAT_sampler_buffer: tstr =
"samplerBUF ";
break;
97 case SAT_sampler_cube_array:tstr =
"samplerCUBEARRAY ";
break;
98 case SAT_sampler1d_array: tstr =
"sampler1DARRAY ";
break;
99 default: tstr =
"unknown ";
break;
102 string cstr =
"invalid";
104 case SAC_scalar: cstr =
"scalar ";
break;
105 case SAC_vector: cstr =
"vector ";
break;
106 case SAC_matrix: cstr =
"matrix ";
break;
107 case SAC_sampler: cstr =
"sampler ";
break;
108 case SAC_array: cstr =
"array ";
break;
109 default: cstr =
"unknown ";
break;
113 p._cat->
error() << fn <<
": " << vstr << dstr << tstr <<
114 p._id._name <<
": " << msg <<
"\n";
126 if ((
int)words.size() != len) {
140 if (p._direction != SAD_in) {
184 case SAT_scalar: nfloat = 1;
break;
185 case SAT_vec2: nfloat = 2;
break;
186 case SAT_vec3: nfloat = 3;
break;
187 case SAT_vec4: nfloat = 4;
break;
188 case SAT_mat3x3: nfloat = 9;
break;
189 case SAT_mat4x4: nfloat = 16;
break;
190 default: nfloat = 0;
break;
192 if ((nfloat < lo)||(nfloat > hi)) {
193 string msg =
"wrong type for parameter:";
204cp_errchk_parameter_ptr(ShaderArgInfo &p) {
206 case SAC_scalar:
return true;
207 case SAC_vector:
return true;
208 case SAC_matrix:
return true;
210 switch (p._subclass) {
211 case SAC_scalar:
return true;
212 case SAC_vector:
return true;
213 case SAC_matrix:
return true;
215 string msg =
"unsupported array subclass.";
220 string msg =
"unsupported class.";
232 if (p._type != SAT_sampler1d &&
233 p._type != SAT_sampler2d &&
234 p._type != SAT_sampler3d &&
235 p._type != SAT_sampler2d_array &&
236 p._type != SAT_sampler_cube &&
237 p._type != SAT_sampler_buffer &&
238 p._type != SAT_sampler_cube_array &&
239 p._type != SAT_sampler1d_array) {
251 if (words[next] !=
"") {
263 if ((words[next] !=
"to")&&(words[next] !=
"rel")) {
277 const string &nword = words[next];
278 if ((nword ==
"")||(nword ==
"to")||(nword ==
"rel")) {
291 vector_string &pieces,
int &next,
295 if (pieces[next] ==
"of") next++;
298 ShaderMatInput from_single;
299 ShaderMatInput from_double;
300 ShaderMatInput to_single;
301 ShaderMatInput to_double;
306 }
else if (word1 ==
"world") {
307 from_single = SMO_world_to_view;
308 from_double = SMO_INVALID;
309 to_single = SMO_view_to_world;
310 to_double = SMO_INVALID;
311 }
else if (word1 ==
"model") {
312 from_single = SMO_model_to_view;
313 from_double = SMO_view_x_to_view;
314 to_single = SMO_view_to_model;
315 to_double = SMO_view_to_view_x;
316 }
else if (word1 ==
"clip") {
317 from_single = SMO_clip_to_view;
318 from_double = SMO_clip_x_to_view;
319 to_single = SMO_view_to_clip;
320 to_double = SMO_view_to_clip_x;
321 }
else if (word1 ==
"view") {
322 from_single = SMO_identity;
323 from_double = SMO_view_x_to_view;
324 to_single = SMO_identity;
325 to_double = SMO_view_to_view_x;
326 }
else if (word1 ==
"apiview") {
327 from_single = SMO_apiview_to_view;
328 from_double = SMO_apiview_x_to_view;
329 to_single = SMO_view_to_apiview;
330 to_double = SMO_view_to_apiview_x;
331 }
else if (word1 ==
"apiclip") {
332 from_single = SMO_apiclip_to_view;
333 from_double = SMO_apiclip_x_to_view;
334 to_single = SMO_view_to_apiclip;
335 to_double = SMO_view_to_apiclip_x;
337 from_single = SMO_view_x_to_view;
338 from_double = SMO_view_x_to_view;
339 to_single = SMO_view_to_view_x;
340 to_double = SMO_view_to_view_x;
346 bind._part[0] = from_single;
347 bind._arg[0] =
nullptr;
349 if (from_double == SMO_INVALID) {
353 bind._part[0] = from_double;
354 bind._arg[0] = InternalName::make(word2);
358 bind._part[1] = to_single;
359 bind._arg[1] =
nullptr;
361 if (to_double == SMO_INVALID) {
365 bind._part[1] = to_double;
366 bind._arg[1] = InternalName::make(word2);
379 int dep = SSD_general;
381 if (inp == SMO_INVALID) {
384 if (inp == SMO_attr_material || inp == SMO_attr_material2) {
385 dep |= SSD_material | SSD_frame;
387 if (inp == SMO_attr_color) {
390 if (inp == SMO_attr_colorscale) {
391 dep |= SSD_colorscale;
393 if (inp == SMO_attr_fog || inp == SMO_attr_fogcolor) {
394 dep |= SSD_fog | SSD_frame;
396 if ((inp == SMO_model_to_view) ||
397 (inp == SMO_view_to_model) ||
398 (inp == SMO_model_to_apiview) ||
399 (inp == SMO_apiview_to_model)) {
400 dep |= SSD_transform;
402 if ((inp == SMO_view_to_world) ||
403 (inp == SMO_world_to_view) ||
404 (inp == SMO_view_x_to_view) ||
405 (inp == SMO_view_to_view_x) ||
406 (inp == SMO_apiview_x_to_view) ||
407 (inp == SMO_view_to_apiview_x) ||
408 (inp == SMO_clip_x_to_view) ||
409 (inp == SMO_view_to_clip_x) ||
410 (inp == SMO_apiclip_x_to_view) ||
411 (inp == SMO_view_to_apiclip_x) ||
412 (inp == SMO_dlight_x) ||
413 (inp == SMO_plight_x) ||
414 (inp == SMO_slight_x)) {
415 dep |= SSD_view_transform;
417 if ((inp == SMO_texpad_x) ||
418 (inp == SMO_texpix_x) ||
419 (inp == SMO_alight_x) ||
420 (inp == SMO_dlight_x) ||
421 (inp == SMO_plight_x) ||
422 (inp == SMO_slight_x) ||
423 (inp == SMO_satten_x) ||
424 (inp == SMO_mat_constant_x) ||
425 (inp == SMO_vec_constant_x) ||
426 (inp == SMO_vec_constant_x_attrib) ||
427 (inp == SMO_view_x_to_view) ||
428 (inp == SMO_view_to_view_x) ||
429 (inp == SMO_apiview_x_to_view) ||
430 (inp == SMO_view_to_apiview_x) ||
431 (inp == SMO_clip_x_to_view) ||
432 (inp == SMO_view_to_clip_x) ||
433 (inp == SMO_apiclip_x_to_view) ||
434 (inp == SMO_view_to_apiclip_x)) {
435 dep |= SSD_shaderinputs;
437 if ((inp == SMO_texpad_x) ||
438 (inp == SMO_texpix_x) ||
439 (inp == SMO_alight_x) ||
440 (inp == SMO_dlight_x) ||
441 (inp == SMO_plight_x) ||
442 (inp == SMO_slight_x) ||
443 (inp == SMO_satten_x) ||
444 (inp == SMO_vec_constant_x_attrib) ||
445 (inp == SMO_view_x_to_view) ||
446 (inp == SMO_view_to_view_x) ||
447 (inp == SMO_apiview_x_to_view) ||
448 (inp == SMO_view_to_apiview_x) ||
449 (inp == SMO_clip_x_to_view) ||
450 (inp == SMO_view_to_clip_x) ||
451 (inp == SMO_apiclip_x_to_view) ||
452 (inp == SMO_view_to_apiclip_x)) {
458 if ((inp == SMO_light_ambient) ||
459 (inp == SMO_light_source_i_attrib) ||
460 (inp == SMO_light_source_i_packed)) {
461 dep |= SSD_light | SSD_frame;
462 if (inp == SMO_light_source_i_attrib ||
463 inp == SMO_light_source_i_packed) {
464 dep |= SSD_view_transform;
467 if ((inp == SMO_light_product_i_ambient) ||
468 (inp == SMO_light_product_i_diffuse) ||
469 (inp == SMO_light_product_i_specular)) {
470 dep |= (SSD_light | SSD_material);
472 if ((inp == SMO_clipplane_x) ||
473 (inp == SMO_apiview_clipplane_i)) {
474 dep |= SSD_clip_planes;
476 if (inp == SMO_texmat_i || inp == SMO_inv_texmat_i || inp == SMO_texscale_i) {
477 dep |= SSD_tex_matrix;
479 if ((inp == SMO_window_size) ||
480 (inp == SMO_pixel_size) ||
481 (inp == SMO_frame_number) ||
482 (inp == SMO_frame_time) ||
483 (inp == SMO_frame_delta)) {
486 if ((inp == SMO_clip_to_view) ||
487 (inp == SMO_view_to_clip) ||
488 (inp == SMO_apiclip_to_view) ||
489 (inp == SMO_view_to_apiclip) ||
490 (inp == SMO_apiview_to_apiclip) ||
491 (inp == SMO_apiclip_to_apiview)) {
492 dep |= SSD_projection;
494 if (inp == SMO_tex_is_alpha_i || inp == SMO_texcolor_i) {
495 dep |= SSD_texture | SSD_frame;
497 if (inp == SMO_texconst_i) {
500 if (inp == SMO_attr_pointparams) {
501 dep |= SSD_render_mode | SSD_transform | SSD_frame;
518 if (spec._func == SMF_first) {
519 spec._part[1] = SMO_INVALID;
520 spec._arg[1] =
nullptr;
522 if (spec._func == SMF_compose) {
523 if (spec._part[1] == SMO_identity) {
524 spec._func = SMF_first;
527 if (spec._func == SMF_compose) {
528 if (spec._part[0] == SMO_identity) {
529 spec._func = SMF_first;
530 spec._part[0] = spec._part[1];
531 spec._arg[0] = spec._arg[1];
536 if (spec._part[0] == SMO_model_to_view &&
537 spec._part[1] == SMO_view_to_apiclip) {
538 spec._part[0] = SMO_model_to_apiview;
539 spec._part[1] = SMO_apiview_to_apiclip;
541 }
else if (spec._part[0] == SMO_apiclip_to_view &&
542 spec._part[1] == SMO_view_to_model) {
543 spec._part[0] = SMO_apiclip_to_apiview;
544 spec._part[1] = SMO_apiview_to_model;
546 }
else if (spec._part[0] == SMO_apiview_to_view &&
547 spec._part[1] == SMO_view_to_apiclip) {
548 spec._func = SMF_first;
549 spec._part[0] = SMO_apiview_to_apiclip;
550 spec._part[1] = SMO_identity;
552 }
else if (spec._part[0] == SMO_apiclip_to_view &&
553 spec._part[1] == SMO_view_to_apiview) {
554 spec._func = SMF_first;
555 spec._part[0] = SMO_apiclip_to_apiview;
556 spec._part[1] = SMO_identity;
558 }
else if (spec._part[0] == SMO_apiview_to_view &&
559 spec._part[1] == SMO_view_to_model) {
560 spec._func = SMF_first;
561 spec._part[0] = SMO_apiview_to_model;
562 spec._part[1] = SMO_identity;
564 }
else if (spec._part[0] == SMO_model_to_view &&
565 spec._part[1] == SMO_view_to_apiview) {
566 spec._func = SMF_first;
567 spec._part[0] = SMO_model_to_apiview;
568 spec._part[1] = SMO_identity;
583cg_recurse_parameters(CGparameter parameter,
const ShaderType &type,
586 if (parameter == 0) {
591 if (cgIsParameterReferenced(parameter)) {
592 int arg_dim[] = {1,0,0};
593 ShaderArgDir arg_dir = cg_parameter_dir(parameter);
594 ShaderArgType arg_type = cg_parameter_type(parameter);
595 ShaderArgClass arg_class = cg_parameter_class(parameter);
596 ShaderArgClass arg_subclass = arg_class;
598 CGenum vbl = cgGetParameterVariability(parameter);
599 CGtype base_type = cgGetParameterBaseType(parameter);
601 if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) {
602 switch (cgGetParameterType(parameter)) {
604 cg_recurse_parameters(
605 cgGetFirstStructParameter(parameter), type, success);
609 arg_type = cg_parameter_type(cgGetArrayParameter(parameter, 0));
610 arg_subclass = cg_parameter_class(cgGetArrayParameter(parameter, 0));
612 arg_dim[0] = cgGetArraySize(parameter, 0);
616 arg_dim[1] = cgGetParameterRows(parameter);
617 arg_dim[2] = cgGetParameterColumns(parameter);
620 p._id._name = cgGetParameterName(parameter);
623 p._class = arg_class;
624 p._subclass = arg_subclass;
626 p._direction = arg_dir;
627 p._varying = (vbl == CG_VARYING);
628 p._cat = shader_cat.get_safe_ptr();
638 p._numeric_type = SPT_uint;
644 p._numeric_type = SPT_int;
647 p._numeric_type = SPT_float;
656 }
else if (shader_cat.is_debug()) {
658 <<
"Parameter " << cgGetParameterName(parameter)
659 <<
" is unreferenced within shader " <<
get_filename(type) <<
"\n";
661 }
while((parameter = cgGetNextParameter(parameter))!= 0);
675 if (p._id._name.size() == 0)
return true;
676 if (p._id._name[0] ==
'$')
return true;
679 size_t loc = p._id._name.find_last_of(
'.');
681 string basename (p._id._name);
682 string struct_name (
"");
684 if (loc < string::npos) {
685 basename = p._id._name.substr(loc + 1);
686 struct_name = p._id._name.substr(0,loc+1);
690 vector_string pieces;
693 if (basename.size() >= 2 && basename.substr(0, 2) ==
"__") {
698 if (pieces[0] ==
"vtx") {
706 bind._append_uv = -1;
707 bind._numeric_type = p._numeric_type;
709 if (pieces.size() == 2) {
710 if (pieces[1] ==
"position") {
711 bind._name = InternalName::get_vertex();
712 bind._append_uv = -1;
713 _var_spec.push_back(bind);
716 if (pieces[1].substr(0, 8) ==
"texcoord") {
717 bind._name = InternalName::get_texcoord();
718 if (pieces[1].size() > 8) {
719 bind._append_uv = atoi(pieces[1].c_str() + 8);
721 _var_spec.push_back(bind);
724 if (pieces[1].substr(0, 7) ==
"tangent") {
725 bind._name = InternalName::get_tangent();
726 if (pieces[1].size() > 7) {
727 bind._append_uv = atoi(pieces[1].c_str() + 7);
729 _var_spec.push_back(bind);
732 if (pieces[1].substr(0, 8) ==
"binormal") {
733 bind._name = InternalName::get_binormal();
734 if (pieces[1].size() > 8) {
735 bind._append_uv = atoi(pieces[1].c_str() + 8);
737 _var_spec.push_back(bind);
740 }
else if (pieces.size() == 3) {
741 if (pieces[1] ==
"transform") {
742 if (pieces[2] ==
"blend") {
743 bind._name = InternalName::get_transform_blend();
744 _var_spec.push_back(bind);
747 if (pieces[2] ==
"index") {
748 bind._name = InternalName::get_transform_index();
749 _var_spec.push_back(bind);
752 if (pieces[2] ==
"weight") {
753 bind._name = InternalName::get_transform_weight();
754 _var_spec.push_back(bind);
760 bind._name = InternalName::get_root();
761 for (
size_t i = 1; i < pieces.size(); ++i) {
762 bind._name = bind._name->append(pieces[i]);
764 _var_spec.push_back(bind);
768 if (pieces[0] ==
"mat" && pieces[1] ==
"shadow") {
777 bind._piece = SMP_whole;
778 bind._func = SMF_compose;
779 bind._part[1] = SMO_light_source_i_attrib;
780 bind._arg[1] = InternalName::make(
"shadowViewMatrix");
781 bind._part[0] = SMO_view_to_apiview;
782 bind._arg[0] =
nullptr;
783 bind._index = atoi(pieces[2].c_str());
786 _mat_spec.push_back(bind);
787 _mat_deps |= bind._dep[0] | bind._dep[1];
794 if (pieces[0] ==
"mstrans") {
796 pieces.push_back(
"to");
797 pieces.push_back(
"model");
799 if (pieces[0] ==
"wstrans") {
801 pieces.push_back(
"to");
802 pieces.push_back(
"world");
804 if (pieces[0] ==
"vstrans") {
806 pieces.push_back(
"to");
807 pieces.push_back(
"view");
809 if (pieces[0] ==
"cstrans") {
811 pieces.push_back(
"to");
812 pieces.push_back(
"clip");
814 if (pieces[0] ==
"mspos") {
816 pieces.push_back(
"to");
817 pieces.push_back(
"model");
819 if (pieces[0] ==
"wspos") {
821 pieces.push_back(
"to");
822 pieces.push_back(
"world");
824 if (pieces[0] ==
"vspos") {
826 pieces.push_back(
"to");
827 pieces.push_back(
"view");
829 if (pieces[0] ==
"cspos") {
831 pieces.push_back(
"to");
832 pieces.push_back(
"clip");
837 if ((pieces[0] ==
"mat")||(pieces[0] ==
"inv")||
838 (pieces[0] ==
"tps")||(pieces[0] ==
"itp")) {
842 string trans = pieces[0];
843 string matrix = pieces[1];
845 if (matrix ==
"modelview") {
846 tokenize(
"trans_model_to_apiview", pieces,
"_");
847 }
else if (matrix ==
"projection") {
848 tokenize(
"trans_apiview_to_apiclip", pieces,
"_");
849 }
else if (matrix ==
"modelproj") {
850 tokenize(
"trans_model_to_apiclip", pieces,
"_");
857 }
else if (trans==
"inv") {
858 string t = pieces[1];
859 pieces[1] = pieces[3];
861 }
else if (trans==
"tps") {
863 }
else if (trans==
"itp") {
864 string t = pieces[1];
865 pieces[1] = pieces[3];
873 if ((pieces[0]==
"trans")||
874 (pieces[0]==
"tpose")||
875 (pieces[0]==
"row0")||
876 (pieces[0]==
"row1")||
877 (pieces[0]==
"row2")||
878 (pieces[0]==
"row3")||
879 (pieces[0]==
"col0")||
880 (pieces[0]==
"col1")||
881 (pieces[0]==
"col2")||
882 (pieces[0]==
"col3")) {
890 bind._piece = SMP_whole;
891 bind._func = SMF_compose;
892 bind._part[1] = SMO_light_source_i_attrib;
893 bind._arg[1] = InternalName::make(
"shadowViewMatrix");
894 bind._part[0] = SMO_view_to_apiview;
895 bind._arg[0] =
nullptr;
896 bind._index = atoi(pieces[2].c_str());
899 pieces.push_back(
"");
902 if (pieces[0]==
"trans") bind._piece = SMP_whole;
903 else if (pieces[0]==
"tpose") bind._piece = SMP_transpose;
904 else if (pieces[0]==
"row0") bind._piece = SMP_row0;
905 else if (pieces[0]==
"row1") bind._piece = SMP_row1;
906 else if (pieces[0]==
"row2") bind._piece = SMP_row2;
907 else if (pieces[0]==
"row3") bind._piece = SMP_row3;
908 else if (pieces[0]==
"col0") bind._piece = SMP_col0;
909 else if (pieces[0]==
"col1") bind._piece = SMP_col1;
910 else if (pieces[0]==
"col2") bind._piece = SMP_col2;
911 else if (pieces[0]==
"col3") bind._piece = SMP_col3;
912 if ((bind._piece == SMP_whole)||(bind._piece == SMP_transpose)) {
913 if (p._type == SAT_mat3x3) {
916 if (bind._piece == SMP_transpose) {
917 bind._piece = SMP_transpose3x3;
919 bind._piece = SMP_upper3x3;
941 _mat_spec.push_back(bind);
942 _mat_deps |= bind._dep[0] | bind._dep[1];
948 if (pieces[0] ==
"attr") {
955 if (pieces[1] ==
"material") {
960 bind._piece = SMP_transpose;
961 bind._func = SMF_first;
962 bind._part[0] = SMO_attr_material;
963 bind._arg[0] =
nullptr;
964 bind._part[1] = SMO_identity;
965 bind._arg[1] =
nullptr;
966 }
else if (pieces[1] ==
"color") {
971 bind._piece = SMP_row3;
972 bind._func = SMF_first;
973 bind._part[0] = SMO_attr_color;
974 bind._arg[0] =
nullptr;
975 bind._part[1] = SMO_identity;
976 bind._arg[1] =
nullptr;
977 }
else if (pieces[1] ==
"colorscale") {
982 bind._piece = SMP_row3;
983 bind._func = SMF_first;
984 bind._part[0] = SMO_attr_colorscale;
985 bind._arg[0] =
nullptr;
986 bind._part[1] = SMO_identity;
987 bind._arg[1] =
nullptr;
988 }
else if (pieces[1] ==
"fog") {
993 bind._piece = SMP_row3;
994 bind._func = SMF_first;
995 bind._part[0] = SMO_attr_fog;
996 bind._arg[0] =
nullptr;
997 bind._part[1] = SMO_identity;
998 bind._arg[1] =
nullptr;
999 }
else if (pieces[1] ==
"fogcolor") {
1004 bind._piece = SMP_row3;
1005 bind._func = SMF_first;
1006 bind._part[0] = SMO_attr_fogcolor;
1007 bind._arg[0] =
nullptr;
1008 bind._part[1] = SMO_identity;
1009 bind._arg[1] =
nullptr;
1010 }
else if (pieces[1] ==
"ambient") {
1015 bind._piece = SMP_row3;
1016 bind._func = SMF_first;
1017 bind._part[0] = SMO_light_ambient;
1018 bind._arg[0] =
nullptr;
1019 bind._part[1] = SMO_identity;
1020 bind._arg[1] =
nullptr;
1021 }
else if (pieces[1].compare(0, 5,
"light") == 0) {
1026 bind._piece = SMP_transpose;
1027 bind._func = SMF_first;
1028 bind._part[0] = SMO_light_source_i_packed;
1029 bind._arg[0] =
nullptr;
1030 bind._part[1] = SMO_identity;
1031 bind._arg[1] =
nullptr;
1032 bind._index = atoi(pieces[1].c_str() + 5);
1033 }
else if (pieces[1].compare(0, 5,
"lspec") == 0) {
1038 bind._piece = SMP_row3;
1039 bind._func = SMF_first;
1040 bind._part[0] = SMO_light_source_i_attrib;
1041 bind._arg[0] = InternalName::make(
"specular");
1042 bind._part[1] = SMO_identity;
1043 bind._arg[1] =
nullptr;
1044 bind._index = atoi(pieces[1].c_str() + 5);
1045 }
else if (pieces[1] ==
"pointparams") {
1050 bind._piece = SMP_row3;
1051 bind._func = SMF_first;
1052 bind._part[0] = SMO_attr_pointparams;
1053 bind._arg[0] =
nullptr;
1054 bind._part[1] = SMO_identity;
1055 bind._arg[1] =
nullptr;
1062 _mat_spec.push_back(bind);
1063 _mat_deps |= bind._dep[0] | bind._dep[1];
1067 if (pieces[0] ==
"color") {
1076 _mat_spec.push_back(bind);
1077 _mat_deps |= bind._dep[0] | bind._dep[1];
1083 if (pieces[0] ==
"alight") {
1092 bind._piece = SMP_row3;
1093 bind._func = SMF_first;
1094 bind._part[0] = SMO_alight_x;
1095 bind._arg[0] = InternalName::make(pieces[1]);
1096 bind._part[1] = SMO_identity;
1097 bind._arg[1] =
nullptr;
1100 _mat_spec.push_back(bind);
1101 _mat_deps |= bind._dep[0] | bind._dep[1];
1105 if (pieces[0] ==
"satten") {
1114 bind._piece = SMP_row3;
1115 bind._func = SMF_first;
1116 bind._part[0] = SMO_satten_x;
1117 bind._arg[0] = InternalName::make(pieces[1]);
1118 bind._part[1] = SMO_identity;
1119 bind._arg[1] =
nullptr;
1122 _mat_spec.push_back(bind);
1123 _mat_deps |= bind._dep[0] | bind._dep[1];
1127 if ((pieces[0]==
"dlight")||(pieces[0]==
"plight")||(pieces[0]==
"slight")) {
1135 bind._piece = SMP_transpose;
1137 pieces.push_back(
"");
1138 if (pieces[next] ==
"") {
1142 if (pieces[0] ==
"dlight") {
1143 bind._func = SMF_transform_dlight;
1144 bind._part[0] = SMO_dlight_x;
1145 }
else if (pieces[0] ==
"plight") {
1146 bind._func = SMF_transform_plight;
1147 bind._part[0] = SMO_plight_x;
1148 }
else if (pieces[0] ==
"slight") {
1149 bind._func = SMF_transform_slight;
1150 bind._part[0] = SMO_slight_x;
1152 bind._arg[0] = InternalName::make(pieces[next]);
1164 _mat_spec.push_back(bind);
1165 _mat_deps |= bind._dep[0] | bind._dep[1];
1169 if (pieces[0] ==
"texmat") {
1178 bind._piece = SMP_whole;
1179 bind._func = SMF_first;
1180 bind._part[0] = SMO_texmat_i;
1181 bind._arg[0] =
nullptr;
1182 bind._part[1] = SMO_identity;
1183 bind._arg[1] =
nullptr;
1184 bind._index = atoi(pieces[1].c_str());
1187 _mat_spec.push_back(bind);
1188 _mat_deps |= bind._dep[0] | bind._dep[1];
1192 if (pieces[0] ==
"texscale") {
1201 bind._piece = SMP_row3;
1202 bind._func = SMF_first;
1203 bind._part[0] = SMO_texscale_i;
1204 bind._arg[0] =
nullptr;
1205 bind._part[1] = SMO_identity;
1206 bind._arg[1] =
nullptr;
1207 bind._index = atoi(pieces[1].c_str());
1210 _mat_spec.push_back(bind);
1211 _mat_deps |= bind._dep[0] | bind._dep[1];
1215 if (pieces[0] ==
"texcolor") {
1224 bind._piece = SMP_row3;
1225 bind._func = SMF_first;
1226 bind._part[0] = SMO_texcolor_i;
1227 bind._arg[0] =
nullptr;
1228 bind._part[1] = SMO_identity;
1229 bind._arg[1] =
nullptr;
1230 bind._index = atoi(pieces[1].c_str());
1233 _mat_spec.push_back(bind);
1234 _mat_deps |= bind._dep[0] | bind._dep[1];
1238 if (pieces[0] ==
"texconst") {
1247 bind._piece = SMP_row3;
1248 bind._func = SMF_first;
1249 bind._part[0] = SMO_texconst_i;
1250 bind._arg[0] =
nullptr;
1251 bind._part[1] = SMO_identity;
1252 bind._arg[1] =
nullptr;
1253 bind._index = atoi(pieces[1].c_str());
1256 _mat_spec.push_back(bind);
1257 _mat_deps |= bind._dep[0] | bind._dep[1];
1261 if (pieces[0] ==
"plane") {
1270 bind._piece = SMP_row3;
1271 bind._func = SMF_first;
1272 bind._part[0] = SMO_plane_x;
1273 bind._arg[0] = InternalName::make(pieces[1]);
1274 bind._part[1] = SMO_identity;
1275 bind._arg[1] =
nullptr;
1278 _mat_spec.push_back(bind);
1279 _mat_deps |= bind._dep[0] | bind._dep[1];
1283 if (pieces[0] ==
"clipplane") {
1292 bind._piece = SMP_row3;
1293 bind._func = SMF_first;
1294 bind._part[0] = SMO_clipplane_x;
1295 bind._arg[0] = InternalName::make(pieces[1]);
1296 bind._part[1] = SMO_identity;
1297 bind._arg[1] =
nullptr;
1300 _mat_spec.push_back(bind);
1301 _mat_deps |= bind._dep[0] | bind._dep[1];
1307 if (pieces[0] ==
"sys") {
1315 bind._piece = SMP_row3;
1316 bind._func = SMF_first;
1317 bind._part[1] = SMO_identity;
1318 bind._arg[1] =
nullptr;
1319 if (pieces[1] ==
"pixelsize") {
1323 bind._part[0] = SMO_pixel_size;
1324 bind._arg[0] =
nullptr;
1326 }
else if (pieces[1] ==
"windowsize") {
1330 bind._part[0] = SMO_window_size;
1331 bind._arg[0] =
nullptr;
1333 }
else if (pieces[1] ==
"time") {
1337 bind._piece = SMP_row3x1;
1338 bind._part[0] = SMO_frame_time;
1339 bind._arg[0] =
nullptr;
1347 _mat_spec.push_back(bind);
1348 _mat_deps |= bind._dep[0] | bind._dep[1];
1354 if (pieces[0] ==
"tex") {
1359 if ((pieces.size() != 2)&&(pieces.size() != 3)) {
1365 bind._name =
nullptr;
1366 bind._stage = atoi(pieces[1].c_str());
1367 bind._part = STO_stage_i;
1369 case SAT_sampler1d: bind._desired_type = Texture::TT_1d_texture;
break;
1370 case SAT_sampler2d: bind._desired_type = Texture::TT_2d_texture;
break;
1371 case SAT_sampler3d: bind._desired_type = Texture::TT_3d_texture;
break;
1372 case SAT_sampler2d_array:bind._desired_type = Texture::TT_2d_texture_array;
break;
1373 case SAT_sampler_cube: bind._desired_type = Texture::TT_cube_map;
break;
1374 case SAT_sampler_buffer: bind._desired_type = Texture::TT_buffer_texture;
break;
1375 case SAT_sampler_cube_array:bind._desired_type = Texture::TT_cube_map_array;
break;
1376 case SAT_sampler1d_array:bind._desired_type = Texture::TT_1d_texture_array;
break;
1381 if (pieces.size() == 3) {
1382 bind._suffix = InternalName::make(((
string)
"-") + pieces[2]);
1383 shader_cat.warning()
1384 <<
"Parameter " << p._id._name <<
": use of a texture suffix is deprecated.\n";
1386 _tex_spec.push_back(bind);
1390 if (pieces[0] ==
"shadow") {
1395 if (pieces.size() != 2) {
1401 bind._name =
nullptr;
1402 bind._stage = atoi(pieces[1].c_str());
1403 bind._part = STO_light_i_shadow_map;
1405 case SAT_sampler2d: bind._desired_type = Texture::TT_2d_texture;
break;
1406 case SAT_sampler_cube: bind._desired_type = Texture::TT_cube_map;
break;
1411 _tex_spec.push_back(bind);
1417 if (pieces[0] ==
"texpad") {
1426 bind._piece = SMP_row3;
1427 bind._func = SMF_first;
1428 bind._part[0] = SMO_texpad_x;
1429 bind._arg[0] = InternalName::make(pieces[1]);
1430 bind._part[1] = SMO_identity;
1431 bind._arg[1] =
nullptr;
1433 _mat_spec.push_back(bind);
1434 _mat_deps |= bind._dep[0] | bind._dep[1];
1438 if (pieces[0] ==
"texpix") {
1447 bind._piece = SMP_row3;
1448 bind._func = SMF_first;
1449 bind._part[0] = SMO_texpix_x;
1450 bind._arg[0] = InternalName::make(pieces[1]);
1451 bind._part[1] = SMO_identity;
1452 bind._arg[1] =
nullptr;
1454 _mat_spec.push_back(bind);
1455 _mat_deps |= bind._dep[0] | bind._dep[1];
1459 if (pieces[0] ==
"tbl") {
1464 if (pieces[0] ==
"l") {
1469 if (pieces[0] ==
"o") {
1480 bool k_prefix =
false;
1483 if (pieces[0] ==
"k") {
1485 basename = basename.substr(2);
1488 PT(
InternalName) kinputname = InternalName::make(struct_name + basename);
1495 if (!cp_errchk_parameter_ptr(p))
1500 bind._arg = kinputname;
1506 bind._dep[0] = SSD_general | SSD_shaderinputs | SSD_frame;
1507 bind._dep[1] = SSD_NONE;
1509 memcpy(bind._dim,arg_dim,
sizeof(
int)*3);
1512 if (k_prefix) bind._dim[0] = -1;
1513 _ptr_spec.push_back(bind);
1519 case SAT_sampler1d: {
1522 bind._name = kinputname;
1523 bind._part = STO_named_input;
1524 bind._desired_type = Texture::TT_1d_texture;
1525 _tex_spec.push_back(bind);
1528 case SAT_sampler2d: {
1531 bind._name = kinputname;
1532 bind._part = STO_named_input;
1533 bind._desired_type = Texture::TT_2d_texture;
1534 _tex_spec.push_back(bind);
1537 case SAT_sampler3d: {
1540 bind._name = kinputname;
1541 bind._part = STO_named_input;
1542 bind._desired_type = Texture::TT_3d_texture;
1543 _tex_spec.push_back(bind);
1546 case SAT_sampler2d_array: {
1549 bind._name = kinputname;
1550 bind._part = STO_named_input;
1551 bind._desired_type = Texture::TT_2d_texture_array;
1552 _tex_spec.push_back(bind);
1555 case SAT_sampler_cube: {
1558 bind._name = kinputname;
1559 bind._part = STO_named_input;
1560 bind._desired_type = Texture::TT_cube_map;
1561 _tex_spec.push_back(bind);
1564 case SAT_sampler_buffer: {
1567 bind._name = kinputname;
1568 bind._part = STO_named_input;
1569 bind._desired_type = Texture::TT_buffer_texture;
1570 _tex_spec.push_back(bind);
1573 case SAT_sampler_cube_array: {
1576 bind._name = kinputname;
1577 bind._part = STO_named_input;
1578 bind._desired_type = Texture::TT_cube_map_array;
1579 _tex_spec.push_back(bind);
1582 case SAT_sampler1d_array: {
1585 bind._name = kinputname;
1586 bind._part = STO_named_input;
1587 bind._desired_type = Texture::TT_1d_texture_array;
1588 _tex_spec.push_back(bind);
1619set_compiled(
unsigned int format,
const char *data,
size_t length) {
1620 _compiled_format = format;
1621 _compiled_binary.assign(data, length);
1624 if (_cache_compiled_shader && !_record.is_null()) {
1625 _record->set_data(
this);
1628 cache->
store(_record);
1636get_compiled(
unsigned int &format,
string &binary)
const {
1637 format = _compiled_format;
1638 binary = _compiled_binary;
1639 return !binary.empty();
1648 _default_caps = caps;
1655Shader::ShaderArgType Shader::
1656cg_parameter_type(CGparameter p) {
1657 switch (cgGetParameterClass(p)) {
1658 case CG_PARAMETERCLASS_SCALAR:
return SAT_scalar;
1659 case CG_PARAMETERCLASS_VECTOR:
1660 switch (cgGetParameterColumns(p)) {
1661 case 1:
return SAT_vec1;
1662 case 2:
return SAT_vec2;
1663 case 3:
return SAT_vec3;
1664 case 4:
return SAT_vec4;
1665 default:
return SAT_unknown;
1667 case CG_PARAMETERCLASS_MATRIX:
1668 switch (cgGetParameterRows(p)) {
1670 switch (cgGetParameterColumns(p)) {
1671 case 1:
return SAT_mat1x1;
1672 case 2:
return SAT_mat1x2;
1673 case 3:
return SAT_mat1x3;
1674 case 4:
return SAT_mat1x4;
1675 default:
return SAT_unknown;
1678 switch (cgGetParameterColumns(p)) {
1679 case 1:
return SAT_mat2x1;
1680 case 2:
return SAT_mat2x2;
1681 case 3:
return SAT_mat2x3;
1682 case 4:
return SAT_mat2x4;
1683 default:
return SAT_unknown;
1686 switch (cgGetParameterColumns(p)) {
1687 case 1:
return SAT_mat3x1;
1688 case 2:
return SAT_mat3x2;
1689 case 3:
return SAT_mat3x3;
1690 case 4:
return SAT_mat3x4;
1691 default:
return SAT_unknown;
1694 switch (cgGetParameterColumns(p)) {
1695 case 1:
return SAT_mat4x1;
1696 case 2:
return SAT_mat4x2;
1697 case 3:
return SAT_mat4x3;
1698 case 4:
return SAT_mat4x4;
1699 default:
return SAT_unknown;
1701 default:
return SAT_unknown;
1703 case CG_PARAMETERCLASS_SAMPLER:
1704 switch (cgGetParameterType(p)) {
1705 case CG_SAMPLER1D:
return Shader::SAT_sampler1d;
1706 case CG_SAMPLER2D:
return Shader::SAT_sampler2d;
1707 case CG_SAMPLER3D:
return Shader::SAT_sampler3d;
1708 case CG_SAMPLER2DARRAY:
return Shader::SAT_sampler2d_array;
1709 case CG_SAMPLERCUBE:
return Shader::SAT_sampler_cube;
1710 case CG_SAMPLERBUF:
return Shader::SAT_sampler_buffer;
1711 case CG_SAMPLERCUBEARRAY:
return Shader::SAT_sampler_cube_array;
1712 case CG_SAMPLER1DARRAY:
return Shader::SAT_sampler1d_array;
1714 case 1313:
return Shader::SAT_sampler1d;
1715 case 1314:
return Shader::SAT_sampler2d;
1716 default:
return SAT_unknown;
1718 case CG_PARAMETERCLASS_ARRAY:
return SAT_unknown;
1727Shader::ShaderArgClass Shader::cg_parameter_class(CGparameter p) {
1728 switch (cgGetParameterClass(p)) {
1729 case CG_PARAMETERCLASS_SCALAR:
return Shader::SAC_scalar;
1730 case CG_PARAMETERCLASS_VECTOR:
return Shader::SAC_vector;
1731 case CG_PARAMETERCLASS_MATRIX:
return Shader::SAC_matrix;
1732 case CG_PARAMETERCLASS_SAMPLER:
return Shader::SAC_sampler;
1733 case CG_PARAMETERCLASS_ARRAY:
return Shader::SAC_array;
1734 default:
return Shader::SAC_unknown;
1741Shader::ShaderArgDir Shader::
1742cg_parameter_dir(CGparameter p) {
1743 switch (cgGetParameterDirection(p)) {
1744 case CG_IN:
return Shader::SAD_in;
1745 case CG_OUT:
return Shader::SAD_out;
1746 case CG_INOUT:
return Shader::SAD_inout;
1747 default:
return Shader::SAD_unknown;
1755cg_release_resources() {
1756 if (_cg_vprogram != 0) {
1757 cgDestroyProgram(_cg_vprogram);
1760 if (_cg_fprogram != 0) {
1761 cgDestroyProgram(_cg_fprogram);
1764 if (_cg_gprogram != 0) {
1765 cgDestroyProgram(_cg_gprogram);
1774cg_compile_entry_point(
const char *entry,
const ShaderCaps &caps,
1775 CGcontext context, ShaderType type) {
1778 const char *compiler_args[100];
1779 const string text =
get_text(type);
1782 int active, ultimate;
1786 active = caps._active_vprofile;
1787 ultimate = caps._ultimate_vprofile;
1791 active = caps._active_fprofile;
1792 ultimate = caps._ultimate_fprofile;
1796 active = caps._active_gprofile;
1797 ultimate = caps._ultimate_gprofile;
1800 case ST_tess_evaluation:
1801 case ST_tess_control:
1802 active = caps._active_tprofile;
1803 ultimate = caps._ultimate_tprofile;
1808 active = CG_PROFILE_UNKNOWN;
1809 ultimate = CG_PROFILE_UNKNOWN;
1812 if (type == ST_fragment && caps._bug_list.count(SBUG_ati_draw_buffers)) {
1813 compiler_args[nargs++] =
"-po";
1814 compiler_args[nargs++] =
"ATI_draw_buffers";
1818 if (!cg_glsl_version.empty() && active != CG_PROFILE_UNKNOWN &&
1819 cgGetProfileProperty((CGprofile) active, CG_IS_GLSL_PROFILE)) {
1821 version_arg =
"version=";
1822 version_arg += cg_glsl_version;
1824 compiler_args[nargs++] =
"-po";
1825 compiler_args[nargs++] = version_arg.c_str();
1828 compiler_args[nargs] = 0;
1832 if ((active != (
int)CG_PROFILE_UNKNOWN) && (active != ultimate)) {
1834 if (shader_cat.is_debug()) {
1836 <<
"Compiling Cg shader " <<
get_filename(type) <<
" with entry point " << entry
1837 <<
" and active profile " << cgGetProfileString((CGprofile) active) <<
"\n";
1840 shader_cat.debug() <<
"Using compiler arguments:";
1841 for (
int i = 0; i < nargs; ++i) {
1842 shader_cat.debug(
false) <<
" " << compiler_args[i];
1844 shader_cat.debug(
false) <<
"\n";
1849 prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
1850 (CGprofile)active, entry, (
const char **)compiler_args);
1852 if (err == CG_NO_ERROR) {
1856 cgDestroyProgram(prog);
1858 if (shader_cat.is_debug()) {
1860 <<
"Compilation with active profile failed: " << cgGetErrorString(err) <<
"\n";
1861 if (err == CG_COMPILER_ERROR) {
1862 const char *listing = cgGetLastListing(context);
1863 if (listing !=
nullptr) {
1864 shader_cat.debug(
false) << listing;
1870 if (shader_cat.is_debug()) {
1872 <<
"Compiling Cg shader " <<
get_filename(type) <<
" with entry point " << entry
1873 <<
" and ultimate profile " << cgGetProfileString((CGprofile) ultimate) <<
"\n";
1877 prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
1878 (CGprofile)ultimate, entry,
nullptr);
1882 const char *listing = cgGetLastListing(context);
1884 if (err == CG_NO_ERROR && listing !=
nullptr && strlen(listing) > 1) {
1885 shader_cat.warning()
1886 <<
"Encountered warnings during compilation of " <<
get_filename(type)
1887 <<
":\n" << listing;
1889 }
else if (err == CG_COMPILER_ERROR) {
1891 <<
"Failed to compile Cg shader " <<
get_filename(type);
1892 if (listing !=
nullptr) {
1893 shader_cat.error(
false) <<
":\n" << listing;
1895 shader_cat.error(
false) <<
"!\n";
1899 if (err == CG_NO_ERROR) {
1903 if (shader_cat.is_debug()) {
1905 <<
"Compilation with ultimate profile failed: " << cgGetErrorString(err) <<
"\n";
1909 cgDestroyProgram(prog);
1920cg_compile_shader(
const ShaderCaps &caps, CGcontext context) {
1921 _cg_last_caps = caps;
1923 if (!_text._separate || !_text._vertex.empty()) {
1924 _cg_vprogram = cg_compile_entry_point(
"vshader", caps, context, ST_vertex);
1925 if (_cg_vprogram == 0) {
1926 cg_release_resources();
1929 _cg_vprofile = cgGetProgramProfile(_cg_vprogram);
1932 if (!_text._separate || !_text._fragment.empty()) {
1933 _cg_fprogram = cg_compile_entry_point(
"fshader", caps, context, ST_fragment);
1934 if (_cg_fprogram == 0) {
1935 cg_release_resources();
1938 _cg_fprofile = cgGetProgramProfile(_cg_fprogram);
1941 if ((_text._separate && !_text._geometry.empty()) || (!_text._separate && _text._shared.find(
"gshader") != string::npos)) {
1942 _cg_gprogram = cg_compile_entry_point(
"gshader", caps, context, ST_geometry);
1943 if (_cg_gprogram == 0) {
1944 cg_release_resources();
1947 _cg_gprofile = cgGetProgramProfile(_cg_gprogram);
1950 if (_cg_vprogram == 0 && _cg_fprogram == 0 && _cg_gprogram == 0) {
1951 shader_cat.error() <<
"Shader must at least have one program!\n";
1952 cg_release_resources();
1960 if (_cg_fprofile == CG_PROFILE_PS_2_0 ||
1961 _cg_fprofile == CG_PROFILE_PS_2_X ||
1962 _cg_fprofile == CG_PROFILE_PS_3_0) {
1963 vector_string lines;
1964 tokenize(cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM), lines,
"\n");
1967 int num_modified = 0;
1969 for (
size_t i = 0; i < lines.size(); ++i) {
1970 const string &line = lines[i];
1972 size_t space = line.find(
' ');
1973 if (space == string::npos) {
1974 out << line <<
'\n';
1978 string instr = line.substr(0, space);
1981 if (instr.compare(0, 5,
"texld") == 0 &&
1982 instr.compare(instr.size() - 4, 4,
"_sat") == 0) {
1984 string reg = line.substr(space + 1, line.find(
',', space) - space - 1);
1987 instr.resize(instr.size() - 4);
1988 out << instr <<
' ' << line.substr(space + 1) <<
'\n';
1989 out <<
"mov_sat " << reg <<
", " << reg <<
'\n';
1992 out << line <<
'\n';
1996 if (num_modified > 0) {
1997 string result = out.str();
1998 CGprogram new_program;
1999 new_program = cgCreateProgram(context, CG_OBJECT, result.c_str(),
2000 (CGprofile)_cg_fprofile,
"fshader",
2003 cgDestroyProgram(_cg_fprogram);
2004 _cg_fprogram = new_program;
2006 if (shader_cat.is_debug()) {
2008 <<
"Replaced " << num_modified <<
" invalid texld_sat instruction"
2009 << ((num_modified == 1) ?
"" :
"s") <<
" in compiled shader\n";
2012 shader_cat.warning()
2013 <<
"Failed to load shader with fixed texld_sat instructions: "
2014 << cgGetErrorString(cgGetError()) <<
"\n";
2020 if (shader_cat.is_debug()) {
2021 const char *vertex_program;
2022 const char *fragment_program;
2023 const char *geometry_program;
2025 if (_cg_vprogram != 0) {
2027 <<
"Cg vertex profile: " << cgGetProfileString((CGprofile)_cg_vprofile) <<
"\n";
2028 vertex_program = cgGetProgramString(_cg_vprogram, CG_COMPILED_PROGRAM);
2029 shader_cat.spam() << vertex_program <<
"\n";
2031 if (_cg_fprogram != 0) {
2033 <<
"Cg fragment profile: " << cgGetProfileString((CGprofile)_cg_fprofile) <<
"\n";
2034 fragment_program = cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM);
2035 shader_cat.spam() << fragment_program <<
"\n";
2037 if (_cg_gprogram != 0) {
2039 <<
"Cg geometry profile: " << cgGetProfileString((CGprofile)_cg_gprofile) <<
"\n";
2040 geometry_program = cgGetProgramString(_cg_gprogram, CG_COMPILED_PROGRAM);
2041 shader_cat.spam() << geometry_program <<
"\n";
2052cg_analyze_entry_point(CGprogram prog, ShaderType type) {
2053 bool success =
true;
2055 cg_recurse_parameters(cgGetFirstParameter(prog, CG_PROGRAM), type, success);
2084cg_analyze_shader(
const ShaderCaps &caps) {
2087 if (_cg_context == 0) {
2088 _cg_context = cgCreateContext();
2089 if (_cg_context == 0) {
2091 <<
"Could not create a Cg context object: "
2092 << cgGetErrorString(cgGetError()) <<
"\n";
2097 if (!cg_compile_shader(caps, _cg_context)) {
2101 if (_cg_fprogram != 0) {
2102 if (!cg_analyze_entry_point(_cg_fprogram, ST_fragment)) {
2103 cg_release_resources();
2109 if (_var_spec.size() != 0) {
2110 shader_cat.error() <<
"Cannot use vtx parameters in an fshader\n";
2111 cg_release_resources();
2116 if (_cg_vprogram != 0) {
2117 if (!cg_analyze_entry_point(_cg_vprogram, ST_vertex)) {
2118 cg_release_resources();
2124 if (_cg_gprogram != 0) {
2125 if (!cg_analyze_entry_point(_cg_gprogram, ST_geometry)) {
2126 cg_release_resources();
2135 for (
size_t i = 0; i < _var_spec.size(); ++i) {
2136 _var_spec[i]._id._seqno = seqno++;
2138 for (
size_t i = 0; i < _mat_spec.size(); ++i) {
2139 _mat_spec[i]._id._seqno = seqno++;
2141 for (
size_t i = 0; i < _tex_spec.size(); ++i) {
2142 _tex_spec[i]._id._seqno = seqno++;
2145 for (
size_t i = 0; i < _ptr_spec.size(); ++i) {
2146 _ptr_spec[i]._id._seqno = seqno++;
2147 _ptr_spec[i]._info._id = _ptr_spec[i]._id;
2225 cg_release_resources();
2233cg_program_from_shadertype(ShaderType type) {
2236 return _cg_vprogram;
2239 return _cg_fprogram;
2242 return _cg_gprogram;
2255cg_compile_for(
const ShaderCaps &caps, CGcontext context,
2259 combined_program = 0;
2265 _default_caps = caps;
2266 if (!cg_compile_shader(caps, context)) {
2272 if (_cg_vprogram != 0 && _cg_vprofile != caps._active_vprofile) {
2273 shader_cat.error() <<
"Cg vertex program not supported by profile "
2274 << cgGetProfileString((CGprofile) caps._active_vprofile) <<
": "
2275 <<
get_filename(ST_vertex) <<
". Try choosing a different profile.\n";
2278 if (_cg_fprogram != 0 && _cg_fprofile != caps._active_fprofile) {
2279 shader_cat.error() <<
"Cg fragment program not supported by profile "
2280 << cgGetProfileString((CGprofile) caps._active_fprofile) <<
": "
2281 <<
get_filename(ST_fragment) <<
". Try choosing a different profile.\n";
2284 if (_cg_gprogram != 0 && _cg_gprofile != caps._active_gprofile) {
2285 shader_cat.error() <<
"Cg geometry program not supported by profile "
2286 << cgGetProfileString((CGprofile) caps._active_gprofile) <<
": "
2287 <<
get_filename(ST_geometry) <<
". Try choosing a different profile.\n";
2293 if (_cg_vprogram != 0) {
2294 programs.push_back(_cg_vprogram);
2296 if (_cg_fprogram != 0) {
2297 programs.push_back(_cg_fprogram);
2299 if (_cg_gprogram != 0) {
2300 programs.push_back(_cg_gprogram);
2306 combined_program = cgCombinePrograms(programs.size(), &programs[0]);
2309 size_t n_mat = _mat_spec.size();
2310 size_t n_tex = _tex_spec.size();
2311 size_t n_var = _var_spec.size();
2312 size_t n_ptr = _ptr_spec.size();
2314 map.resize(n_mat + n_tex + n_var + n_ptr);
2318 CGprogram programs_by_type[ST_COUNT];
2319 for (
int i = 0; i < cgGetNumProgramDomains(combined_program); ++i) {
2321 CGprogram program = cgGetProgramDomainProgram(combined_program, i);
2322 programs_by_type[cgGetProgramDomain(program)] = program;
2325 for (
size_t i = 0; i < n_mat; ++i) {
2326 const ShaderArgId &
id = _mat_spec[i]._id;
2327 map[
id._seqno] = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
2329 if (shader_cat.is_debug()) {
2330 const char *resource = cgGetParameterResourceName(map[
id._seqno]);
2331 if (resource !=
nullptr) {
2332 shader_cat.debug() <<
"Uniform parameter " <<
id._name
2333 <<
" is bound to resource " << resource <<
"\n";
2338 for (
size_t i = 0; i < n_tex; ++i) {
2339 const ShaderArgId &
id = _tex_spec[i]._id;
2340 CGparameter p = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
2342 if (shader_cat.is_debug()) {
2343 const char *resource = cgGetParameterResourceName(p);
2344 if (resource !=
nullptr) {
2345 shader_cat.debug() <<
"Texture parameter " <<
id._name
2346 <<
" is bound to resource " << resource <<
"\n";
2352 for (
size_t i = 0; i < n_var; ++i) {
2353 const ShaderArgId &
id = _var_spec[i]._id;
2354 CGparameter p = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
2356 const char *resource = cgGetParameterResourceName(p);
2357 if (shader_cat.is_debug() && resource !=
nullptr) {
2358 if (cgGetParameterResource(p) == CG_GLSL_ATTRIB) {
2360 <<
"Varying parameter " <<
id._name <<
" is bound to GLSL attribute "
2361 << resource <<
"\n";
2364 <<
"Varying parameter " <<
id._name <<
" is bound to resource "
2365 << resource <<
" (" << cgGetParameterResource(p)
2366 <<
", index " << cgGetParameterResourceIndex(p) <<
")\n";
2373 for (
size_t i = 0; i < n_ptr; ++i) {
2374 const ShaderArgId &
id = _ptr_spec[i]._id;
2375 map[
id._seqno] = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
2377 if (shader_cat.is_debug()) {
2378 const char *resource = cgGetParameterResourceName(map[
id._seqno]);
2379 if (resource !=
nullptr) {
2380 shader_cat.debug() <<
"Uniform ptr parameter " <<
id._name
2381 <<
" is bound to resource " << resource <<
"\n";
2387 if (_cg_vprogram != 0) {
2388 cgDestroyProgram(_cg_vprogram);
2391 if (_cg_fprogram != 0) {
2392 cgDestroyProgram(_cg_fprogram);
2395 if (_cg_gprogram != 0) {
2396 cgDestroyProgram(_cg_gprogram);
2400 _cg_last_caps.clear();
2410Shader(ShaderLanguage lang) :
2417 _cache_compiled_shader(false)
2423 _cg_vprofile = CG_PROFILE_UNKNOWN;
2424 _cg_fprofile = CG_PROFILE_UNKNOWN;
2425 _cg_gprofile = CG_PROFILE_UNKNOWN;
2426 if (_default_caps._ultimate_vprofile == 0 || _default_caps._ultimate_vprofile == CG_PROFILE_UNKNOWN) {
2427 if (basic_shaders_only) {
2428 _default_caps._active_vprofile = CG_PROFILE_ARBVP1;
2429 _default_caps._active_fprofile = CG_PROFILE_ARBFP1;
2430 _default_caps._active_gprofile = CG_PROFILE_UNKNOWN;
2432 _default_caps._active_vprofile = CG_PROFILE_UNKNOWN;
2433 _default_caps._active_fprofile = CG_PROFILE_UNKNOWN;
2434 _default_caps._active_gprofile = CG_PROFILE_UNKNOWN;
2436 _default_caps._ultimate_vprofile = cgGetProfile(
"glslv");
2437 _default_caps._ultimate_fprofile = cgGetProfile(
"glslf");
2438 _default_caps._ultimate_gprofile = cgGetProfile(
"glslg");
2439 if (_default_caps._ultimate_gprofile == CG_PROFILE_UNKNOWN) {
2440 _default_caps._ultimate_gprofile = cgGetProfile(
"gp4gp");
2452 _text._separate = sfile._separate;
2454 if (sfile._separate) {
2455 if (_language == SL_none) {
2457 <<
"No shader language was specified!\n";
2461 if (!sfile._vertex.empty() &&
2462 !do_read_source(_text._vertex, sfile._vertex, record)) {
2465 if (!sfile._fragment.empty() &&
2466 !do_read_source(_text._fragment, sfile._fragment, record)) {
2469 if (!sfile._geometry.empty() &&
2470 !do_read_source(_text._geometry, sfile._geometry, record)) {
2473 if (!sfile._tess_control.empty() &&
2474 !do_read_source(_text._tess_control, sfile._tess_control, record)) {
2477 if (!sfile._tess_evaluation.empty() &&
2478 !do_read_source(_text._tess_evaluation, sfile._tess_evaluation, record)) {
2481 if (!sfile._compute.empty() &&
2482 !do_read_source(_text._compute, sfile._compute, record)) {
2488 if (!do_read_source(_text._shared, sfile._shared, record)) {
2491 _fullpath = _source_files[0];
2495 if (_language == SL_none) {
2499 if (header ==
"//Cg") {
2503 <<
"Unable to determine shader language of " << sfile._shared <<
"\n";
2506 }
else if (_language == SL_GLSL) {
2508 <<
"GLSL shaders must have separate shader bodies!\n";
2513 if (_language == SL_Cg) {
2515 ShaderCaps caps = _default_caps;
2516 cg_get_profile_from_header(caps);
2518 if (!cg_analyze_shader(caps)) {
2520 <<
"Shader encountered an error.\n";
2525 <<
"Tried to load Cg shader, but no Cg support is enabled.\n";
2529 <<
"Shader is not in a supported shader-language.\n";
2544 _filename = ShaderFile(
"created-shader");
2546 _text._separate = sbody._separate;
2548 if (sbody._separate) {
2549 if (_language == SL_none) {
2551 <<
"No shader language was specified!\n";
2555 if (!sbody._vertex.empty() &&
2556 !do_load_source(_text._vertex, sbody._vertex, record)) {
2559 if (!sbody._fragment.empty() &&
2560 !do_load_source(_text._fragment, sbody._fragment, record)) {
2563 if (!sbody._geometry.empty() &&
2564 !do_load_source(_text._geometry, sbody._geometry, record)) {
2567 if (!sbody._tess_control.empty() &&
2568 !do_load_source(_text._tess_control, sbody._tess_control, record)) {
2571 if (!sbody._tess_evaluation.empty() &&
2572 !do_load_source(_text._tess_evaluation, sbody._tess_evaluation, record)) {
2575 if (!sbody._compute.empty() &&
2576 !do_load_source(_text._compute, sbody._compute, record)) {
2581 if (!do_load_source(_text._shared, sbody._shared, record)) {
2586 if (_language == SL_none) {
2590 if (header ==
"//Cg") {
2594 <<
"Unable to determine shader language of " << sbody._shared <<
"\n";
2597 }
else if (_language == SL_GLSL) {
2599 <<
"GLSL shaders must have separate shader bodies!\n";
2604 if (_language == SL_Cg) {
2606 ShaderCaps caps = _default_caps;
2607 cg_get_profile_from_header(caps);
2609 if (!cg_analyze_shader(caps)) {
2611 <<
"Shader encountered an error.\n";
2616 <<
"Tried to load Cg shader, but no Cg support is enabled.\n";
2620 <<
"Shader is not in a supported shader-language.\n";
2639 if (vf ==
nullptr) {
2641 <<
"Could not find shader file: " << fn <<
"\n";
2645 if (_language == SL_GLSL && glsl_preprocess) {
2646 istream *source = vf->open_read_file(
true);
2647 if (source ==
nullptr) {
2649 <<
"Could not open shader file: " << fn <<
"\n";
2655 <<
"Preprocessing shader file: " << fn <<
"\n";
2657 std::set<Filename> open_files;
2659 if (!r_preprocess_source(sstr, *source, fn, vf->get_filename(), open_files, record)) {
2660 vf->close_read_file(source);
2663 vf->close_read_file(source);
2667 shader_cat.info() <<
"Reading shader file: " << fn <<
"\n";
2669 if (!vf->read_file(into,
true)) {
2671 <<
"Could not read shader file: " << fn <<
"\n";
2676 if (record !=
nullptr) {
2680 _last_modified = std::max(_last_modified, vf->get_timestamp());
2681 _source_files.push_back(vf->get_filename());
2684 while (!into.empty() && isspace(into[into.size() - 1])) {
2685 into.resize(into.size() - 1);
2702do_load_source(
string &into,
const std::string &source,
BamCacheRecord *record) {
2703 if (_language == SL_GLSL && glsl_preprocess) {
2705 std::set<Filename> open_files;
2706 std::ostringstream sstr;
2707 std::istringstream in(source);
2709 open_files, record)) {
2719 while (!into.empty() && isspace(into[into.size() - 1])) {
2720 into.resize(into.size() - 1);
2737r_preprocess_include(ostream &out,
const Filename &fn,
2739 std::set<Filename> &once_files,
2742 if (depth > glsl_include_recursion_limit) {
2744 <<
"GLSL includes nested too deeply, raise glsl-include-recursion-limit"
2750 if (!source_dir.empty()) {
2751 path.prepend_directory(source_dir);
2756 if (vf ==
nullptr) {
2758 <<
"Could not find shader include: " << fn <<
"\n";
2762 Filename full_fn = vf->get_filename();
2763 if (once_files.find(full_fn) != once_files.end()) {
2768 istream *source = vf->open_read_file(
true);
2769 if (source ==
nullptr) {
2771 <<
"Could not open shader include: " << fn <<
"\n";
2775 if (record !=
nullptr) {
2778 _last_modified = std::max(_last_modified, vf->get_timestamp());
2779 _source_files.push_back(full_fn);
2787 fileno = 2048 + _included_files.size();
2792 _included_files.push_back(fn);
2794 if (shader_cat.is_debug()) {
2796 <<
"Preprocessing shader include " << fileno <<
": " << fn <<
"\n";
2799 bool result = r_preprocess_source(out, *source, fn, full_fn, once_files, record, fileno, depth);
2800 vf->close_read_file(source);
2812r_preprocess_source(ostream &out, istream &in,
const Filename &fn,
2813 const Filename &full_fn, std::set<Filename> &once_files,
2818 int ext_google_include = 0;
2819 int ext_google_line = 0;
2820 bool had_include =
false;
2821 bool had_version =
false;
2823 bool write_line_directive = (fileno != 0);
2825 while (std::getline(in, line)) {
2831 if (!write_line_directive) {
2839 while (line[line.size() - 1] ==
'\\') {
2840 line.resize(line.size() - 1);
2843 if (std::getline(in, line2)) {
2845 if (!write_line_directive) {
2856 size_t line_comment = line.find(
"//");
2857 size_t block_comment = line.find(
"/*");
2858 if (line_comment < block_comment) {
2860 line.resize(line_comment);
2862 }
else if (block_comment < line_comment) {
2864 string line2 = line.substr(block_comment + 2);
2868 line.resize(block_comment);
2871 size_t block_end = line2.find(
"*/");
2872 while (block_end == string::npos) {
2874 if (std::getline(in, line2)) {
2875 if (!write_line_directive) {
2879 block_end = line2.find(
"*/");
2882 <<
"Expected */ before end of file " << fn <<
"\n";
2887 line += line2.substr(block_end + 2);
2891 while (!line.empty() && isspace(line[line.size() - 1])) {
2892 line.resize(line.size() - 1);
2896 if (!write_line_directive) {
2904 if (line.size() < 8 || sscanf(line.c_str(),
" # %63s", directive) != 1) {
2906 if (write_line_directive) {
2907 out <<
"#line " << lineno <<
" " << fileno <<
" // " << fn <<
"\n";
2908 write_line_directive =
false;
2910 out << line <<
"\n";
2917 if (strcmp(directive,
"pragma") == 0 &&
2918 sscanf(line.c_str(),
" # pragma %63s", pragma) == 1) {
2919 if (strcmp(pragma,
"include") == 0) {
2924 if (sscanf(line.c_str(),
" # pragma%*[ \t]include \"%2047[^\"]\" %zn", incfile, &nread) == 1
2925 && nread == line.size()) {
2930 }
else if (sscanf(line.c_str(),
" # pragma%*[ \t]include <%2047[^>]> %zn", incfile, &nread) == 1
2931 && nread == line.size()) {
2939 <<
"Malformed #pragma include at line " << lineno
2940 <<
" of file " << fn <<
":\n " << line <<
"\n";
2946 if (!r_preprocess_include(out, incfn, source_dir, once_files, record, depth + 1)) {
2948 shader_cat.error(
false) <<
"included at line "
2949 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
2954 write_line_directive =
true;
2958 }
else if (strcmp(pragma,
"once") == 0) {
2960 if (sscanf(line.c_str(),
" # pragma%*[ \t]once %zn", &nread) != 0 ||
2961 nread != line.size()) {
2963 <<
"Malformed #pragma once at line " << lineno
2964 <<
" of file " << fn <<
":\n " << line <<
"\n";
2969 shader_cat.warning()
2970 <<
"#pragma once in main file at line "
2971 << lineno <<
" of file " << fn
2978 if (!full_fn.empty()) {
2979 once_files.insert(full_fn);
2985 }
else if (strcmp(directive,
"endif") == 0) {
2989 write_line_directive =
true;
2992 }
else if (strcmp(directive,
"version") == 0) {
2995 }
else if (strcmp(directive,
"extension") == 0) {
2997 char extension[256];
2999 if (sscanf(line.c_str(),
" # extension%*[ \t]%255[^: \t] : %8s", extension, behavior) == 2) {
3002 if (strcmp(behavior,
"require") == 0 || strcmp(behavior,
"enable") == 0) {
3004 }
else if (strcmp(behavior,
"warn") == 0) {
3006 }
else if (strcmp(behavior,
"disable") == 0) {
3010 <<
"Extension directive specifies invalid behavior at line "
3011 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
3015 if (strcmp(extension,
"all") == 0) {
3018 <<
"Extension directive for 'all' may only specify 'warn' or "
3019 "'disable' at line " << lineno <<
" of file " << fn
3020 <<
":\n " << line <<
"\n";
3023 ext_google_include = mode;
3024 ext_google_line = mode;
3028 }
else if (strcmp(extension,
"GL_GOOGLE_include_directive") == 0) {
3032 ext_google_include = mode;
3033 ext_google_line = mode;
3036 }
else if (strcmp(extension,
"GL_GOOGLE_cpp_style_line_directive") == 0) {
3038 ext_google_line = mode;
3043 <<
"Failed to parse extension directive at line "
3044 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
3048 }
else if (ext_google_include > 0 && strcmp(directive,
"include") == 0) {
3050 if (ext_google_include == 1) {
3051 shader_cat.warning()
3052 <<
"Extension GL_GOOGLE_include_directive is being used at line "
3053 << lineno <<
" of file " << fn
3064 if (sscanf(line.c_str(),
" # include%*[ \t]\"%2047[^\"]\" %zn", incfile, &nread) != 1
3065 || nread != line.size()) {
3068 <<
"Malformed #include at line " << lineno
3069 <<
" of file " << fn <<
":\n " << line <<
"\n";
3077 if (!r_preprocess_include(out, incfn, source_dir, once_files, record, depth + 1)) {
3079 shader_cat.error(
false) <<
"included at line "
3080 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
3085 write_line_directive =
true;
3089 }
else if (ext_google_line > 0 && strcmp(directive,
"line") == 0) {
3092 if (sscanf(line.c_str(),
" # line%*[ \t]%d%*[ \t]\"%2047[^\"]\" %zn", &lineno, filestr, &nread) == 2
3093 && nread == line.size()) {
3095 if (ext_google_line == 1) {
3096 shader_cat.warning()
3097 <<
"Extension GL_GOOGLE_cpp_style_line_directive is being used at line "
3098 << lineno <<
" of file " << fn
3107 fileno = 2048 + _included_files.size();
3108 _included_files.push_back(
Filename(filestr));
3110 out <<
"#line " << lineno <<
" " << fileno <<
" // " << filestr <<
"\n";
3115 if (write_line_directive) {
3116 out <<
"#line " << lineno <<
" " << fileno <<
" // " << fn <<
"\n";
3117 write_line_directive =
false;
3119 out << line <<
"\n";
3122 if (fileno == 0 && !had_version) {
3123 shader_cat.warning()
3124 <<
"GLSL shader " << fn <<
" does not contain a #version line!\n";
3135check_modified()
const {
3139 for (it = _source_files.begin(); it != _source_files.end(); ++it) {
3143 if (vfile ==
nullptr || vfile->get_timestamp() > _last_modified) {
3157cg_get_profile_from_header(ShaderCaps& caps) {
3171 int profilePos = buf.find(
"//Cg profile");
3172 if (profilePos >= 0) {
3174 if ((
int)buf.find(
"gp4vp") >= 0)
3175 caps._active_vprofile = cgGetProfile(
"gp4vp");
3177 if ((
int)buf.find(
"gp5vp") >= 0)
3178 caps._active_vprofile = cgGetProfile(
"gp5vp");
3180 if ((
int)buf.find(
"glslv") >= 0)
3181 caps._active_vprofile = cgGetProfile(
"glslv");
3183 if ((
int)buf.find(
"arbvp1") >= 0)
3184 caps._active_vprofile = cgGetProfile(
"arbvp1");
3186 if ((
int)buf.find(
"vp40") >= 0)
3187 caps._active_vprofile = cgGetProfile(
"vp40");
3189 if ((
int)buf.find(
"vp30") >= 0)
3190 caps._active_vprofile = cgGetProfile(
"vp30");
3192 if ((
int)buf.find(
"vp20") >= 0)
3193 caps._active_vprofile = cgGetProfile(
"vp20");
3195 if ((
int)buf.find(
"vs_1_1") >= 0)
3196 caps._active_vprofile = cgGetProfile(
"vs_1_1");
3198 if ((
int)buf.find(
"vs_2_0") >= 0)
3199 caps._active_vprofile = cgGetProfile(
"vs_2_0");
3201 if ((
int)buf.find(
"vs_2_x") >= 0)
3202 caps._active_vprofile = cgGetProfile(
"vs_2_x");
3204 if ((
int)buf.find(
"vs_3_0") >= 0)
3205 caps._active_vprofile = cgGetProfile(
"vs_3_0");
3207 if ((
int)buf.find(
"vs_4_0") >= 0)
3208 caps._active_vprofile = cgGetProfile(
"vs_4_0");
3210 if ((
int)buf.find(
"vs_5_0") >= 0)
3211 caps._active_vprofile = cgGetProfile(
"vs_5_0");
3214 if ((
int)buf.find(
"gp4fp") >= 0)
3215 caps._active_fprofile = cgGetProfile(
"gp4fp");
3217 if ((
int)buf.find(
"gp5fp") >= 0)
3218 caps._active_fprofile = cgGetProfile(
"gp5fp");
3220 if ((
int)buf.find(
"glslf") >= 0)
3221 caps._active_fprofile = cgGetProfile(
"glslf");
3223 if ((
int)buf.find(
"arbfp1") >= 0)
3224 caps._active_fprofile = cgGetProfile(
"arbfp1");
3226 if ((
int)buf.find(
"fp40") >= 0)
3227 caps._active_fprofile = cgGetProfile(
"fp40");
3229 if ((
int)buf.find(
"fp30") >= 0)
3230 caps._active_fprofile = cgGetProfile(
"fp30");
3232 if ((
int)buf.find(
"fp20") >= 0)
3233 caps._active_fprofile = cgGetProfile(
"fp20");
3235 if ((
int)buf.find(
"ps_1_1") >= 0)
3236 caps._active_fprofile = cgGetProfile(
"ps_1_1");
3238 if ((
int)buf.find(
"ps_1_2") >= 0)
3239 caps._active_fprofile = cgGetProfile(
"ps_1_2");
3241 if ((
int)buf.find(
"ps_1_3") >= 0)
3242 caps._active_fprofile = cgGetProfile(
"ps_1_3");
3244 if ((
int)buf.find(
"ps_2_0") >= 0)
3245 caps._active_fprofile = cgGetProfile(
"ps_2_0");
3247 if ((
int)buf.find(
"ps_2_x") >= 0)
3248 caps._active_fprofile = cgGetProfile(
"ps_2_x");
3250 if ((
int)buf.find(
"ps_3_0") >= 0)
3251 caps._active_fprofile = cgGetProfile(
"ps_3_0");
3253 if ((
int)buf.find(
"ps_4_0") >= 0)
3254 caps._active_fprofile = cgGetProfile(
"ps_4_0");
3256 if ((
int)buf.find(
"ps_5_0") >= 0)
3257 caps._active_fprofile = cgGetProfile(
"ps_5_0");
3260 if ((
int)buf.find(
"gp4gp") >= 0)
3261 caps._active_gprofile = cgGetProfile(
"gp4gp");
3263 if ((
int)buf.find(
"gp5gp") >= 0)
3264 caps._active_gprofile = cgGetProfile(
"gp5gp");
3266 if ((
int)buf.find(
"glslg") >= 0)
3267 caps._active_gprofile = cgGetProfile(
"glslg");
3269 if ((
int)buf.find(
"gs_4_0") >= 0)
3270 caps._active_gprofile = cgGetProfile(
"gs_4_0");
3272 if ((
int)buf.find(
"gs_5_0") >= 0)
3273 caps._active_gprofile = cgGetProfile(
"gs_5_0");
3275 }
while(_parse > lastParse);
3308 }
else if (glsl_preprocess && index >= 2048 &&
3309 (index - 2048) < (
int)_included_files.size()) {
3310 return _included_files[(size_t)index - 2048];
3313 string str = format_string(index);
3321load(
const Filename &file, ShaderLanguage lang) {
3322 ShaderFile sfile(file);
3323 ShaderTable::const_iterator i = _load_table.find(sfile);
3324 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
3326 if (i->second->check_modified()) {
3328 <<
"Shader " << file <<
" was modified on disk, reloading.\n";
3330 if (shader_cat.is_debug()) {
3332 <<
"Shader " << file <<
" was found in shader cache.\n";
3339 if (!shader->read(sfile)) {
3343 _load_table[sfile] = shader;
3345 if (cache_generated_shaders) {
3346 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3347 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3350 _make_table[shader->_text] = shader;
3359load(ShaderLanguage lang,
const Filename &vertex,
3362 ShaderFile sfile(vertex, fragment, geometry, tess_control, tess_evaluation);
3363 ShaderTable::const_iterator i = _load_table.find(sfile);
3364 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
3366 if (i->second->check_modified()) {
3368 <<
"Shader was modified on disk, reloading.\n";
3370 if (shader_cat.is_debug()) {
3372 <<
"Shader was found in shader cache.\n";
3379 if (!shader->read(sfile)) {
3383 _load_table[sfile] = shader;
3385 if (cache_generated_shaders) {
3386 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3387 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3390 _make_table[shader->_text] = shader;
3399load_compute(ShaderLanguage lang,
const Filename &fn) {
3400 if (lang != SL_GLSL) {
3402 <<
"Only GLSL compute shaders are currently supported.\n";
3410 <<
"Could not find compute shader file: " << fn <<
"\n";
3415 sfile._separate =
true;
3416 sfile._compute = fn;
3418 ShaderTable::const_iterator i = _load_table.find(sfile);
3419 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
3421 if (i->second->check_modified()) {
3423 <<
"Compute shader " << fn <<
" was modified on disk, reloading.\n";
3425 if (shader_cat.is_debug()) {
3427 <<
"Compute shader " << fn <<
" was found in shader cache.\n";
3435 if (record !=
nullptr) {
3436 if (record->has_data()) {
3438 <<
"Compute shader " << fn <<
" was found in disk cache.\n";
3446 if (!shader->read(sfile, record)) {
3449 _load_table[sfile] = shader;
3451 if (cache_generated_shaders) {
3452 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3453 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3456 _make_table[shader->_text] = shader;
3461 std::swap(shader->_record, record);
3463 shader->_fullpath = shader->_source_files[0];
3471make(
string body, ShaderLanguage lang) {
3472 if (lang == SL_GLSL) {
3474 <<
"GLSL shaders must have separate shader bodies!\n";
3477 }
else if (lang == SL_none) {
3478 shader_cat.warning()
3479 <<
"Shader::make() now requires an explicit shader language. Assuming Cg.\n";
3483 if (lang == SL_Cg) {
3484 shader_cat.error() <<
"Support for Cg shaders is not enabled.\n";
3489 ShaderFile sbody(std::move(body));
3491 if (cache_generated_shaders) {
3492 ShaderTable::const_iterator i = _make_table.find(sbody);
3493 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3495 if (!i->second->check_modified()) {
3502 if (!shader->load(sbody)) {
3506 if (cache_generated_shaders) {
3507 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3508 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3511 _make_table[shader->_text] = shader;
3513 _make_table[std::move(sbody)] = shader;
3516 if (dump_generated_shaders) {
3518 int index = _shaders_generated ++;
3519 fns <<
"genshader" << index;
3520 string fn = fns.str();
3521 shader_cat.warning() <<
"Dumping shader: " << fn <<
"\n";
3524 s.open(fn.c_str(), std::ios::out | std::ios::trunc);
3525 s << shader->get_text();
3535make(ShaderLanguage lang,
string vertex,
string fragment,
string geometry,
3536 string tess_control,
string tess_evaluation) {
3538 if (lang == SL_Cg) {
3539 shader_cat.error() <<
"Support for Cg shaders is not enabled.\n";
3543 if (lang == SL_none) {
3545 <<
"Shader::make() requires an explicit shader language.\n";
3549 ShaderFile sbody(std::move(vertex), std::move(fragment), std::move(geometry),
3550 std::move(tess_control), std::move(tess_evaluation));
3552 if (cache_generated_shaders) {
3553 ShaderTable::const_iterator i = _make_table.find(sbody);
3554 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3556 if (!i->second->check_modified()) {
3563 shader->_filename = ShaderFile(
"created-shader");
3564 if (!shader->load(sbody)) {
3568 if (cache_generated_shaders) {
3569 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3570 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3573 _make_table[shader->_text] = shader;
3575 _make_table[std::move(sbody)] = shader;
3585make_compute(ShaderLanguage lang,
string body) {
3586 if (lang != SL_GLSL) {
3588 <<
"Only GLSL compute shaders are currently supported.\n";
3593 sbody._separate =
true;
3594 sbody._compute = std::move(body);
3596 if (cache_generated_shaders) {
3597 ShaderTable::const_iterator i = _make_table.find(sbody);
3598 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3600 if (!i->second->check_modified()) {
3607 shader->_filename = ShaderFile(
"created-shader");
3608 if (!shader->load(sbody)) {
3612 if (cache_generated_shaders) {
3613 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3614 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3617 _make_table[shader->_text] = shader;
3619 _make_table[std::move(sbody)] = shader;
3639parse_line(
string &result,
bool lt,
bool rt) {
3640 nassertv(!_text._separate);
3641 int len = _text._shared.size();
3644 while ((tail < len) && (_text._shared[tail] !=
'\n')) {
3653 while ((head < tail)&&(isspace(_text._shared[head]))) head++;
3654 while ((tail > head)&&(isspace(_text._shared[tail-1]))) tail--;
3656 result = _text._shared.substr(head, tail-head);
3665parse_upto(
string &result,
string pattern,
bool include) {
3666 nassertv(!_text._separate);
3670 while (_parse < (
int)(_text._shared.size())) {
3677 result = _text._shared.substr(start, _parse - start);
3679 result = _text._shared.substr(start, last - start);
3688 nassertv(!_text._separate);
3689 result = _text._shared.substr(_parse, _text._shared.size() - _parse);
3697 return (
int)_text._shared.size() == _parse;
3711 return prepared_objects->enqueue_shader_future(
this);
3720 Contexts::const_iterator ci;
3721 ci = _contexts.find(prepared_objects);
3722 if (ci != _contexts.end()) {
3734 Contexts::iterator ci;
3735 ci = _contexts.find(prepared_objects);
3736 if (ci != _contexts.end()) {
3738 if (sc !=
nullptr) {
3741 _contexts.erase(ci);
3764 Contexts::const_iterator ci;
3765 ci = _contexts.find(prepared_objects);
3766 if (ci != _contexts.end()) {
3767 return (*ci).second;
3771 _contexts[prepared_objects] = tc;
3784 Contexts::iterator ci;
3785 ci = _contexts.find(prepared_objects);
3786 if (ci != _contexts.end()) {
3787 _contexts.erase(ci);
3791 nassert_raise(
"unknown PreparedGraphicsObjects");
3806 int num_freed = (int)_contexts.size();
3808 Contexts::const_iterator ci;
3809 for (ci = temp.begin(); ci != temp.end(); ++ci) {
3812 if (sc !=
nullptr) {
3827void Shader::ShaderCaps::
3829 _supports_glsl =
false;
3832 _active_vprofile = CG_PROFILE_UNKNOWN;
3833 _active_fprofile = CG_PROFILE_UNKNOWN;
3834 _active_gprofile = CG_PROFILE_UNKNOWN;
3835 _ultimate_vprofile = CG_PROFILE_UNKNOWN;
3836 _ultimate_fprofile = CG_PROFILE_UNKNOWN;
3837 _ultimate_gprofile = CG_PROFILE_UNKNOWN;
3876 attrib->fillin(scan, manager);
3886 _language = (ShaderLanguage) scan.
get_uint8();
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_params(const FactoryParams ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
This class represents a thread-safe handle to a promised future result of an asynchronous operation,...
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
void add_dependent_file(const Filename &pathname)
Adds the indicated file to the list of files that will be loaded to generate the data in this record.
get_data
Returns a pointer to the data stored in the record, or NULL if there is no data.
This class maintains a cache of Bam and/or Txo objects generated from model files and texture images ...
bool store(BamCacheRecord *record)
Flushes a cache entry to disk.
static BamCache * get_global_ptr()
Returns a pointer to the global BamCache object, which is used automatically by the ModelPool and Tex...
get_cache_compiled_shaders
Returns whether compiled shader programs will be stored in the cache, as binary .txo files.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
This class stores a list of directories that can be searched, in order, to locate a particular file.
A class to retrieve the individual data elements previously stored in a Datagram.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
bool get_bool()
Extracts a boolean value.
std::string get_string()
Extracts a variable-length string.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
void add_bool(bool value)
Adds a boolean value to the datagram.
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
The name of a file, such as a texture file or an Egg file.
std::string get_dirname() const
Returns the directory part of the filename.
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
bool matches(const std::string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Encodes a string name in a hash table, mapping it to a pointer.
std::ostream & error(bool prefix=true) const
A shorthand way to write out(NS_error).
A table of objects that are saved within the graphics context for reference by handle later.
bool is_shader_queued(const Shader *shader) const
Returns true if the shader has been queued on this GSG, false otherwise.
bool dequeue_shader(Shader *shader)
Removes a shader from the queued list of shaders to be prepared.
void release_shader(ShaderContext *sc)
Indicates that a shader context, created by a previous call to prepare_shader(), is no longer needed.
ShaderContext * prepare_shader_now(Shader *shader, GraphicsStateGuardianBase *gsg)
Immediately creates a new ShaderContext for the indicated shader and returns it.
The ShaderContext is meant to contain the compiled version of a shader string.
void read_datagram(DatagramIterator &source)
Reads the object from a Datagram.
void write_datagram(Datagram &dg) const
Writes the contents of this object to the datagram for shipping out to a Bam file.
bool cp_errchk_parameter_varying(ShaderArgInfo &arg)
Make sure the provided parameter has the correct variance.
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.
bool get_compiled(unsigned int &format, std::string &binary) const
Called by the back-end to retrieve compiled data.
bool cp_parse_delimiter(ShaderArgInfo &arg, vector_string &pieces, int &next)
Pop a delimiter ('to' or 'rel') from the word list.
const std::string & get_text(ShaderType type=ST_none) const
Return the Shader's text for the given shader type.
void cp_report_error(ShaderArgInfo &arg, const std::string &msg)
Generate an error message including a description of the specified parameter.
void parse_init()
Set a 'parse pointer' to the beginning of the shader.
void set_compiled(unsigned int format, const char *data, size_t length)
Called by the back-end when the shader has compiled data available.
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 compile_parameter(ShaderArgInfo &p, int *arg_dim)
Analyzes a parameter and decides how to bind the parameter to some part of panda's internal state.
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 cp_errchk_parameter_uniform(ShaderArgInfo &arg)
Make sure the provided parameter has the correct variance.
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.
static void set_default_caps(const ShaderCaps &caps)
Called by the graphics back-end to specify the caps with which we will likely want to be compiling ou...
Filename get_filename_from_index(int index, ShaderType type) const
Returns the filename of the included shader with the given source file index (as recorded in the #lin...
std::string cp_parse_non_delimiter(vector_string &pieces, int &next)
Pop a non-delimiter word from the word list.
void parse_line(std::string &result, bool rt, bool lt)
Parse a line of text.
void parse_rest(std::string &result)
Returns the rest of the text from the current parse location.
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 cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi)
Make sure the provided parameter has a floating point type.
void parse_upto(std::string &result, std::string pattern, bool include)
Parse lines until you read a line that matches the specified pattern.
static void register_with_read_factory()
Tells the BamReader how to create objects of type Shader.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
bool cp_errchk_parameter_words(ShaderArgInfo &arg, int len)
Make sure the provided parameter contains the specified number of words.
bool cp_errchk_parameter_sampler(ShaderArgInfo &arg)
Make sure the provided parameter has a texture type.
bool parse_eof()
Returns true if the parse pointer is at the end of the shader.
Filename get_filename(ShaderType type=ST_none) const
Return the Shader's filename for the given shader type.
int cp_dependency(ShaderMatInput inp)
Given ShaderMatInput, returns an indication of what part or parts of the state_and_transform the Shad...
~Shader()
Delete the compiled code, if it exists.
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the texture context only on the indicated object, if it exists there.
TypeHandle is the identifier used to differentiate C++ class types.
Base class for objects that can be written to and read from Bam files.
A hierarchy of directories and files that appears to be one continuous file system,...
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 resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
The abstract base class for a file or directory within the VirtualFileSystem.
This is our own Panda specialization on the default STL map.
This is our own Panda specialization on the default STL vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void tokenize(const string &str, vector_string &words, const string &delimiters, bool discard_repeated_delimiters)
Chops the source string up into pieces delimited by any of the characters specified in delimiters.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.