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() {
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);
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 cg_get_profile_from_header(_default_caps);
2466 if (!cg_analyze_shader(_default_caps)) {
2468 <<
"Shader encountered an error.\n";
2473 <<
"Tried to load Cg shader, but no Cg support is enabled.\n";
2477 <<
"Shader is not in a supported shader-language.\n";
2492 _filename = ShaderFile(
"created-shader");
2494 _text._separate = sbody._separate;
2496 if (sbody._separate) {
2497 if (_language == SL_none) {
2499 <<
"No shader language was specified!\n";
2503 if (!sbody._vertex.empty() &&
2504 !do_load_source(_text._vertex, sbody._vertex, record)) {
2507 if (!sbody._fragment.empty() &&
2508 !do_load_source(_text._fragment, sbody._fragment, record)) {
2511 if (!sbody._geometry.empty() &&
2512 !do_load_source(_text._geometry, sbody._geometry, record)) {
2515 if (!sbody._tess_control.empty() &&
2516 !do_load_source(_text._tess_control, sbody._tess_control, record)) {
2519 if (!sbody._tess_evaluation.empty() &&
2520 !do_load_source(_text._tess_evaluation, sbody._tess_evaluation, record)) {
2523 if (!sbody._compute.empty() &&
2524 !do_load_source(_text._compute, sbody._compute, record)) {
2529 if (!do_load_source(_text._shared, sbody._shared, record)) {
2534 if (_language == SL_none) {
2538 if (header ==
"//Cg") {
2542 <<
"Unable to determine shader language of " << sbody._shared <<
"\n";
2545 }
else if (_language == SL_GLSL) {
2547 <<
"GLSL shaders must have separate shader bodies!\n";
2552 if (_language == SL_Cg) {
2554 cg_get_profile_from_header(_default_caps);
2556 if (!cg_analyze_shader(_default_caps)) {
2558 <<
"Shader encountered an error.\n";
2563 <<
"Tried to load Cg shader, but no Cg support is enabled.\n";
2567 <<
"Shader is not in a supported shader-language.\n";
2586 if (vf ==
nullptr) {
2588 <<
"Could not find shader file: " << fn <<
"\n";
2592 if (_language == SL_GLSL && glsl_preprocess) {
2593 istream *source = vf->open_read_file(
true);
2594 if (source ==
nullptr) {
2596 <<
"Could not open shader file: " << fn <<
"\n";
2602 <<
"Preprocessing shader file: " << fn <<
"\n";
2604 std::set<Filename> open_files;
2606 if (!r_preprocess_source(sstr, *source, fn, vf->get_filename(), open_files, record)) {
2607 vf->close_read_file(source);
2610 vf->close_read_file(source);
2614 shader_cat.info() <<
"Reading shader file: " << fn <<
"\n";
2616 if (!vf->read_file(into,
true)) {
2618 <<
"Could not read shader file: " << fn <<
"\n";
2623 if (record !=
nullptr) {
2627 _last_modified = std::max(_last_modified, vf->get_timestamp());
2628 _source_files.push_back(vf->get_filename());
2631 while (!into.empty() && isspace(into[into.size() - 1])) {
2632 into.resize(into.size() - 1);
2649 do_load_source(
string &into,
const std::string &source,
BamCacheRecord *record) {
2650 if (_language == SL_GLSL && glsl_preprocess) {
2652 std::set<Filename> open_files;
2653 std::ostringstream sstr;
2654 std::istringstream in(source);
2656 open_files, record)) {
2666 while (!into.empty() && isspace(into[into.size() - 1])) {
2667 into.resize(into.size() - 1);
2684 r_preprocess_include(ostream &out,
const Filename &fn,
2686 std::set<Filename> &once_files,
2689 if (depth > glsl_include_recursion_limit) {
2691 <<
"GLSL includes nested too deeply, raise glsl-include-recursion-limit" 2697 if (!source_dir.empty()) {
2698 path.prepend_directory(source_dir);
2703 if (vf ==
nullptr) {
2705 <<
"Could not find shader include: " << fn <<
"\n";
2709 Filename full_fn = vf->get_filename();
2710 if (once_files.find(full_fn) != once_files.end()) {
2715 istream *source = vf->open_read_file(
true);
2716 if (source ==
nullptr) {
2718 <<
"Could not open shader include: " << fn <<
"\n";
2722 if (record !=
nullptr) {
2725 _last_modified = std::max(_last_modified, vf->get_timestamp());
2726 _source_files.push_back(full_fn);
2734 fileno = 2048 + _included_files.size();
2739 _included_files.push_back(fn);
2741 if (shader_cat.is_debug()) {
2743 <<
"Preprocessing shader include " << fileno <<
": " << fn <<
"\n";
2746 bool result = r_preprocess_source(out, *source, fn, full_fn, once_files, record, fileno, depth);
2747 vf->close_read_file(source);
2759 r_preprocess_source(ostream &out, istream &in,
const Filename &fn,
2760 const Filename &full_fn, std::set<Filename> &once_files,
2765 int ext_google_include = 0;
2766 int ext_google_line = 0;
2767 bool had_include =
false;
2768 bool had_version =
false;
2770 bool write_line_directive = (fileno != 0);
2772 while (std::getline(in, line)) {
2778 if (!write_line_directive) {
2786 while (line[line.size() - 1] ==
'\\') {
2787 line.resize(line.size() - 1);
2790 if (std::getline(in, line2)) {
2792 if (!write_line_directive) {
2803 size_t line_comment = line.find(
"//");
2804 size_t block_comment = line.find(
"/*");
2805 if (line_comment < block_comment) {
2807 line.resize(line_comment);
2809 }
else if (block_comment < line_comment) {
2811 string line2 = line.substr(block_comment + 2);
2815 line.resize(block_comment);
2818 size_t block_end = line2.find(
"*/");
2819 while (block_end == string::npos) {
2821 if (std::getline(in, line2)) {
2822 if (!write_line_directive) {
2826 block_end = line2.find(
"*/");
2829 <<
"Expected */ before end of file " << fn <<
"\n";
2834 line += line2.substr(block_end + 2);
2838 while (!line.empty() && isspace(line[line.size() - 1])) {
2839 line.resize(line.size() - 1);
2843 if (!write_line_directive) {
2851 if (line.size() < 8 || sscanf(line.c_str(),
" # %63s", directive) != 1) {
2853 if (write_line_directive) {
2854 out <<
"#line " << lineno <<
" " << fileno <<
" // " << fn <<
"\n";
2855 write_line_directive =
false;
2857 out << line <<
"\n";
2864 if (strcmp(directive,
"pragma") == 0 &&
2865 sscanf(line.c_str(),
" # pragma %63s", pragma) == 1) {
2866 if (strcmp(pragma,
"include") == 0) {
2871 if (sscanf(line.c_str(),
" # pragma%*[ \t]include \"%2047[^\"]\" %zn", incfile, &nread) == 1
2872 && nread == line.size()) {
2877 }
else if (sscanf(line.c_str(),
" # pragma%*[ \t]include <%2047[^\"]> %zn", incfile, &nread) == 1
2878 && nread == line.size()) {
2886 <<
"Malformed #pragma include at line " << lineno
2887 <<
" of file " << fn <<
":\n " << line <<
"\n";
2893 if (!r_preprocess_include(out, incfn, source_dir, once_files, record, depth + 1)) {
2895 shader_cat.error(
false) <<
"included at line " 2896 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
2901 write_line_directive =
true;
2905 }
else if (strcmp(pragma,
"once") == 0) {
2907 if (sscanf(line.c_str(),
" # pragma%*[ \t]once %zn", &nread) != 0 ||
2908 nread != line.size()) {
2910 <<
"Malformed #pragma once at line " << lineno
2911 <<
" of file " << fn <<
":\n " << line <<
"\n";
2916 shader_cat.warning()
2917 <<
"#pragma once in main file at line " 2918 << lineno <<
" of file " << fn
2925 if (!full_fn.empty()) {
2926 once_files.insert(full_fn);
2932 }
else if (strcmp(directive,
"endif") == 0) {
2936 write_line_directive =
true;
2939 }
else if (strcmp(directive,
"version") == 0) {
2942 }
else if (strcmp(directive,
"extension") == 0) {
2944 char extension[256];
2946 if (sscanf(line.c_str(),
" # extension%*[ \t]%255[^: \t] : %8s", extension, behavior) == 2) {
2949 if (strcmp(behavior,
"require") == 0 || strcmp(behavior,
"enable") == 0) {
2951 }
else if (strcmp(behavior,
"warn") == 0) {
2953 }
else if (strcmp(behavior,
"disable") == 0) {
2957 <<
"Extension directive specifies invalid behavior at line " 2958 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
2962 if (strcmp(extension,
"all") == 0) {
2965 <<
"Extension directive for 'all' may only specify 'warn' or " 2966 "'disable' at line " << lineno <<
" of file " << fn
2967 <<
":\n " << line <<
"\n";
2970 ext_google_include = mode;
2971 ext_google_line = mode;
2975 }
else if (strcmp(extension,
"GL_GOOGLE_include_directive") == 0) {
2979 ext_google_include = mode;
2980 ext_google_line = mode;
2983 }
else if (strcmp(extension,
"GL_GOOGLE_cpp_style_line_directive") == 0) {
2985 ext_google_line = mode;
2990 <<
"Failed to parse extension directive at line " 2991 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
2995 }
else if (ext_google_include > 0 && strcmp(directive,
"include") == 0) {
2997 if (ext_google_include == 1) {
2998 shader_cat.warning()
2999 <<
"Extension GL_GOOGLE_include_directive is being used at line " 3000 << lineno <<
" of file " << fn
3011 if (sscanf(line.c_str(),
" # include%*[ \t]\"%2047[^\"]\" %zn", incfile, &nread) != 1
3012 || nread != line.size()) {
3015 <<
"Malformed #include at line " << lineno
3016 <<
" of file " << fn <<
":\n " << line <<
"\n";
3024 if (!r_preprocess_include(out, incfn, source_dir, once_files, record, depth + 1)) {
3026 shader_cat.error(
false) <<
"included at line " 3027 << lineno <<
" of file " << fn <<
":\n " << line <<
"\n";
3032 write_line_directive =
true;
3036 }
else if (ext_google_line > 0 && strcmp(directive,
"line") == 0) {
3039 if (sscanf(line.c_str(),
" # line%*[ \t]%d%*[ \t]\"%2047[^\"]\" %zn", &lineno, filestr, &nread) == 2
3040 && nread == line.size()) {
3042 if (ext_google_line == 1) {
3043 shader_cat.warning()
3044 <<
"Extension GL_GOOGLE_cpp_style_line_directive is being used at line " 3045 << lineno <<
" of file " << fn
3054 fileno = 2048 + _included_files.size();
3055 _included_files.push_back(
Filename(filestr));
3057 out <<
"#line " << lineno <<
" " << fileno <<
" // " << filestr <<
"\n";
3062 if (write_line_directive) {
3063 out <<
"#line " << lineno <<
" " << fileno <<
" // " << fn <<
"\n";
3064 write_line_directive =
false;
3066 out << line <<
"\n";
3069 if (fileno == 0 && !had_version) {
3070 shader_cat.warning()
3071 <<
"GLSL shader " << fn <<
" does not contain a #version line!\n";
3082 check_modified()
const {
3086 for (it = _source_files.begin(); it != _source_files.end(); ++it) {
3090 if (vfile ==
nullptr || vfile->get_timestamp() > _last_modified) {
3104 cg_get_profile_from_header(ShaderCaps& caps) {
3118 int profilePos = buf.find(
"//Cg profile");
3119 if (profilePos >= 0) {
3121 if ((
int)buf.find(
"gp4vp") >= 0)
3122 caps._active_vprofile = cgGetProfile(
"gp4vp");
3124 if ((
int)buf.find(
"gp5vp") >= 0)
3125 caps._active_vprofile = cgGetProfile(
"gp5vp");
3127 if ((
int)buf.find(
"glslv") >= 0)
3128 caps._active_vprofile = cgGetProfile(
"glslv");
3130 if ((
int)buf.find(
"arbvp1") >= 0)
3131 caps._active_vprofile = cgGetProfile(
"arbvp1");
3133 if ((
int)buf.find(
"vp40") >= 0)
3134 caps._active_vprofile = cgGetProfile(
"vp40");
3136 if ((
int)buf.find(
"vp30") >= 0)
3137 caps._active_vprofile = cgGetProfile(
"vp30");
3139 if ((
int)buf.find(
"vp20") >= 0)
3140 caps._active_vprofile = cgGetProfile(
"vp20");
3142 if ((
int)buf.find(
"vs_1_1") >= 0)
3143 caps._active_vprofile = cgGetProfile(
"vs_1_1");
3145 if ((
int)buf.find(
"vs_2_0") >= 0)
3146 caps._active_vprofile = cgGetProfile(
"vs_2_0");
3148 if ((
int)buf.find(
"vs_2_x") >= 0)
3149 caps._active_vprofile = cgGetProfile(
"vs_2_x");
3151 if ((
int)buf.find(
"vs_3_0") >= 0)
3152 caps._active_vprofile = cgGetProfile(
"vs_3_0");
3154 if ((
int)buf.find(
"vs_4_0") >= 0)
3155 caps._active_vprofile = cgGetProfile(
"vs_4_0");
3157 if ((
int)buf.find(
"vs_5_0") >= 0)
3158 caps._active_vprofile = cgGetProfile(
"vs_5_0");
3161 if ((
int)buf.find(
"gp4fp") >= 0)
3162 caps._active_fprofile = cgGetProfile(
"gp4fp");
3164 if ((
int)buf.find(
"gp5fp") >= 0)
3165 caps._active_fprofile = cgGetProfile(
"gp5fp");
3167 if ((
int)buf.find(
"glslf") >= 0)
3168 caps._active_fprofile = cgGetProfile(
"glslf");
3170 if ((
int)buf.find(
"arbfp1") >= 0)
3171 caps._active_fprofile = cgGetProfile(
"arbfp1");
3173 if ((
int)buf.find(
"fp40") >= 0)
3174 caps._active_fprofile = cgGetProfile(
"fp40");
3176 if ((
int)buf.find(
"fp30") >= 0)
3177 caps._active_fprofile = cgGetProfile(
"fp30");
3179 if ((
int)buf.find(
"fp20") >= 0)
3180 caps._active_fprofile = cgGetProfile(
"fp20");
3182 if ((
int)buf.find(
"ps_1_1") >= 0)
3183 caps._active_fprofile = cgGetProfile(
"ps_1_1");
3185 if ((
int)buf.find(
"ps_1_2") >= 0)
3186 caps._active_fprofile = cgGetProfile(
"ps_1_2");
3188 if ((
int)buf.find(
"ps_1_3") >= 0)
3189 caps._active_fprofile = cgGetProfile(
"ps_1_3");
3191 if ((
int)buf.find(
"ps_2_0") >= 0)
3192 caps._active_fprofile = cgGetProfile(
"ps_2_0");
3194 if ((
int)buf.find(
"ps_2_x") >= 0)
3195 caps._active_fprofile = cgGetProfile(
"ps_2_x");
3197 if ((
int)buf.find(
"ps_3_0") >= 0)
3198 caps._active_fprofile = cgGetProfile(
"ps_3_0");
3200 if ((
int)buf.find(
"ps_4_0") >= 0)
3201 caps._active_fprofile = cgGetProfile(
"ps_4_0");
3203 if ((
int)buf.find(
"ps_5_0") >= 0)
3204 caps._active_fprofile = cgGetProfile(
"ps_5_0");
3207 if ((
int)buf.find(
"gp4gp") >= 0)
3208 caps._active_gprofile = cgGetProfile(
"gp4gp");
3210 if ((
int)buf.find(
"gp5gp") >= 0)
3211 caps._active_gprofile = cgGetProfile(
"gp5gp");
3213 if ((
int)buf.find(
"glslg") >= 0)
3214 caps._active_gprofile = cgGetProfile(
"glslg");
3216 if ((
int)buf.find(
"gs_4_0") >= 0)
3217 caps._active_gprofile = cgGetProfile(
"gs_4_0");
3219 if ((
int)buf.find(
"gs_5_0") >= 0)
3220 caps._active_gprofile = cgGetProfile(
"gs_5_0");
3222 }
while(_parse > lastParse);
3255 }
else if (glsl_preprocess && index >= 2048 &&
3256 (index - 2048) < (int)_included_files.size()) {
3257 return _included_files[(size_t)index - 2048];
3260 string str = format_string(index);
3268 load(
const Filename &file, ShaderLanguage lang) {
3269 ShaderFile sfile(file);
3270 ShaderTable::const_iterator i = _load_table.find(sfile);
3271 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
3273 if (i->second->check_modified()) {
3275 <<
"Shader " << file <<
" was modified on disk, reloading.\n";
3278 <<
"Shader " << file <<
" was found in shader cache.\n";
3284 if (!shader->read(sfile)) {
3288 _load_table[sfile] = shader;
3290 if (cache_generated_shaders) {
3291 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3292 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3295 _make_table[shader->_text] = shader;
3304 load(ShaderLanguage lang,
const Filename &vertex,
3307 ShaderFile sfile(vertex, fragment, geometry, tess_control, tess_evaluation);
3308 ShaderTable::const_iterator i = _load_table.find(sfile);
3309 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
3311 if (i->second->check_modified()) {
3313 <<
"Shader was modified on disk, reloading.\n";
3316 <<
"Shader was found in shader cache.\n";
3322 if (!shader->read(sfile)) {
3326 _load_table[sfile] = shader;
3328 if (cache_generated_shaders) {
3329 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3330 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3333 _make_table[shader->_text] = shader;
3342 load_compute(ShaderLanguage lang,
const Filename &fn) {
3343 if (lang != SL_GLSL) {
3345 <<
"Only GLSL compute shaders are currently supported.\n";
3353 <<
"Could not find compute shader file: " << fn <<
"\n";
3358 sfile._separate =
true;
3359 sfile._compute = fn;
3361 ShaderTable::const_iterator i = _load_table.find(sfile);
3362 if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
3364 if (i->second->check_modified()) {
3366 <<
"Compute shader " << fn <<
" was modified on disk, reloading.\n";
3369 <<
"Compute shader " << fn <<
" was found in shader cache.\n";
3376 if (record !=
nullptr) {
3377 if (record->has_data()) {
3379 <<
"Compute shader " << fn <<
" was found in disk cache.\n";
3387 if (!shader->read(sfile, record)) {
3390 _load_table[sfile] = shader;
3392 if (cache_generated_shaders) {
3393 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3394 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3397 _make_table[shader->_text] = shader;
3402 std::swap(shader->_record, record);
3404 shader->_fullpath = shader->_source_files[0];
3412 make(
string body, ShaderLanguage lang) {
3413 if (lang == SL_GLSL) {
3415 <<
"GLSL shaders must have separate shader bodies!\n";
3418 }
else if (lang == SL_none) {
3419 shader_cat.warning()
3420 <<
"Shader::make() now requires an explicit shader language. Assuming Cg.\n";
3424 if (lang == SL_Cg) {
3425 shader_cat.error() <<
"Support for Cg shaders is not enabled.\n";
3430 ShaderFile sbody(move(body));
3432 if (cache_generated_shaders) {
3433 ShaderTable::const_iterator i = _make_table.find(sbody);
3434 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3436 if (!i->second->check_modified()) {
3443 if (!shader->load(sbody)) {
3447 if (cache_generated_shaders) {
3448 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3449 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3452 _make_table[shader->_text] = shader;
3454 _make_table[std::move(sbody)] = shader;
3457 if (dump_generated_shaders) {
3459 int index = _shaders_generated ++;
3460 fns <<
"genshader" << index;
3461 string fn = fns.str();
3462 shader_cat.warning() <<
"Dumping shader: " << fn <<
"\n";
3465 s.open(fn.c_str(), std::ios::out | std::ios::trunc);
3466 s << shader->get_text();
3476 make(ShaderLanguage lang,
string vertex,
string fragment,
string geometry,
3477 string tess_control,
string tess_evaluation) {
3479 if (lang == SL_Cg) {
3480 shader_cat.error() <<
"Support for Cg shaders is not enabled.\n";
3484 if (lang == SL_none) {
3486 <<
"Shader::make() requires an explicit shader language.\n";
3490 ShaderFile sbody(move(vertex), move(fragment), move(geometry),
3491 move(tess_control), move(tess_evaluation));
3493 if (cache_generated_shaders) {
3494 ShaderTable::const_iterator i = _make_table.find(sbody);
3495 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3497 if (!i->second->check_modified()) {
3504 shader->_filename = ShaderFile(
"created-shader");
3505 if (!shader->load(sbody)) {
3509 if (cache_generated_shaders) {
3510 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3511 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3514 _make_table[shader->_text] = shader;
3516 _make_table[std::move(sbody)] = shader;
3526 make_compute(ShaderLanguage lang,
string body) {
3527 if (lang != SL_GLSL) {
3529 <<
"Only GLSL compute shaders are currently supported.\n";
3534 sbody._separate =
true;
3535 sbody._compute = move(body);
3537 if (cache_generated_shaders) {
3538 ShaderTable::const_iterator i = _make_table.find(sbody);
3539 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3541 if (!i->second->check_modified()) {
3548 shader->_filename = ShaderFile(
"created-shader");
3549 if (!shader->load(sbody)) {
3553 if (cache_generated_shaders) {
3554 ShaderTable::const_iterator i = _make_table.find(shader->_text);
3555 if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
3558 _make_table[shader->_text] = shader;
3560 _make_table[std::move(sbody)] = shader;
3581 nassertv(!_text._separate);
3582 int len = _text._shared.size();
3585 while ((tail < len) && (_text._shared[tail] !=
'\n')) {
3594 while ((head < tail)&&(isspace(_text._shared[head]))) head++;
3595 while ((tail > head)&&(isspace(_text._shared[tail-1]))) tail--;
3597 result = _text._shared.substr(head, tail-head);
3607 nassertv(!_text._separate);
3611 while (_parse < (
int)(_text._shared.size())) {
3618 result = _text._shared.substr(start, _parse - start);
3620 result = _text._shared.substr(start, last - start);
3629 nassertv(!_text._separate);
3630 result = _text._shared.substr(_parse, _text._shared.size() - _parse);
3638 return (
int)_text._shared.size() == _parse;
3652 return prepared_objects->enqueue_shader_future(
this);
3661 Contexts::const_iterator ci;
3662 ci = _contexts.find(prepared_objects);
3663 if (ci != _contexts.end()) {
3675 Contexts::iterator ci;
3676 ci = _contexts.find(prepared_objects);
3677 if (ci != _contexts.end()) {
3679 if (sc !=
nullptr) {
3682 _contexts.erase(ci);
3705 Contexts::const_iterator ci;
3706 ci = _contexts.find(prepared_objects);
3707 if (ci != _contexts.end()) {
3708 return (*ci).second;
3712 _contexts[prepared_objects] = tc;
3725 Contexts::iterator ci;
3726 ci = _contexts.find(prepared_objects);
3727 if (ci != _contexts.end()) {
3728 _contexts.erase(ci);
3732 nassert_raise(
"unknown PreparedGraphicsObjects");
3747 int num_freed = (int)_contexts.size();
3749 Contexts::const_iterator ci;
3750 for (ci = temp.begin(); ci != temp.end(); ++ci) {
3753 if (sc !=
nullptr) {
3768 void Shader::ShaderCaps::
3770 _supports_glsl =
false;
3773 _active_vprofile = CG_PROFILE_UNKNOWN;
3774 _active_fprofile = CG_PROFILE_UNKNOWN;
3775 _active_gprofile = CG_PROFILE_UNKNOWN;
3776 _ultimate_vprofile = CG_PROFILE_UNKNOWN;
3777 _ultimate_fprofile = CG_PROFILE_UNKNOWN;
3778 _ultimate_gprofile = CG_PROFILE_UNKNOWN;
3817 attrib->fillin(scan, manager);
3827 _language = (ShaderLanguage) scan.
get_uint8();
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.
std::string get_dirname() const
Returns the directory part of the filename.
void parse_rest(std::string &result)
Returns the rest of the text from the current parse location.
void release_shader(ShaderContext *sc)
Indicates that a shader context, created by a previous call to prepare_shader(), is no longer needed.
bool cp_errchk_parameter_varying(ShaderArgInfo &arg)
Make sure the provided parameter has the correct variance.
This is our own Panda specialization on the default STL map.
This class represents a thread-safe handle to a promised future result of an asynchronous operation,...
bool get_bool()
Extracts a boolean value.
static void register_with_read_factory()
Tells the BamReader how to create objects of type Shader.
std::ostream & error(bool prefix=true) const
A shorthand way to write out(NS_error).
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
This class maintains a cache of Bam and/or Txo objects generated from model files and texture images ...
A hierarchy of directories and files that appears to be one continuous file system,...
void set_compiled(unsigned int format, const char *data, size_t length)
Called by the back-end when the shader has compiled data available.
Base class for objects that can be written to and read from Bam files.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const std::string & get_text(ShaderType type=ST_none) const
Return the Shader's text 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...
Filename get_filename(ShaderType type=ST_none) const
Return the Shader's filename for the given shader type.
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...
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
bool cp_errchk_parameter_sampler(ShaderArgInfo &arg)
Make sure the provided parameter has a texture type.
The abstract base class for a file or directory within the VirtualFileSystem.
A table of objects that are saved within the graphics context for reference by handle later.
PT(Shader) Shader
Loads the shader with the given filename.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_init()
Set a 'parse pointer' to the beginning of the shader.
std::string get_string()
Extracts a variable-length string.
bool matches(const std::string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
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...
get_cache_compiled_shaders
Returns whether compiled shader programs will be stored in the cache, as binary .txo files.
bool cp_parse_eol(ShaderArgInfo &arg, vector_string &pieces, int &next)
Make sure the next thing on the word list is EOL.
void cp_optimize_mat_spec(ShaderMatSpec &spec)
Analyzes a ShaderMatSpec and decides what it should use its cache for.
The ShaderContext is meant to contain the compiled version of a shader string.
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
void parse_line(std::string &result, bool rt, bool lt)
Parse a line of text.
This is our own Panda specialization on the default STL vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void cp_report_error(ShaderArgInfo &arg, const std::string &msg)
Generate an error message including a description of the specified parameter.
ShaderContext * prepare_shader_now(Shader *shader, GraphicsStateGuardianBase *gsg)
Immediately creates a new ShaderContext for the indicated shader and returns it.
bool store(BamCacheRecord *record)
Flushes a cache entry to disk.
void read_datagram(DatagramIterator &source)
Reads the object from a Datagram.
bool get_compiled(unsigned int &format, std::string &binary) const
Called by the back-end to retrieve compiled data.
bool cp_errchk_parameter_uniform(ShaderArgInfo &arg)
Make sure the provided parameter has the correct variance.
void parse_params(const FactoryParams ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
void add_bool(bool value)
Adds a boolean value to the datagram.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
The name of a file, such as a texture file or an Egg file.
void write_datagram(Datagram &dg) const
Writes the contents of this object to the datagram for shipping out to a Bam file.
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
get_data
Returns a pointer to the data stored in the record, or NULL if there is no data.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
bool cp_parse_coord_sys(ShaderArgInfo &arg, vector_string &pieces, int &next, ShaderMatSpec &spec, bool fromflag)
Convert a single-word coordinate system name into a PART/ARG of a ShaderMatSpec.
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
~Shader()
Delete the compiled code, if it exists.
bool dequeue_shader(Shader *shader)
Removes a shader from the queued list of shaders to be prepared.
std::string cp_parse_non_delimiter(vector_string &pieces, int &next)
Pop a non-delimiter word from the word list.
Encodes a string name in a hash table, mapping it to a pointer.
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.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int release_all()
Frees the context allocated on all objects for which the texture has been declared.
bool cp_errchk_parameter_in(ShaderArgInfo &arg)
Make sure the provided parameter has the 'in' direction.
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const
Returns true if the shader has already been prepared or enqueued for preparation on the indicated GSG...
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the texture context only on the indicated object, if it exists there.
This class stores a list of directories that can be searched, in order, to locate a particular file.
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
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.
A class to retrieve the individual data elements previously stored in a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
bool parse_eof()
Returns true if the parse pointer is at the end of the shader.
bool cp_errchk_parameter_words(ShaderArgInfo &arg, int len)
Make sure the provided parameter contains the specified number of words.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
ShaderContext * prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the shader on the particular GSG, if it does not already exist.
bool 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.
bool cp_parse_delimiter(ShaderArgInfo &arg, vector_string &pieces, int &next)
Pop a delimiter ('to' or 'rel') from the word list.
static BamCache * get_global_ptr()
Returns a pointer to the global BamCache object, which is used automatically by the ModelPool and Tex...
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
void parse_upto(std::string &result, std::string pattern, bool include)
Parse lines until you read a line that matches the specified pattern.
bool is_shader_queued(const Shader *shader) const
Returns true if the shader has been queued on this GSG, false otherwise.
bool cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi)
Make sure the provided parameter has a floating point type.