33 using std::ostringstream;
40 int Shader::_shaders_generated;
43 CGcontext Shader::_cg_context = 0;
60 string dstr =
"unknown ";
61 if (p._direction == SAD_in) {
63 }
else if (p._direction == SAD_out) {
65 }
else if (p._direction == SAD_inout) {
69 string tstr =
"invalid ";
71 case SAT_scalar: tstr =
"scalar ";
break;
72 case SAT_vec1: tstr =
"vec1 ";
break;
73 case SAT_vec2: tstr =
"vec2 ";
break;
74 case SAT_vec3: tstr =
"vec3 ";
break;
75 case SAT_vec4: tstr =
"vec4 ";
break;
76 case SAT_mat1x1: tstr =
"mat1x1 ";
break;
77 case SAT_mat1x2: tstr =
"mat1x2 ";
break;
78 case SAT_mat1x3: tstr =
"mat1x3 ";
break;
79 case SAT_mat1x4: tstr =
"mat1x4 ";
break;
80 case SAT_mat2x1: tstr =
"mat2x1 ";
break;
81 case SAT_mat2x2: tstr =
"mat2x2 ";
break;
82 case SAT_mat2x3: tstr =
"mat2x3 ";
break;
83 case SAT_mat2x4: tstr =
"mat2x4 ";
break;
84 case SAT_mat3x1: tstr =
"mat3x1 ";
break;
85 case SAT_mat3x2: tstr =
"mat3x2 ";
break;
86 case SAT_mat3x3: tstr =
"mat3x3 ";
break;
87 case SAT_mat3x4: tstr =
"mat3x4 ";
break;
88 case SAT_mat4x1: tstr =
"mat4x1 ";
break;
89 case SAT_mat4x2: tstr =
"mat4x2 ";
break;
90 case SAT_mat4x3: tstr =
"mat4x3 ";
break;
91 case SAT_mat4x4: tstr =
"mat4x4 ";
break;
92 case SAT_sampler1d: tstr =
"sampler1D ";
break;
93 case SAT_sampler2d: tstr =
"sampler2D ";
break;
94 case SAT_sampler3d: tstr =
"sampler3D ";
break;
95 case SAT_sampler2d_array: tstr =
"sampler2DArray ";
break;
96 case SAT_sampler_cube: tstr =
"samplerCUBE ";
break;
97 case SAT_sampler_buffer: tstr =
"samplerBUF ";
break;
98 case SAT_sampler_cube_array:tstr =
"samplerCUBEARRAY ";
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:";
204 cp_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.";
233 if ((p._type!=SAT_sampler1d)&&
234 (p._type!=SAT_sampler2d)&&
235 (p._type!=SAT_sampler3d)&&
236 (p._type!=SAT_sampler2d_array)&&
237 (p._type!=SAT_sampler_cube)&&
238 (p._type!=SAT_sampler_buffer)&&
239 (p._type!=SAT_sampler_cube_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) {
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;
512 if (spec._func == SMF_first) {
513 spec._part[1] = SMO_INVALID;
514 spec._arg[1] =
nullptr;
516 if (spec._func == SMF_compose) {
517 if (spec._part[1] == SMO_identity) {
518 spec._func = SMF_first;
521 if (spec._func == SMF_compose) {
522 if (spec._part[0] == SMO_identity) {
523 spec._func = SMF_first;
524 spec._part[0] = spec._part[1];
525 spec._arg[0] = spec._arg[1];
530 if (spec._part[0] == SMO_model_to_view &&
531 spec._part[1] == SMO_view_to_apiclip) {
532 spec._part[0] = SMO_model_to_apiview;
533 spec._part[1] = SMO_apiview_to_apiclip;
535 }
else if (spec._part[0] == SMO_apiclip_to_view &&
536 spec._part[1] == SMO_view_to_model) {
537 spec._part[0] = SMO_apiclip_to_apiview;
538 spec._part[1] = SMO_apiview_to_model;
540 }
else if (spec._part[0] == SMO_apiview_to_view &&
541 spec._part[1] == SMO_view_to_apiclip) {
542 spec._func = SMF_first;
543 spec._part[0] = SMO_apiview_to_apiclip;
544 spec._part[1] = SMO_identity;
546 }
else if (spec._part[0] == SMO_apiclip_to_view &&
547 spec._part[1] == SMO_view_to_apiview) {
548 spec._func = SMF_first;
549 spec._part[0] = SMO_apiclip_to_apiview;
550 spec._part[1] = SMO_identity;
552 }
else if (spec._part[0] == SMO_apiview_to_view &&
553 spec._part[1] == SMO_view_to_model) {
554 spec._func = SMF_first;
555 spec._part[0] = SMO_apiview_to_model;
556 spec._part[1] = SMO_identity;
558 }
else if (spec._part[0] == SMO_model_to_view &&
559 spec._part[1] == SMO_view_to_apiview) {
560 spec._func = SMF_first;
561 spec._part[0] = SMO_model_to_apiview;
562 spec._part[1] = SMO_identity;
577 cg_recurse_parameters(CGparameter parameter,
const ShaderType &type,
580 if (parameter == 0) {
585 if (cgIsParameterReferenced(parameter)) {
586 int arg_dim[] = {1,0,0};
587 ShaderArgDir arg_dir = cg_parameter_dir(parameter);
588 ShaderArgType arg_type = cg_parameter_type(parameter);
589 ShaderArgClass arg_class = cg_parameter_class(parameter);
590 ShaderArgClass arg_subclass = arg_class;
592 CGenum vbl = cgGetParameterVariability(parameter);
593 CGtype base_type = cgGetParameterBaseType(parameter);
595 if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) {
596 switch (cgGetParameterType(parameter)) {
598 cg_recurse_parameters(
599 cgGetFirstStructParameter(parameter), type, success);
603 arg_type = cg_parameter_type(cgGetArrayParameter(parameter, 0));
604 arg_subclass = cg_parameter_class(cgGetArrayParameter(parameter, 0));
606 arg_dim[0] = cgGetArraySize(parameter, 0);
610 arg_dim[1] = cgGetParameterRows(parameter);
611 arg_dim[2] = cgGetParameterColumns(parameter);
614 p._id._name = cgGetParameterName(parameter);
617 p._class = arg_class;
618 p._subclass = arg_subclass;
620 p._direction = arg_dir;
621 p._varying = (vbl == CG_VARYING);
622 p._cat = shader_cat.get_safe_ptr();
632 p._numeric_type = SPT_uint;
638 p._numeric_type = SPT_int;
641 p._numeric_type = SPT_float;
650 }
else if (shader_cat.is_debug()) {
652 <<
"Parameter " << cgGetParameterName(parameter)
653 <<
" is unreferenced within shader " <<
get_filename(type) <<
"\n";
655 }
while((parameter = cgGetNextParameter(parameter))!= 0);
669 if (p._id._name.size() == 0)
return true;
670 if (p._id._name[0] ==
'$')
return true;
673 size_t loc = p._id._name.find_last_of(
'.');
675 string basename (p._id._name);
676 string struct_name (
"");
678 if (loc < string::npos) {
679 basename = p._id._name.substr(loc + 1);
680 struct_name = p._id._name.substr(0,loc+1);
684 vector_string pieces;
687 if (basename.size() >= 2 && basename.substr(0, 2) ==
"__") {
692 if (pieces[0] ==
"vtx") {
700 bind._append_uv = -1;
701 bind._numeric_type = p._numeric_type;
703 if (pieces.size() == 2) {
704 if (pieces[1] ==
"position") {
705 bind._name = InternalName::get_vertex();
706 bind._append_uv = -1;
707 _var_spec.push_back(bind);
710 if (pieces[1].substr(0, 8) ==
"texcoord") {
711 bind._name = InternalName::get_texcoord();
712 if (pieces[1].size() > 8) {
713 bind._append_uv = atoi(pieces[1].c_str() + 8);
715 _var_spec.push_back(bind);
718 if (pieces[1].substr(0, 7) ==
"tangent") {
719 bind._name = InternalName::get_tangent();
720 if (pieces[1].size() > 7) {
721 bind._append_uv = atoi(pieces[1].c_str() + 7);
723 _var_spec.push_back(bind);
726 if (pieces[1].substr(0, 8) ==
"binormal") {
727 bind._name = InternalName::get_binormal();
728 if (pieces[1].size() > 8) {
729 bind._append_uv = atoi(pieces[1].c_str() + 8);
731 _var_spec.push_back(bind);
734 }
else if (pieces.size() == 3) {
735 if (pieces[1] ==
"transform") {
736 if (pieces[2] ==
"blend") {
737 bind._name = InternalName::get_transform_blend();
738 _var_spec.push_back(bind);
741 if (pieces[2] ==
"index") {
742 bind._name = InternalName::get_transform_index();
743 _var_spec.push_back(bind);
746 if (pieces[2] ==
"weight") {
747 bind._name = InternalName::get_transform_weight();
748 _var_spec.push_back(bind);
754 bind._name = InternalName::get_root();
755 for (
size_t i = 1; i < pieces.size(); ++i) {
756 bind._name = bind._name->append(pieces[i]);
758 _var_spec.push_back(bind);
762 if (pieces[0] ==
"mat" && pieces[1] ==
"shadow") {
771 bind._piece = SMP_whole;
772 bind._func = SMF_compose;
773 bind._part[1] = SMO_light_source_i_attrib;
774 bind._arg[1] = InternalName::make(
"shadowViewMatrix");
775 bind._part[0] = SMO_view_to_apiview;
776 bind._arg[0] =
nullptr;
777 bind._index = atoi(pieces[2].c_str());
780 _mat_spec.push_back(bind);
781 _mat_deps |= bind._dep[0] | bind._dep[1];
788 if (pieces[0] ==
"mstrans") {
790 pieces.push_back(
"to");
791 pieces.push_back(
"model");
793 if (pieces[0] ==
"wstrans") {
795 pieces.push_back(
"to");
796 pieces.push_back(
"world");
798 if (pieces[0] ==
"vstrans") {
800 pieces.push_back(
"to");
801 pieces.push_back(
"view");
803 if (pieces[0] ==
"cstrans") {
805 pieces.push_back(
"to");
806 pieces.push_back(
"clip");
808 if (pieces[0] ==
"mspos") {
810 pieces.push_back(
"to");
811 pieces.push_back(
"model");
813 if (pieces[0] ==
"wspos") {
815 pieces.push_back(
"to");
816 pieces.push_back(
"world");
818 if (pieces[0] ==
"vspos") {
820 pieces.push_back(
"to");
821 pieces.push_back(
"view");
823 if (pieces[0] ==
"cspos") {
825 pieces.push_back(
"to");
826 pieces.push_back(
"clip");
831 if ((pieces[0] ==
"mat")||(pieces[0] ==
"inv")||
832 (pieces[0] ==
"tps")||(pieces[0] ==
"itp")) {
836 string trans = pieces[0];
837 string matrix = pieces[1];
839 if (matrix ==
"modelview") {
840 tokenize(
"trans_model_to_apiview", pieces,
"_");
841 }
else if (matrix ==
"projection") {
842 tokenize(
"trans_apiview_to_apiclip", pieces,
"_");
843 }
else if (matrix ==
"modelproj") {
844 tokenize(
"trans_model_to_apiclip", pieces,
"_");
851 }
else if (trans==
"inv") {
852 string t = pieces[1];
853 pieces[1] = pieces[3];
855 }
else if (trans==
"tps") {
857 }
else if (trans==
"itp") {
858 string t = pieces[1];
859 pieces[1] = pieces[3];
867 if ((pieces[0]==
"trans")||
868 (pieces[0]==
"tpose")||
869 (pieces[0]==
"row0")||
870 (pieces[0]==
"row1")||
871 (pieces[0]==
"row2")||
872 (pieces[0]==
"row3")||
873 (pieces[0]==
"col0")||
874 (pieces[0]==
"col1")||
875 (pieces[0]==
"col2")||
876 (pieces[0]==
"col3")) {
884 bind._piece = SMP_whole;
885 bind._func = SMF_compose;
886 bind._part[1] = SMO_light_source_i_attrib;
887 bind._arg[1] = InternalName::make(
"shadowViewMatrix");
888 bind._part[0] = SMO_view_to_apiview;
889 bind._arg[0] =
nullptr;
890 bind._index = atoi(pieces[2].c_str());
893 pieces.push_back(
"");
896 if (pieces[0]==
"trans") bind._piece = SMP_whole;
897 else if (pieces[0]==
"tpose") bind._piece = SMP_transpose;
898 else if (pieces[0]==
"row0") bind._piece = SMP_row0;
899 else if (pieces[0]==
"row1") bind._piece = SMP_row1;
900 else if (pieces[0]==
"row2") bind._piece = SMP_row2;
901 else if (pieces[0]==
"row3") bind._piece = SMP_row3;
902 else if (pieces[0]==
"col0") bind._piece = SMP_col0;
903 else if (pieces[0]==
"col1") bind._piece = SMP_col1;
904 else if (pieces[0]==
"col2") bind._piece = SMP_col2;
905 else if (pieces[0]==
"col3") bind._piece = SMP_col3;
906 if ((bind._piece == SMP_whole)||(bind._piece == SMP_transpose)) {
907 if (p._type == SAT_mat3x3) {
910 if (bind._piece == SMP_transpose) {
911 bind._piece = SMP_transpose3x3;
913 bind._piece = SMP_upper3x3;
935 _mat_spec.push_back(bind);
936 _mat_deps |= bind._dep[0] | bind._dep[1];
942 if (pieces[0] ==
"attr") {
949 if (pieces[1] ==
"material") {
954 bind._piece = SMP_transpose;
955 bind._func = SMF_first;
956 bind._part[0] = SMO_attr_material;
957 bind._arg[0] =
nullptr;
958 bind._part[1] = SMO_identity;
959 bind._arg[1] =
nullptr;
960 }
else if (pieces[1] ==
"color") {
965 bind._piece = SMP_row3;
966 bind._func = SMF_first;
967 bind._part[0] = SMO_attr_color;
968 bind._arg[0] =
nullptr;
969 bind._part[1] = SMO_identity;
970 bind._arg[1] =
nullptr;
971 }
else if (pieces[1] ==
"colorscale") {
976 bind._piece = SMP_row3;
977 bind._func = SMF_first;
978 bind._part[0] = SMO_attr_colorscale;
979 bind._arg[0] =
nullptr;
980 bind._part[1] = SMO_identity;
981 bind._arg[1] =
nullptr;
982 }
else if (pieces[1] ==
"fog") {
987 bind._piece = SMP_row3;
988 bind._func = SMF_first;
989 bind._part[0] = SMO_attr_fog;
990 bind._arg[0] =
nullptr;
991 bind._part[1] = SMO_identity;
992 bind._arg[1] =
nullptr;
993 }
else if (pieces[1] ==
"fogcolor") {
998 bind._piece = SMP_row3;
999 bind._func = SMF_first;
1000 bind._part[0] = SMO_attr_fogcolor;
1001 bind._arg[0] =
nullptr;
1002 bind._part[1] = SMO_identity;
1003 bind._arg[1] =
nullptr;
1004 }
else if (pieces[1] ==
"ambient") {
1009 bind._piece = SMP_row3;
1010 bind._func = SMF_first;
1011 bind._part[0] = SMO_light_ambient;
1012 bind._arg[0] =
nullptr;
1013 bind._part[1] = SMO_identity;
1014 bind._arg[1] =
nullptr;
1015 }
else if (pieces[1].compare(0, 5,
"light") == 0) {
1020 bind._piece = SMP_transpose;
1021 bind._func = SMF_first;
1022 bind._part[0] = SMO_light_source_i_packed;
1023 bind._arg[0] =
nullptr;
1024 bind._part[1] = SMO_identity;
1025 bind._arg[1] =
nullptr;
1026 bind._index = atoi(pieces[1].c_str() + 5);
1027 }
else if (pieces[1].compare(0, 5,
"lspec") == 0) {
1032 bind._piece = SMP_row3;
1033 bind._func = SMF_first;
1034 bind._part[0] = SMO_light_source_i_attrib;
1035 bind._arg[0] = InternalName::make(
"specular");
1036 bind._part[1] = SMO_identity;
1037 bind._arg[1] =
nullptr;
1038 bind._index = atoi(pieces[1].c_str() + 5);
1045 _mat_spec.push_back(bind);
1046 _mat_deps |= bind._dep[0] | bind._dep[1];
1050 if (pieces[0] ==
"color") {
1059 _mat_spec.push_back(bind);
1060 _mat_deps |= bind._dep[0] | bind._dep[1];
1066 if (pieces[0] ==
"alight") {
1075 bind._piece = SMP_row3;
1076 bind._func = SMF_first;
1077 bind._part[0] = SMO_alight_x;
1078 bind._arg[0] = InternalName::make(pieces[1]);
1079 bind._part[1] = SMO_identity;
1080 bind._arg[1] =
nullptr;
1083 _mat_spec.push_back(bind);
1084 _mat_deps |= bind._dep[0] | bind._dep[1];
1088 if (pieces[0] ==
"satten") {
1097 bind._piece = SMP_row3;
1098 bind._func = SMF_first;
1099 bind._part[0] = SMO_satten_x;
1100 bind._arg[0] = InternalName::make(pieces[1]);
1101 bind._part[1] = SMO_identity;
1102 bind._arg[1] =
nullptr;
1105 _mat_spec.push_back(bind);
1106 _mat_deps |= bind._dep[0] | bind._dep[1];
1110 if ((pieces[0]==
"dlight")||(pieces[0]==
"plight")||(pieces[0]==
"slight")) {
1118 bind._piece = SMP_transpose;
1120 pieces.push_back(
"");
1121 if (pieces[next] ==
"") {
1125 if (pieces[0] ==
"dlight") {
1126 bind._func = SMF_transform_dlight;
1127 bind._part[0] = SMO_dlight_x;
1128 }
else if (pieces[0] ==
"plight") {
1129 bind._func = SMF_transform_plight;
1130 bind._part[0] = SMO_plight_x;
1131 }
else if (pieces[0] ==
"slight") {
1132 bind._func = SMF_transform_slight;
1133 bind._part[0] = SMO_slight_x;
1135 bind._arg[0] = InternalName::make(pieces[next]);
1147 _mat_spec.push_back(bind);
1148 _mat_deps |= bind._dep[0] | bind._dep[1];
1152 if (pieces[0] ==
"texmat") {
1161 bind._piece = SMP_whole;
1162 bind._func = SMF_first;
1163 bind._part[0] = SMO_texmat_i;
1164 bind._arg[0] =
nullptr;
1165 bind._part[1] = SMO_identity;
1166 bind._arg[1] =
nullptr;
1167 bind._index = atoi(pieces[1].c_str());
1170 _mat_spec.push_back(bind);
1171 _mat_deps |= bind._dep[0] | bind._dep[1];
1175 if (pieces[0] ==
"texscale") {
1184 bind._piece = SMP_row3;
1185 bind._func = SMF_first;
1186 bind._part[0] = SMO_texscale_i;
1187 bind._arg[0] =
nullptr;
1188 bind._part[1] = SMO_identity;
1189 bind._arg[1] =
nullptr;
1190 bind._index = atoi(pieces[1].c_str());
1193 _mat_spec.push_back(bind);
1194 _mat_deps |= bind._dep[0] | bind._dep[1];
1198 if (pieces[0] ==
"texcolor") {
1207 bind._piece = SMP_row3;
1208 bind._func = SMF_first;
1209 bind._part[0] = SMO_texcolor_i;
1210 bind._arg[0] =
nullptr;
1211 bind._part[1] = SMO_identity;
1212 bind._arg[1] =
nullptr;
1213 bind._index = atoi(pieces[1].c_str());
1216 _mat_spec.push_back(bind);
1217 _mat_deps |= bind._dep[0] | bind._dep[1];
1221 if (pieces[0] ==
"plane") {
1230 bind._piece = SMP_row3;
1231 bind._func = SMF_first;
1232 bind._part[0] = SMO_plane_x;
1233 bind._arg[0] = InternalName::make(pieces[1]);
1234 bind._part[1] = SMO_identity;
1235 bind._arg[1] =
nullptr;
1238 _mat_spec.push_back(bind);
1239 _mat_deps |= bind._dep[0] | bind._dep[1];
1243 if (pieces[0] ==
"clipplane") {
1252 bind._piece = SMP_row3;
1253 bind._func = SMF_first;
1254 bind._part[0] = SMO_clipplane_x;
1255 bind._arg[0] = InternalName::make(pieces[1]);
1256 bind._part[1] = SMO_identity;
1257 bind._arg[1] =
nullptr;
1260 _mat_spec.push_back(bind);
1261 _mat_deps |= bind._dep[0] | bind._dep[1];
1267 if (pieces[0] ==
"sys") {
1275 bind._piece = SMP_row3;
1276 bind._func = SMF_first;
1277 bind._part[1] = SMO_identity;
1278 bind._arg[1] =
nullptr;
1279 if (pieces[1] ==
"pixelsize") {
1283 bind._part[0] = SMO_pixel_size;
1284 bind._arg[0] =
nullptr;
1286 }
else if (pieces[1] ==
"windowsize") {
1290 bind._part[0] = SMO_window_size;
1291 bind._arg[0] =
nullptr;
1293 }
else if (pieces[1] ==
"time") {
1297 bind._piece = SMP_row3x1;
1298 bind._part[0] = SMO_frame_time;
1299 bind._arg[0] =
nullptr;
1307 _mat_spec.push_back(bind);
1308 _mat_deps |= bind._dep[0] | bind._dep[1];
1314 if (pieces[0] ==
"tex") {
1319 if ((pieces.size() != 2)&&(pieces.size() != 3)) {
1325 bind._name =
nullptr;
1326 bind._stage = atoi(pieces[1].c_str());
1327 bind._part = STO_stage_i;
1329 case SAT_sampler1d: bind._desired_type = Texture::TT_1d_texture;
break;
1330 case SAT_sampler2d: bind._desired_type = Texture::TT_2d_texture;
break;
1331 case SAT_sampler3d: bind._desired_type = Texture::TT_3d_texture;
break;
1332 case SAT_sampler2d_array:bind._desired_type = Texture::TT_2d_texture_array;
break;
1333 case SAT_sampler_cube: bind._desired_type = Texture::TT_cube_map;
break;
1334 case SAT_sampler_buffer: bind._desired_type = Texture::TT_buffer_texture;
break;
1335 case SAT_sampler_cube_array:bind._desired_type = Texture::TT_cube_map_array;
break;
1340 if (pieces.size() == 3) {
1341 bind._suffix = InternalName::make(((
string)
"-") + pieces[2]);
1342 shader_cat.warning()
1343 <<
"Parameter " << p._id._name <<
": use of a texture suffix is deprecated.\n";
1345 _tex_spec.push_back(bind);
1349 if (pieces[0] ==
"shadow") {
1354 if (pieces.size() != 2) {
1360 bind._name =
nullptr;
1361 bind._stage = atoi(pieces[1].c_str());
1362 bind._part = STO_light_i_shadow_map;
1364 case SAT_sampler2d: bind._desired_type = Texture::TT_2d_texture;
break;
1365 case SAT_sampler_cube: bind._desired_type = Texture::TT_cube_map;
break;
1370 _tex_spec.push_back(bind);
1376 if (pieces[0] ==
"texpad") {
1385 bind._piece = SMP_row3;
1386 bind._func = SMF_first;
1387 bind._part[0] = SMO_texpad_x;
1388 bind._arg[0] = InternalName::make(pieces[1]);
1389 bind._part[1] = SMO_identity;
1390 bind._arg[1] =
nullptr;
1392 _mat_spec.push_back(bind);
1393 _mat_deps |= bind._dep[0] | bind._dep[1];
1397 if (pieces[0] ==
"texpix") {
1406 bind._piece = SMP_row3;
1407 bind._func = SMF_first;
1408 bind._part[0] = SMO_texpix_x;
1409 bind._arg[0] = InternalName::make(pieces[1]);
1410 bind._part[1] = SMO_identity;
1411 bind._arg[1] =
nullptr;
1413 _mat_spec.push_back(bind);
1414 _mat_deps |= bind._dep[0] | bind._dep[1];
1418 if (pieces[0] ==
"tbl") {
1423 if (pieces[0] ==
"l") {
1428 if (pieces[0] ==
"o") {
1439 bool k_prefix =
false;
1442 if (pieces[0] ==
"k") {
1444 basename = basename.substr(2);
1447 PT(
InternalName) kinputname = InternalName::make(struct_name + basename);
1454 if (!cp_errchk_parameter_ptr(p))
1459 bind._arg = kinputname;
1465 bind._dep[0] = SSD_general | SSD_shaderinputs | SSD_frame;
1466 bind._dep[1] = SSD_NONE;
1468 memcpy(bind._dim,arg_dim,
sizeof(
int)*3);
1471 if (k_prefix) bind._dim[0] = -1;
1472 _ptr_spec.push_back(bind);
1478 case SAT_sampler1d: {
1481 bind._name = kinputname;
1482 bind._part = STO_named_input;
1483 bind._desired_type = Texture::TT_1d_texture;
1484 _tex_spec.push_back(bind);
1487 case SAT_sampler2d: {
1490 bind._name = kinputname;
1491 bind._part = STO_named_input;
1492 bind._desired_type = Texture::TT_2d_texture;
1493 _tex_spec.push_back(bind);
1496 case SAT_sampler3d: {
1499 bind._name = kinputname;
1500 bind._part = STO_named_input;
1501 bind._desired_type = Texture::TT_3d_texture;
1502 _tex_spec.push_back(bind);
1505 case SAT_sampler2d_array: {
1508 bind._name = kinputname;
1509 bind._part = STO_named_input;
1510 bind._desired_type = Texture::TT_2d_texture_array;
1511 _tex_spec.push_back(bind);
1514 case SAT_sampler_cube: {
1517 bind._name = kinputname;
1518 bind._part = STO_named_input;
1519 bind._desired_type = Texture::TT_cube_map;
1520 _tex_spec.push_back(bind);
1523 case SAT_sampler_buffer: {
1526 bind._name = kinputname;
1527 bind._part = STO_named_input;
1528 bind._desired_type = Texture::TT_buffer_texture;
1529 _tex_spec.push_back(bind);
1532 case SAT_sampler_cube_array: {
1535 bind._name = kinputname;
1536 bind._part = STO_named_input;
1537 bind._desired_type = Texture::TT_cube_map_array;
1538 _tex_spec.push_back(bind);
1559 clear_parameters() {
1569 set_compiled(
unsigned int format,
const char *data,
size_t length) {
1570 _compiled_format = format;
1571 _compiled_binary.assign(data, length);
1574 if (_cache_compiled_shader && !_record.is_null()) {
1575 _record->set_data(
this);
1578 cache->
store(_record);
1586 get_compiled(
unsigned int &format,
string &binary)
const {
1587 format = _compiled_format;
1588 binary = _compiled_binary;
1589 return !binary.empty();
1598 _default_caps = caps;
1605 Shader::ShaderArgType Shader::
1606 cg_parameter_type(CGparameter p) {
1607 switch (cgGetParameterClass(p)) {
1608 case CG_PARAMETERCLASS_SCALAR:
return SAT_scalar;
1609 case CG_PARAMETERCLASS_VECTOR:
1610 switch (cgGetParameterColumns(p)) {
1611 case 1:
return SAT_vec1;
1612 case 2:
return SAT_vec2;
1613 case 3:
return SAT_vec3;
1614 case 4:
return SAT_vec4;
1615 default:
return SAT_unknown;
1617 case CG_PARAMETERCLASS_MATRIX:
1618 switch (cgGetParameterRows(p)) {
1620 switch (cgGetParameterColumns(p)) {
1621 case 1:
return SAT_mat1x1;
1622 case 2:
return SAT_mat1x2;
1623 case 3:
return SAT_mat1x3;
1624 case 4:
return SAT_mat1x4;
1625 default:
return SAT_unknown;
1628 switch (cgGetParameterColumns(p)) {
1629 case 1:
return SAT_mat2x1;
1630 case 2:
return SAT_mat2x2;
1631 case 3:
return SAT_mat2x3;
1632 case 4:
return SAT_mat2x4;
1633 default:
return SAT_unknown;
1636 switch (cgGetParameterColumns(p)) {
1637 case 1:
return SAT_mat3x1;
1638 case 2:
return SAT_mat3x2;
1639 case 3:
return SAT_mat3x3;
1640 case 4:
return SAT_mat3x4;
1641 default:
return SAT_unknown;
1644 switch (cgGetParameterColumns(p)) {
1645 case 1:
return SAT_mat4x1;
1646 case 2:
return SAT_mat4x2;
1647 case 3:
return SAT_mat4x3;
1648 case 4:
return SAT_mat4x4;
1649 default:
return SAT_unknown;
1651 default:
return SAT_unknown;
1653 case CG_PARAMETERCLASS_SAMPLER:
1654 switch (cgGetParameterType(p)) {
1655 case CG_SAMPLER1D:
return Shader::SAT_sampler1d;
1656 case CG_SAMPLER2D:
return Shader::SAT_sampler2d;
1657 case CG_SAMPLER3D:
return Shader::SAT_sampler3d;
1658 case CG_SAMPLER2DARRAY:
return Shader::SAT_sampler2d_array;
1659 case CG_SAMPLERCUBE:
return Shader::SAT_sampler_cube;
1660 case CG_SAMPLERBUF:
return Shader::SAT_sampler_buffer;
1661 case CG_SAMPLERCUBEARRAY:
return Shader::SAT_sampler_cube_array;
1663 case 1313:
return Shader::SAT_sampler1d;
1664 case 1314:
return Shader::SAT_sampler2d;
1665 default:
return SAT_unknown;
1667 case CG_PARAMETERCLASS_ARRAY:
return SAT_unknown;
1676 Shader::ShaderArgClass Shader::cg_parameter_class(CGparameter p) {
1677 switch (cgGetParameterClass(p)) {
1678 case CG_PARAMETERCLASS_SCALAR:
return Shader::SAC_scalar;
1679 case CG_PARAMETERCLASS_VECTOR:
return Shader::SAC_vector;
1680 case CG_PARAMETERCLASS_MATRIX:
return Shader::SAC_matrix;
1681 case CG_PARAMETERCLASS_SAMPLER:
return Shader::SAC_sampler;
1682 case CG_PARAMETERCLASS_ARRAY:
return Shader::SAC_array;
1683 default:
return Shader::SAC_unknown;
1690 Shader::ShaderArgDir Shader::
1691 cg_parameter_dir(CGparameter p) {
1692 switch (cgGetParameterDirection(p)) {
1693 case CG_IN:
return Shader::SAD_in;
1694 case CG_OUT:
return Shader::SAD_out;
1695 case CG_INOUT:
return Shader::SAD_inout;
1696 default:
return Shader::SAD_unknown;
1704 cg_release_resources() {
1705 if (_cg_vprogram != 0) {
1706 cgDestroyProgram(_cg_vprogram);
1709 if (_cg_fprogram != 0) {
1710 cgDestroyProgram(_cg_fprogram);
1713 if (_cg_gprogram != 0) {
1714 cgDestroyProgram(_cg_gprogram);
1723 cg_compile_entry_point(
const char *entry,
const ShaderCaps &caps,
1724 CGcontext context, ShaderType type) {
1727 const char *compiler_args[100];
1728 const string text =
get_text(type);
1731 int active, ultimate;
1735 active = caps._active_vprofile;
1736 ultimate = caps._ultimate_vprofile;
1740 active = caps._active_fprofile;
1741 ultimate = caps._ultimate_fprofile;
1745 active = caps._active_gprofile;
1746 ultimate = caps._ultimate_gprofile;
1749 case ST_tess_evaluation:
1750 case ST_tess_control:
1751 active = caps._active_tprofile;
1752 ultimate = caps._ultimate_tprofile;
1757 active = CG_PROFILE_UNKNOWN;
1758 ultimate = CG_PROFILE_UNKNOWN;
1761 if (type == ST_fragment && caps._bug_list.count(SBUG_ati_draw_buffers)) {
1762 compiler_args[nargs++] =
"-po";
1763 compiler_args[nargs++] =
"ATI_draw_buffers";
1767 if (!cg_glsl_version.empty() && active != CG_PROFILE_UNKNOWN &&
1768 cgGetProfileProperty((CGprofile) active, CG_IS_GLSL_PROFILE)) {
1770 version_arg =
"version=";
1771 version_arg += cg_glsl_version;
1773 compiler_args[nargs++] =
"-po";
1774 compiler_args[nargs++] = version_arg.c_str();
1777 compiler_args[nargs] = 0;
1781 if ((active != (
int)CG_PROFILE_UNKNOWN) && (active != ultimate)) {
1783 if (shader_cat.is_debug()) {
1785 <<
"Compiling Cg shader " <<
get_filename(type) <<
" with entry point " << entry
1786 <<
" and active profile " << cgGetProfileString((CGprofile) active) <<
"\n";
1789 shader_cat.debug() <<
"Using compiler arguments:";
1790 for (
int i = 0; i < nargs; ++i) {
1791 shader_cat.debug(
false) <<
" " << compiler_args[i];
1793 shader_cat.debug(
false) <<
"\n";
1798 prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
1799 (CGprofile)active, entry, (
const char **)compiler_args);
1801 if (err == CG_NO_ERROR) {
1805 cgDestroyProgram(prog);
1807 if (shader_cat.is_debug()) {
1809 <<
"Compilation with active profile failed: " << cgGetErrorString(err) <<
"\n";
1810 if (err == CG_COMPILER_ERROR) {
1811 const char *listing = cgGetLastListing(context);
1812 if (listing !=
nullptr) {
1813 shader_cat.debug(
false) << listing;
1819 if (shader_cat.is_debug()) {
1821 <<
"Compiling Cg shader " <<
get_filename(type) <<
" with entry point " << entry
1822 <<
" and ultimate profile " << cgGetProfileString((CGprofile) ultimate) <<
"\n";
1826 prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
1827 (CGprofile)ultimate, entry,
nullptr);
1831 const char *listing = cgGetLastListing(context);
1833 if (err == CG_NO_ERROR && listing !=
nullptr && strlen(listing) > 1) {
1834 shader_cat.warning()
1835 <<
"Encountered warnings during compilation of " <<
get_filename(type)
1836 <<
":\n" << listing;
1838 }
else if (err == CG_COMPILER_ERROR) {
1840 <<
"Failed to compile Cg shader " <<
get_filename(type);
1841 if (listing !=
nullptr) {
1842 shader_cat.error(
false) <<
":\n" << listing;
1844 shader_cat.error(
false) <<
"!\n";
1848 if (err == CG_NO_ERROR) {
1852 if (shader_cat.is_debug()) {
1854 <<
"Compilation with ultimate profile failed: " << cgGetErrorString(err) <<
"\n";
1858 cgDestroyProgram(prog);
1869 cg_compile_shader(
const ShaderCaps &caps, CGcontext context) {
1870 _cg_last_caps = caps;
1872 if (!_text._separate || !_text._vertex.empty()) {
1873 _cg_vprogram = cg_compile_entry_point(
"vshader", caps, context, ST_vertex);
1874 if (_cg_vprogram == 0) {
1875 cg_release_resources();
1878 _cg_vprofile = cgGetProgramProfile(_cg_vprogram);
1881 if (!_text._separate || !_text._fragment.empty()) {
1882 _cg_fprogram = cg_compile_entry_point(
"fshader", caps, context, ST_fragment);
1883 if (_cg_fprogram == 0) {
1884 cg_release_resources();
1887 _cg_fprofile = cgGetProgramProfile(_cg_fprogram);
1890 if ((_text._separate && !_text._geometry.empty()) || (!_text._separate && _text._shared.find(
"gshader") != string::npos)) {
1891 _cg_gprogram = cg_compile_entry_point(
"gshader", caps, context, ST_geometry);
1892 if (_cg_gprogram == 0) {
1893 cg_release_resources();
1896 _cg_gprofile = cgGetProgramProfile(_cg_gprogram);
1899 if (_cg_vprogram == 0 && _cg_fprogram == 0 && _cg_gprogram == 0) {
1900 shader_cat.error() <<
"Shader must at least have one program!\n";
1901 cg_release_resources();
1909 if (_cg_fprofile == CG_PROFILE_PS_2_0 ||
1910 _cg_fprofile == CG_PROFILE_PS_2_X ||
1911 _cg_fprofile == CG_PROFILE_PS_3_0) {
1912 vector_string lines;
1913 tokenize(cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM), lines,
"\n");
1916 int num_modified = 0;
1918 for (
size_t i = 0; i < lines.size(); ++i) {
1919 const string &line = lines[i];
1921 size_t space = line.find(
' ');
1922 if (space == string::npos) {
1923 out << line <<
'\n';
1927 string instr = line.substr(0, space);
1930 if (instr.compare(0, 5,
"texld") == 0 &&
1931 instr.compare(instr.size() - 4, 4,
"_sat") == 0) {
1933 string reg = line.substr(space + 1, line.find(
',', space) - space - 1);
1936 instr.resize(instr.size() - 4);
1937 out << instr <<
' ' << line.substr(space + 1) <<
'\n';
1938 out <<
"mov_sat " << reg <<
", " << reg <<
'\n';
1941 out << line <<
'\n';
1945 if (num_modified > 0) {
1946 string result = out.str();
1947 CGprogram new_program;
1948 new_program = cgCreateProgram(context, CG_OBJECT, result.c_str(),
1949 (CGprofile)_cg_fprofile,
"fshader",
1952 cgDestroyProgram(_cg_fprogram);
1953 _cg_fprogram = new_program;
1955 if (shader_cat.is_debug()) {
1957 <<
"Replaced " << num_modified <<
" invalid texld_sat instruction"
1958 << ((num_modified == 1) ?
"" :
"s") <<
" in compiled shader\n";
1961 shader_cat.warning()
1962 <<
"Failed to load shader with fixed texld_sat instructions: "
1963 << cgGetErrorString(cgGetError()) <<
"\n";
1969 if (shader_cat.is_debug()) {
1970 const char *vertex_program;
1971 const char *fragment_program;
1972 const char *geometry_program;
1974 if (_cg_vprogram != 0) {
1976 <<
"Cg vertex profile: " << cgGetProfileString((CGprofile)_cg_vprofile) <<
"\n";
1977 vertex_program = cgGetProgramString(_cg_vprogram, CG_COMPILED_PROGRAM);
1978 shader_cat.spam() << vertex_program <<
"\n";
1980 if (_cg_fprogram != 0) {
1982 <<
"Cg fragment profile: " << cgGetProfileString((CGprofile)_cg_fprofile) <<
"\n";
1983 fragment_program = cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM);
1984 shader_cat.spam() << fragment_program <<
"\n";
1986 if (_cg_gprogram != 0) {
1988 <<
"Cg geometry profile: " << cgGetProfileString((CGprofile)_cg_gprofile) <<
"\n";
1989 geometry_program = cgGetProgramString(_cg_gprogram, CG_COMPILED_PROGRAM);
1990 shader_cat.spam() << geometry_program <<
"\n";
2001 cg_analyze_entry_point(CGprogram prog, ShaderType type) {
2002 bool success =
true;
2004 cg_recurse_parameters(cgGetFirstParameter(prog, CG_PROGRAM), type, success);
2033 cg_analyze_shader(
const ShaderCaps &caps) {
2036 if (_cg_context == 0) {
2037 _cg_context = cgCreateContext();
2038 if (_cg_context == 0) {
2040 <<
"Could not create a Cg context object: "
2041 << cgGetErrorString(cgGetError()) <<
"\n";
2046 if (!cg_compile_shader(caps, _cg_context)) {
2050 if (_cg_fprogram != 0) {
2051 if (!cg_analyze_entry_point(_cg_fprogram, ST_fragment)) {
2052 cg_release_resources();
2058 if (_var_spec.size() != 0) {
2059 shader_cat.error() <<
"Cannot use vtx parameters in an fshader\n";
2060 cg_release_resources();
2065 if (_cg_vprogram != 0) {
2066 if (!cg_analyze_entry_point(_cg_vprogram, ST_vertex)) {
2067 cg_release_resources();
2073 if (_cg_gprogram != 0) {
2074 if (!cg_analyze_entry_point(_cg_gprogram, ST_geometry)) {
2075 cg_release_resources();
2084 for (
size_t i = 0; i < _var_spec.size(); ++i) {
2085 _var_spec[i]._id._seqno = seqno++;
2087 for (
size_t i = 0; i < _mat_spec.size(); ++i) {
2088 _mat_spec[i]._id._seqno = seqno++;
2090 for (
size_t i = 0; i < _tex_spec.size(); ++i) {
2091 _tex_spec[i]._id._seqno = seqno++;
2094 for (
size_t i = 0; i < _ptr_spec.size(); ++i) {
2095 _ptr_spec[i]._id._seqno = seqno++;
2096 _ptr_spec[i]._info._id = _ptr_spec[i]._id;
2174 cg_release_resources();
2182 cg_program_from_shadertype(ShaderType type) {
2185 return _cg_vprogram;
2188 return _cg_fprogram;
2191 return _cg_gprogram;
2204 cg_compile_for(
const ShaderCaps &caps, CGcontext context,
2208 combined_program = 0;
2214 _default_caps = caps;
2215 if (!cg_compile_shader(caps, context)) {
2221 if (_cg_vprogram != 0 && _cg_vprofile != caps._active_vprofile) {
2222 shader_cat.error() <<
"Cg vertex program not supported by profile "
2223 << cgGetProfileString((CGprofile) caps._active_vprofile) <<
": "
2224 <<
get_filename(ST_vertex) <<
". Try choosing a different profile.\n";
2227 if (_cg_fprogram != 0 && _cg_fprofile != caps._active_fprofile) {
2228 shader_cat.error() <<
"Cg fragment program not supported by profile "
2229 << cgGetProfileString((CGprofile) caps._active_fprofile) <<
": "
2230 <<
get_filename(ST_fragment) <<
". Try choosing a different profile.\n";
2233 if (_cg_gprogram != 0 && _cg_gprofile != caps._active_gprofile) {
2234 shader_cat.error() <<
"Cg geometry program not supported by profile "
2235 << cgGetProfileString((CGprofile) caps._active_gprofile) <<
": "
2236 <<
get_filename(ST_geometry) <<
". Try choosing a different profile.\n";
2242 if (_cg_vprogram != 0) {
2243 programs.push_back(_cg_vprogram);
2245 if (_cg_fprogram != 0) {
2246 programs.push_back(_cg_fprogram);
2248 if (_cg_gprogram != 0) {
2249 programs.push_back(_cg_gprogram);
2255 combined_program = cgCombinePrograms(programs.size(), &programs[0]);
2258 size_t n_mat = _mat_spec.size();
2259 size_t n_tex = _tex_spec.size();
2260 size_t n_var = _var_spec.size();
2261 size_t n_ptr = _ptr_spec.size();
2263 map.resize(n_mat + n_tex + n_var + n_ptr);
2267 CGprogram programs_by_type[ST_COUNT];
2268 for (
int i = 0; i < cgGetNumProgramDomains(combined_program); ++i) {
2270 CGprogram program = cgGetProgramDomainProgram(combined_program, i);
2271 programs_by_type[cgGetProgramDomain(program)] = program;
2274 for (
size_t i = 0; i < n_mat; ++i) {
2275 const ShaderArgId &
id = _mat_spec[i]._id;
2276 map[
id._seqno] = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
2278 if (shader_cat.is_debug()) {
2279 const char *resource = cgGetParameterResourceName(map[
id._seqno]);
2280 if (resource !=
nullptr) {
2281 shader_cat.debug() <<
"Uniform parameter " <<
id._name
2282 <<
" is bound to resource " << resource <<
"\n";
2287 for (
size_t i = 0; i < n_tex; ++i) {
2288 const ShaderArgId &
id = _tex_spec[i]._id;
2289 CGparameter p = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
2291 if (shader_cat.is_debug()) {
2292 const char *resource = cgGetParameterResourceName(p);
2293 if (resource !=
nullptr) {
2294 shader_cat.debug() <<
"Texture parameter " <<
id._name
2295 <<
" is bound to resource " << resource <<
"\n";
2301 for (
size_t i = 0; i < n_var; ++i) {
2302 const ShaderArgId &
id = _var_spec[i]._id;
2303 CGparameter p = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
2305 const char *resource = cgGetParameterResourceName(p);
2306 if (shader_cat.is_debug() && resource !=
nullptr) {
2307 if (cgGetParameterResource(p) == CG_GLSL_ATTRIB) {
2309 <<
"Varying parameter " <<
id._name <<
" is bound to GLSL attribute "
2310 << resource <<
"\n";
2313 <<
"Varying parameter " <<
id._name <<
" is bound to resource "
2314 << resource <<
" (" << cgGetParameterResource(p)
2315 <<
", index " << cgGetParameterResourceIndex(p) <<
")\n";
2322 for (
size_t i = 0; i < n_ptr; ++i) {
2323 const ShaderArgId &
id = _ptr_spec[i]._id;
2324 map[
id._seqno] = cgGetNamedParameter(programs_by_type[
id._type],
id._name.c_str());
2326 if (shader_cat.is_debug()) {
2327 const char *resource = cgGetParameterResourceName(map[
id._seqno]);
2328 if (resource !=
nullptr) {
2329 shader_cat.debug() <<
"Uniform ptr parameter " <<
id._name
2330 <<
" is bound to resource " << resource <<
"\n";
2336 if (_cg_vprogram != 0) {
2337 cgDestroyProgram(_cg_vprogram);
2340 if (_cg_fprogram != 0) {
2341 cgDestroyProgram(_cg_fprogram);
2344 if (_cg_gprogram != 0) {
2345 cgDestroyProgram(_cg_gprogram);
2349 _cg_last_caps.clear();
2359 Shader(ShaderLanguage lang) :
2366 _cache_compiled_shader(false)
2372 _cg_vprofile = CG_PROFILE_UNKNOWN;
2373 _cg_fprofile = CG_PROFILE_UNKNOWN;
2374 _cg_gprofile = CG_PROFILE_UNKNOWN;
2375 if (_default_caps._ultimate_vprofile == 0 || _default_caps._ultimate_vprofile == CG_PROFILE_UNKNOWN) {
2376 if (basic_shaders_only) {
2377 _default_caps._active_vprofile = CG_PROFILE_ARBVP1;
2378 _default_caps._active_fprofile = CG_PROFILE_ARBFP1;
2379 _default_caps._active_gprofile = CG_PROFILE_UNKNOWN;
2381 _default_caps._active_vprofile = CG_PROFILE_UNKNOWN;
2382 _default_caps._active_fprofile = CG_PROFILE_UNKNOWN;
2383 _default_caps._active_gprofile = CG_PROFILE_UNKNOWN;
2385 _default_caps._ultimate_vprofile = cgGetProfile(
"glslv");
2386 _default_caps._ultimate_fprofile = cgGetProfile(
"glslf");
2387 _default_caps._ultimate_gprofile = cgGetProfile(
"glslg");
2388 if (_default_caps._ultimate_gprofile == CG_PROFILE_UNKNOWN) {
2389 _default_caps._ultimate_gprofile = cgGetProfile(
"gp4gp");
2401 _text._separate = sfile._separate;
2403 if (sfile._separate) {
2404 if (_language == SL_none) {
2406 <<
"No shader language was specified!\n";
2410 if (!sfile._vertex.empty() &&
2411 !do_read_source(_text._vertex, sfile._vertex, record)) {
2414 if (!sfile._fragment.empty() &&
2415 !do_read_source(_text._fragment, sfile._fragment, record)) {
2418 if (!sfile._geometry.empty() &&
2419 !do_read_source(_text._geometry, sfile._geometry, record)) {
2422 if (!sfile._tess_control.empty() &&
2423 !do_read_source(_text._tess_control, sfile._tess_control, record)) {
2426 if (!sfile._tess_evaluation.empty() &&
2427 !do_read_source(_text._tess_evaluation, sfile._tess_evaluation, record)) {
2430 if (!sfile._compute.empty() &&
2431 !do_read_source(_text._compute, sfile._compute, record)) {
2437 if (!do_read_source(_text._shared, sfile._shared, record)) {
2440 _fullpath = _source_files[0];
2444 if (_language == SL_none) {
2448 if (header ==
"//Cg") {
2452 <<
"Unable to determine shader language of " << sfile._shared <<
"\n";
2455 }
else if (_language == SL_GLSL) {
2457 <<
"GLSL shaders must have separate shader bodies!\n";
2462 if (_language == SL_Cg) {
2464 ShaderCaps caps = _default_caps;
2465 cg_get_profile_from_header(caps);
2467 if (!cg_analyze_shader(caps)) {
2469 <<
"Shader encountered an error.\n";
2474 <<
"Tried to load Cg shader, but no Cg support is enabled.\n";
2478 <<
"Shader is not in a supported shader-language.\n";
2493 _filename = ShaderFile(
"created-shader");
2495 _text._separate = sbody._separate;
2497 if (sbody._separate) {
2498 if (_language == SL_none) {
2500 <<
"No shader language was specified!\n";
2504 if (!sbody._vertex.empty() &&
2505 !do_load_source(_text._vertex, sbody._vertex, record)) {
2508 if (!sbody._fragment.empty() &&
2509 !do_load_source(_text._fragment, sbody._fragment, record)) {
2512 if (!sbody._geometry.empty() &&
2513 !do_load_source(_text._geometry, sbody._geometry, record)) {
2516 if (!sbody._tess_control.empty() &&
2517 !do_load_source(_text._tess_control, sbody._tess_control, record)) {
2520 if (!sbody._tess_evaluation.empty() &&
2521 !do_load_source(_text._tess_evaluation, sbody._tess_evaluation, record)) {
2524 if (!sbody._compute.empty() &&
2525 !do_load_source(_text._compute, sbody._compute, record)) {
2530 if (!do_load_source(_text._shared, sbody._shared, record)) {
2535 if (_language == SL_none) {
2539 if (header ==
"//Cg") {
2543 <<
"Unable to determine shader language of " << sbody._shared <<
"\n";
2546 }
else if (_language == SL_GLSL) {
2548 <<
"GLSL shaders must have separate shader bodies!\n";
2553 if (_language == SL_Cg) {
2555 ShaderCaps caps = _default_caps;
2556 cg_get_profile_from_header(caps);
2558 if (!cg_analyze_shader(caps)) {
2560 <<
"Shader encountered an error.\n";
2565 <<
"Tried to load Cg shader, but no Cg support is enabled.\n";
2569 <<
"Shader is not in a supported shader-language.\n";
2588 if (vf ==
nullptr) {
2590 <<
"Could not find shader file: " << fn <<
"\n";
2594 if (_language == SL_GLSL && glsl_preprocess) {
2595 istream *source = vf->open_read_file(
true);
2596 if (source ==
nullptr) {
2598 <<
"Could not open shader file: " << fn <<
"\n";
2604 <<
"Preprocessing shader file: " << fn <<
"\n";
2606 std::set<Filename> open_files;
2608 if (!r_preprocess_source(sstr, *source, fn, vf->get_filename(), open_files, record)) {
2609 vf->close_read_file(source);
2612 vf->close_read_file(source);
2616 shader_cat.info() <<
"Reading shader file: " << fn <<
"\n";
2618 if (!vf->read_file(into,
true)) {
2620 <<
"Could not read shader file: " << fn <<
"\n";
2625 if (record !=
nullptr) {
2629 _last_modified = std::max(_last_modified, vf->get_timestamp());
2630 _source_files.push_back(vf->get_filename());
2633 while (!into.empty() && isspace(into[into.size() - 1])) {
2634 into.resize(into.size() - 1);
2651 do_load_source(
string &into,
const std::string &source,
BamCacheRecord *record) {
2652 if (_language == SL_GLSL && glsl_preprocess) {
2654 std::set<Filename> open_files;
2655 std::ostringstream sstr;
2656 std::istringstream in(source);
2658 open_files, record)) {
2668 while (!into.empty() && isspace(into[into.size() - 1])) {
2669 into.resize(into.size() - 1);
2686 r_preprocess_include(ostream &out,
const Filename &fn,
2688 std::set<Filename> &once_files,
2691 if (depth > glsl_include_recursion_limit) {
2693 <<
"GLSL includes nested too deeply, raise glsl-include-recursion-limit"
2699 if (!source_dir.empty()) {
2700 path.prepend_directory(source_dir);
2705 if (vf ==
nullptr) {
2707 <<
"Could not find shader include: " << fn <<
"\n";
2711 Filename full_fn = vf->get_filename();
2712 if (once_files.find(full_fn) != once_files.end()) {
2717 istream *source = vf->open_read_file(
true);
2718 if (source ==
nullptr) {
2720 <<
"Could not open shader include: " << fn <<
"\n";
2724 if (record !=
nullptr) {
2727 _last_modified = std::max(_last_modified, vf->get_timestamp());
2728 _source_files.push_back(full_fn);
2736 fileno = 2048 + _included_files.size();
2741 _included_files.push_back(fn);
2743 if (shader_cat.is_debug()) {
2745 <<
"Preprocessing shader include " << fileno <<
": " << fn <<
"\n";
2748 bool result = r_preprocess_source(out, *source, fn, full_fn, once_files, record, fileno, depth);
2749 vf->close_read_file(source);
2761 r_preprocess_source(ostream &out, istream &in,
const Filename &fn,
2762 const Filename &full_fn, std::set<Filename> &once_files,
2767 int ext_google_include = 0;
2768 int ext_google_line = 0;
2769 bool had_include =
false;
2770 bool had_version =
false;
2772 bool write_line_directive = (fileno != 0);
2774 while (std::getline(in, line)) {
2780 if (!write_line_directive) {
2788 while (line[line.size() - 1] ==
'\\') {
2789 line.resize(line.size() - 1);
2792 if (std::getline(in, line2)) {
2794 if (!write_line_directive) {
2805 size_t line_comment = line.find(
"//");
2806 size_t block_comment = line.find(
"/*");
2807 if (line_comment < block_comment) {
2809 line.resize(line_comment);
2811 }
else if (block_comment < line_comment) {
2813 string line2 = line.substr(block_comment + 2);
2817 line.resize(block_comment);
2820 size_t block_end = line2.find(
"*/");
2821 while (block_end == string::npos) {
2823 if (std::getline(in, line2)) {
2824 if (!write_line_directive) {
2828 block_end = line2.find(
"*/");
2831 <<
"Expected */ before end of file " << fn <<
"\n";
2836 line += line2.substr(block_end + 2);
2840 while (!line.empty() && isspace(line[line.size() - 1])) {
2841 line.resize(line.size() - 1);
2845 if (!write_line_directive) {
2853 if (line.size() < 8 || sscanf(line.c_str(),
" # %63s", directive) != 1) {
2855 if (write_line_directive) {
2856 out <<
"#line " << lineno <<
" " << fileno <<
" // " << fn <<
"\n";
2857 write_line_directive =
false;
2859 out << line <<
"\n";
2866 if (strcmp(directive,
"pragma") == 0 &&
2867 sscanf(line.c_str(),
" # pragma %63s", pragma) == 1) {
2868 if (strcmp(pragma,
"include") == 0) {
2873 if (sscanf(line.c_str(),
" # pragma%*[ \t]include \"%2047[^\"]\" %zn", incfile, &nread) == 1
2874 && nread == line.size()) {
2879 }
else if (sscanf(line.c_str(),
" # pragma%*[ \t]include <%2047[^\"]> %zn", incfile, &nread) == 1
2880 && nread == line.size()) {
2888 <<
"Malformed #pragma include at line " << lineno
2889 <<
" of file " << fn <<
":\n " << line <<
"\n";
2895 if (!r_preprocess_include(out, incfn, source_dir, once_files, record, depth + 1)) {
2897 shader_cat.error(
false) <<
"included at line "
2898 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
2903 write_line_directive =
true;
2907 }
else if (strcmp(pragma,
"once") == 0) {
2909 if (sscanf(line.c_str(),
" # pragma%*[ \t]once %zn", &nread) != 0 ||
2910 nread != line.size()) {
2912 <<
"Malformed #pragma once at line " << lineno
2913 <<
" of file " << fn <<
":\n " << line <<
"\n";
2918 shader_cat.warning()
2919 <<
"#pragma once in main file at line "
2920 << lineno <<
" of file " << fn
2927 if (!full_fn.empty()) {
2928 once_files.insert(full_fn);
2934 }
else if (strcmp(directive,
"endif") == 0) {
2938 write_line_directive =
true;
2941 }
else if (strcmp(directive,
"version") == 0) {
2944 }
else if (strcmp(directive,
"extension") == 0) {
2946 char extension[256];
2948 if (sscanf(line.c_str(),
" # extension%*[ \t]%255[^: \t] : %8s", extension, behavior) == 2) {
2951 if (strcmp(behavior,
"require") == 0 || strcmp(behavior,
"enable") == 0) {
2953 }
else if (strcmp(behavior,
"warn") == 0) {
2955 }
else if (strcmp(behavior,
"disable") == 0) {
2959 <<
"Extension directive specifies invalid behavior at line "
2960 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
2964 if (strcmp(extension,
"all") == 0) {
2967 <<
"Extension directive for 'all' may only specify 'warn' or "
2968 "'disable' at line " << lineno <<
" of file " << fn
2969 <<
":\n " << line <<
"\n";
2972 ext_google_include = mode;
2973 ext_google_line = mode;
2977 }
else if (strcmp(extension,
"GL_GOOGLE_include_directive") == 0) {
2981 ext_google_include = mode;
2982 ext_google_line = mode;
2985 }
else if (strcmp(extension,
"GL_GOOGLE_cpp_style_line_directive") == 0) {
2987 ext_google_line = mode;
2992 <<
"Failed to parse extension directive at line "
2993 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
2997 }
else if (ext_google_include > 0 && strcmp(directive,
"include") == 0) {
2999 if (ext_google_include == 1) {
3000 shader_cat.warning()
3001 <<
"Extension GL_GOOGLE_include_directive is being used at line "
3002 << lineno <<
" of file " << fn
3013 if (sscanf(line.c_str(),
" # include%*[ \t]\"%2047[^\"]\" %zn", incfile, &nread) != 1
3014 || nread != line.size()) {
3017 <<
"Malformed #include at line " << lineno
3018 <<
" of file " << fn <<
":\n " << line <<
"\n";
3026 if (!r_preprocess_include(out, incfn, source_dir, once_files, record, depth + 1)) {
3028 shader_cat.error(
false) <<
"included at line "
3029 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
3034 write_line_directive =
true;
3038 }
else if (ext_google_line > 0 && strcmp(directive,
"line") == 0) {
3041 if (sscanf(line.c_str(),
" # line%*[ \t]%d%*[ \t]\"%2047[^\"]\" %zn", &lineno, filestr, &nread) == 2
3042 && nread == line.size()) {
3044 if (ext_google_line == 1) {
3045 shader_cat.warning()
3046 <<
"Extension GL_GOOGLE_cpp_style_line_directive is being used at line "
3047 << lineno <<
" of file " << fn
3056 fileno = 2048 + _included_files.size();
3057 _included_files.push_back(
Filename(filestr));
3059 out <<
"#line " << lineno <<
" " << fileno <<
" // " << filestr <<
"\n";
3064 if (write_line_directive) {
3065 out <<
"#line " << lineno <<
" " << fileno <<
" // " << fn <<
"\n";
3066 write_line_directive =
false;
3068 out << line <<
"\n";
3071 if (fileno == 0 && !had_version) {
3072 shader_cat.warning()
3073 <<
"GLSL shader " << fn <<
" does not contain a #version line!\n";
3084 check_modified()
const {
3088 for (it = _source_files.begin(); it != _source_files.end(); ++it) {
3092 if (vfile ==
nullptr || vfile->get_timestamp() > _last_modified) {
3106 cg_get_profile_from_header(ShaderCaps& caps) {
3120 int profilePos = buf.find(
"//Cg profile");
3121 if (profilePos >= 0) {
3123 if ((
int)buf.find(
"gp4vp") >= 0)
3124 caps._active_vprofile = cgGetProfile(
"gp4vp");
3126 if ((
int)buf.find(
"gp5vp") >= 0)
3127 caps._active_vprofile = cgGetProfile(
"gp5vp");
3129 if ((
int)buf.find(
"glslv") >= 0)
3130 caps._active_vprofile = cgGetProfile(
"glslv");
3132 if ((
int)buf.find(
"arbvp1") >= 0)
3133 caps._active_vprofile = cgGetProfile(
"arbvp1");
3135 if ((
int)buf.find(
"vp40") >= 0)
3136 caps._active_vprofile = cgGetProfile(
"vp40");
3138 if ((
int)buf.find(
"vp30") >= 0)
3139 caps._active_vprofile = cgGetProfile(
"vp30");
3141 if ((
int)buf.find(
"vp20") >= 0)
3142 caps._active_vprofile = cgGetProfile(
"vp20");
3144 if ((
int)buf.find(
"vs_1_1") >= 0)
3145 caps._active_vprofile = cgGetProfile(
"vs_1_1");
3147 if ((
int)buf.find(
"vs_2_0") >= 0)
3148 caps._active_vprofile = cgGetProfile(
"vs_2_0");
3150 if ((
int)buf.find(
"vs_2_x") >= 0)
3151 caps._active_vprofile = cgGetProfile(
"vs_2_x");
3153 if ((
int)buf.find(
"vs_3_0") >= 0)
3154 caps._active_vprofile = cgGetProfile(
"vs_3_0");
3156 if ((
int)buf.find(
"vs_4_0") >= 0)
3157 caps._active_vprofile = cgGetProfile(
"vs_4_0");
3159 if ((
int)buf.find(
"vs_5_0") >= 0)
3160 caps._active_vprofile = cgGetProfile(
"vs_5_0");
3163 if ((
int)buf.find(
"gp4fp") >= 0)
3164 caps._active_fprofile = cgGetProfile(
"gp4fp");
3166 if ((
int)buf.find(
"gp5fp") >= 0)
3167 caps._active_fprofile = cgGetProfile(
"gp5fp");
3169 if ((
int)buf.find(
"glslf") >= 0)
3170 caps._active_fprofile = cgGetProfile(
"glslf");
3172 if ((
int)buf.find(
"arbfp1") >= 0)
3173 caps._active_fprofile = cgGetProfile(
"arbfp1");
3175 if ((
int)buf.find(
"fp40") >= 0)
3176 caps._active_fprofile = cgGetProfile(
"fp40");
3178 if ((
int)buf.find(
"fp30") >= 0)
3179 caps._active_fprofile = cgGetProfile(
"fp30");
3181 if ((
int)buf.find(
"fp20") >= 0)
3182 caps._active_fprofile = cgGetProfile(
"fp20");
3184 if ((
int)buf.find(
"ps_1_1") >= 0)
3185 caps._active_fprofile = cgGetProfile(
"ps_1_1");
3187 if ((
int)buf.find(
"ps_1_2") >= 0)
3188 caps._active_fprofile = cgGetProfile(
"ps_1_2");
3190 if ((
int)buf.find(
"ps_1_3") >= 0)
3191 caps._active_fprofile = cgGetProfile(
"ps_1_3");
3193 if ((
int)buf.find(
"ps_2_0") >= 0)
3194 caps._active_fprofile = cgGetProfile(
"ps_2_0");
3196 if ((
int)buf.find(
"ps_2_x") >= 0)
3197 caps._active_fprofile = cgGetProfile(
"ps_2_x");
3199 if ((
int)buf.find(
"ps_3_0") >= 0)
3200 caps._active_fprofile = cgGetProfile(
"ps_3_0");
3202 if ((
int)buf.find(
"ps_4_0") >= 0)
3203 caps._active_fprofile = cgGetProfile(
"ps_4_0");
3205 if ((
int)buf.find(
"ps_5_0") >= 0)
3206 caps._active_fprofile = cgGetProfile(
"ps_5_0");
3209 if ((
int)buf.find(
"gp4gp") >= 0)
3210 caps._active_gprofile = cgGetProfile(
"gp4gp");
3212 if ((
int)buf.find(
"gp5gp") >= 0)
3213 caps._active_gprofile = cgGetProfile(
"gp5gp");
3215 if ((
int)buf.find(
"glslg") >= 0)
3216 caps._active_gprofile = cgGetProfile(
"glslg");
3218 if ((
int)buf.find(
"gs_4_0") >= 0)
3219 caps._active_gprofile = cgGetProfile(
"gs_4_0");
3221 if ((
int)buf.find(
"gs_5_0") >= 0)
3222 caps._active_gprofile = cgGetProfile(
"gs_5_0");
3224 }
while(_parse > lastParse);
3257 }
else if (glsl_preprocess && index >= 2048 &&
3258 (index - 2048) < (
int)_included_files.size()) {
3259 return _included_files[(size_t)index - 2048];
3262 string str = format_string(index);
3270 load(
const Filename &file, ShaderLanguage lang) {
3271 ShaderFile sfile(file);
3272 ShaderTable::const_iterator i = _load_table.find(sfile);
3273 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
3275 if (i->second->check_modified()) {
3277 <<
"Shader " << file <<
" was modified on disk, reloading.\n";
3279 if (shader_cat.is_debug()) {
3281 <<
"Shader " << file <<
" was found in shader cache.\n";
3288 if (!shader->read(sfile)) {
3292 _load_table[sfile] = shader;
3294 if (cache_generated_shaders) {
3295 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3296 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3299 _make_table[shader->_text] = shader;
3308 load(ShaderLanguage lang,
const Filename &vertex,
3311 ShaderFile sfile(vertex, fragment, geometry, tess_control, tess_evaluation);
3312 ShaderTable::const_iterator i = _load_table.find(sfile);
3313 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
3315 if (i->second->check_modified()) {
3317 <<
"Shader was modified on disk, reloading.\n";
3319 if (shader_cat.is_debug()) {
3321 <<
"Shader was found in shader cache.\n";
3328 if (!shader->read(sfile)) {
3332 _load_table[sfile] = shader;
3334 if (cache_generated_shaders) {
3335 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3336 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3339 _make_table[shader->_text] = shader;
3348 load_compute(ShaderLanguage lang,
const Filename &fn) {
3349 if (lang != SL_GLSL) {
3351 <<
"Only GLSL compute shaders are currently supported.\n";
3359 <<
"Could not find compute shader file: " << fn <<
"\n";
3364 sfile._separate =
true;
3365 sfile._compute = fn;
3367 ShaderTable::const_iterator i = _load_table.find(sfile);
3368 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
3370 if (i->second->check_modified()) {
3372 <<
"Compute shader " << fn <<
" was modified on disk, reloading.\n";
3374 if (shader_cat.is_debug()) {
3376 <<
"Compute shader " << fn <<
" was found in shader cache.\n";
3384 if (record !=
nullptr) {
3385 if (record->has_data()) {
3387 <<
"Compute shader " << fn <<
" was found in disk cache.\n";
3395 if (!shader->read(sfile, record)) {
3398 _load_table[sfile] = shader;
3400 if (cache_generated_shaders) {
3401 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3402 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3405 _make_table[shader->_text] = shader;
3410 std::swap(shader->_record, record);
3412 shader->_fullpath = shader->_source_files[0];
3420 make(
string body, ShaderLanguage lang) {
3421 if (lang == SL_GLSL) {
3423 <<
"GLSL shaders must have separate shader bodies!\n";
3426 }
else if (lang == SL_none) {
3427 shader_cat.warning()
3428 <<
"Shader::make() now requires an explicit shader language. Assuming Cg.\n";
3432 if (lang == SL_Cg) {
3433 shader_cat.error() <<
"Support for Cg shaders is not enabled.\n";
3438 ShaderFile sbody(move(body));
3440 if (cache_generated_shaders) {
3441 ShaderTable::const_iterator i = _make_table.find(sbody);
3442 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3444 if (!i->second->check_modified()) {
3451 if (!shader->load(sbody)) {
3455 if (cache_generated_shaders) {
3456 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3457 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3460 _make_table[shader->_text] = shader;
3462 _make_table[std::move(sbody)] = shader;
3465 if (dump_generated_shaders) {
3467 int index = _shaders_generated ++;
3468 fns <<
"genshader" << index;
3469 string fn = fns.str();
3470 shader_cat.warning() <<
"Dumping shader: " << fn <<
"\n";
3473 s.open(fn.c_str(), std::ios::out | std::ios::trunc);
3474 s << shader->get_text();
3484 make(ShaderLanguage lang,
string vertex,
string fragment,
string geometry,
3485 string tess_control,
string tess_evaluation) {
3487 if (lang == SL_Cg) {
3488 shader_cat.error() <<
"Support for Cg shaders is not enabled.\n";
3492 if (lang == SL_none) {
3494 <<
"Shader::make() requires an explicit shader language.\n";
3498 ShaderFile sbody(move(vertex), move(fragment), move(geometry),
3499 move(tess_control), move(tess_evaluation));
3501 if (cache_generated_shaders) {
3502 ShaderTable::const_iterator i = _make_table.find(sbody);
3503 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3505 if (!i->second->check_modified()) {
3512 shader->_filename = ShaderFile(
"created-shader");
3513 if (!shader->load(sbody)) {
3517 if (cache_generated_shaders) {
3518 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3519 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3522 _make_table[shader->_text] = shader;
3524 _make_table[std::move(sbody)] = shader;
3534 make_compute(ShaderLanguage lang,
string body) {
3535 if (lang != SL_GLSL) {
3537 <<
"Only GLSL compute shaders are currently supported.\n";
3542 sbody._separate =
true;
3543 sbody._compute = move(body);
3545 if (cache_generated_shaders) {
3546 ShaderTable::const_iterator i = _make_table.find(sbody);
3547 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3549 if (!i->second->check_modified()) {
3556 shader->_filename = ShaderFile(
"created-shader");
3557 if (!shader->load(sbody)) {
3561 if (cache_generated_shaders) {
3562 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3563 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3566 _make_table[shader->_text] = shader;
3568 _make_table[std::move(sbody)] = shader;
3588 parse_line(
string &result,
bool lt,
bool rt) {
3589 nassertv(!_text._separate);
3590 int len = _text._shared.size();
3593 while ((tail < len) && (_text._shared[tail] !=
'\n')) {
3602 while ((head < tail)&&(isspace(_text._shared[head]))) head++;
3603 while ((tail > head)&&(isspace(_text._shared[tail-1]))) tail--;
3605 result = _text._shared.substr(head, tail-head);
3614 parse_upto(
string &result,
string pattern,
bool include) {
3615 nassertv(!_text._separate);
3619 while (_parse < (
int)(_text._shared.size())) {
3626 result = _text._shared.substr(start, _parse - start);
3628 result = _text._shared.substr(start, last - start);
3637 nassertv(!_text._separate);
3638 result = _text._shared.substr(_parse, _text._shared.size() - _parse);
3646 return (
int)_text._shared.size() == _parse;
3660 return prepared_objects->enqueue_shader_future(
this);
3669 Contexts::const_iterator ci;
3670 ci = _contexts.find(prepared_objects);
3671 if (ci != _contexts.end()) {
3683 Contexts::iterator ci;
3684 ci = _contexts.find(prepared_objects);
3685 if (ci != _contexts.end()) {
3687 if (sc !=
nullptr) {
3690 _contexts.erase(ci);
3713 Contexts::const_iterator ci;
3714 ci = _contexts.find(prepared_objects);
3715 if (ci != _contexts.end()) {
3716 return (*ci).second;
3720 _contexts[prepared_objects] = tc;
3733 Contexts::iterator ci;
3734 ci = _contexts.find(prepared_objects);
3735 if (ci != _contexts.end()) {
3736 _contexts.erase(ci);
3740 nassert_raise(
"unknown PreparedGraphicsObjects");
3755 int num_freed = (int)_contexts.size();
3757 Contexts::const_iterator ci;
3758 for (ci = temp.begin(); ci != temp.end(); ++ci) {
3761 if (sc !=
nullptr) {
3776 void Shader::ShaderCaps::
3778 _supports_glsl =
false;
3781 _active_vprofile = CG_PROFILE_UNKNOWN;
3782 _active_fprofile = CG_PROFILE_UNKNOWN;
3783 _active_gprofile = CG_PROFILE_UNKNOWN;
3784 _ultimate_vprofile = CG_PROFILE_UNKNOWN;
3785 _ultimate_fprofile = CG_PROFILE_UNKNOWN;
3786 _ultimate_gprofile = CG_PROFILE_UNKNOWN;
3825 attrib->fillin(scan, manager);
3835 _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.
PT(Shader) Shader
Loads the shader with the given filename.
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.