57#define UNPACK_COMBINE_SRC(from, n) (TextureStage::CombineSource)((from >> ((uint16_t)n * 5u)) & 7u)
58#define UNPACK_COMBINE_OP(from, n) (TextureStage::CombineOperand)(((from >> (((uint16_t)n * 5u) + 3u)) & 3u) + 1u)
61pack_combine(TextureStage::CombineSource src0, TextureStage::CombineOperand op0,
62 TextureStage::CombineSource src1, TextureStage::CombineOperand op1,
63 TextureStage::CombineSource src2, TextureStage::CombineOperand op2) {
64 if (op0 == TextureStage::CO_undefined) op0 = TextureStage::CO_src_alpha;
65 if (op1 == TextureStage::CO_undefined) op1 = TextureStage::CO_src_alpha;
66 if (op2 == TextureStage::CO_undefined) op2 = TextureStage::CO_src_alpha;
68 return ((uint16_t)src0) | ((((uint16_t)op0 - 1u) & 3u) << 3u) |
69 ((uint16_t)src1 << 5u) | ((((uint16_t)op1 - 1u) & 3u) << 8u) |
70 ((uint16_t)src2 << 10u) | ((((uint16_t)op2 - 1u) & 3u) << 13u);
74static PStatCollector synthesize_collector(
"*:Munge:ShaderGen:Synthesize");
83 _use_shadow_filter(use_shadow_filter) {
87 _use_generic_attr = (caps._active_vprofile <= 6151 || caps._active_vprofile >= 7000);
89 _use_generic_attr =
true;
93 _use_pointcoord = (caps._active_fprofile == 7017 || caps._active_fprofile == 7008);
107 _use_generic_attr = !gsg->get_supports_hlsl();
109 _use_generic_attr =
true;
114 _use_shadow_filter = gsg->get_supports_shadow_filter();
128void ShaderGenerator::
129reset_register_allocator() {
139const char *ShaderGenerator::
141 if (_use_generic_attr) {
143 switch (_vtregs_used) {
144 case 0: _vtregs_used += 1;
return "ATTR8";
145 case 1: _vtregs_used += 1;
return "ATTR9";
146 case 2: _vtregs_used += 1;
return "ATTR10";
147 case 3: _vtregs_used += 1;
return "ATTR11";
148 case 4: _vtregs_used += 1;
return "ATTR12";
149 case 5: _vtregs_used += 1;
return "ATTR13";
150 case 6: _vtregs_used += 1;
return "ATTR14";
151 case 7: _vtregs_used += 1;
return "ATTR15";
153 switch (_vcregs_used) {
154 case 0: _vcregs_used += 1;
return "ATTR3";
155 case 1: _vcregs_used += 1;
return "ATTR4";
156 case 2: _vcregs_used += 1;
return "ATTR5";
157 case 3: _vcregs_used += 1;
return "ATTR6";
158 case 4: _vcregs_used += 1;
return "ATTR7";
159 case 5: _vcregs_used += 1;
return "ATTR1";
163 switch (_vtregs_used) {
164 case 0: _vtregs_used += 1;
return "TEXCOORD0";
165 case 1: _vtregs_used += 1;
return "TEXCOORD1";
166 case 2: _vtregs_used += 1;
return "TEXCOORD2";
167 case 3: _vtregs_used += 1;
return "TEXCOORD3";
168 case 4: _vtregs_used += 1;
return "TEXCOORD4";
169 case 5: _vtregs_used += 1;
return "TEXCOORD5";
170 case 6: _vtregs_used += 1;
return "TEXCOORD6";
171 case 7: _vtregs_used += 1;
return "TEXCOORD7";
173 switch (_vcregs_used) {
174 case 0: _vcregs_used += 1;
return "COLOR0";
175 case 1: _vcregs_used += 1;
return "COLOR1";
180 switch (_vtregs_used) {
181 case 8: _vtregs_used += 1;
return "TEXCOORD8";
182 case 9: _vtregs_used += 1;
return "TEXCOORD9";
183 case 10: _vtregs_used += 1;
return "TEXCOORD10";
184 case 11: _vtregs_used += 1;
return "TEXCOORD11";
185 case 12: _vtregs_used += 1;
return "TEXCOORD12";
186 case 13: _vtregs_used += 1;
return "TEXCOORD13";
187 case 14: _vtregs_used += 1;
return "TEXCOORD14";
188 case 15: _vtregs_used += 1;
return "TEXCOORD15";
196const char *ShaderGenerator::
198 switch (_ftregs_used) {
199 case 0: _ftregs_used += 1;
return "TEXCOORD0";
200 case 1: _ftregs_used += 1;
return "TEXCOORD1";
201 case 2: _ftregs_used += 1;
return "TEXCOORD2";
202 case 3: _ftregs_used += 1;
return "TEXCOORD3";
203 case 4: _ftregs_used += 1;
return "TEXCOORD4";
204 case 5: _ftregs_used += 1;
return "TEXCOORD5";
205 case 6: _ftregs_used += 1;
return "TEXCOORD6";
206 case 7: _ftregs_used += 1;
return "TEXCOORD7";
210 switch (_ftregs_used) {
211 case 8: _ftregs_used += 1;
return "TEXCOORD8";
212 case 9: _ftregs_used += 1;
return "TEXCOORD9";
213 case 10: _ftregs_used += 1;
return "TEXCOORD10";
214 case 11: _ftregs_used += 1;
return "TEXCOORD11";
215 case 12: _ftregs_used += 1;
return "TEXCOORD12";
216 case 13: _ftregs_used += 1;
return "TEXCOORD13";
217 case 14: _ftregs_used += 1;
return "TEXCOORD14";
218 case 15: _ftregs_used += 1;
return "TEXCOORD15";
227void ShaderGenerator::
228analyze_renderstate(ShaderKey &key,
const RenderState *rs) {
230 rs->get_attrib_def(shader_attrib);
235 rs->get_attrib_def(aux_bitplane);
239 bool have_alpha_test =
false;
240 bool have_alpha_blend =
false;
242 rs->get_attrib_def(alpha_test);
243 if (alpha_test->
get_mode() != RenderAttrib::M_none &&
244 alpha_test->
get_mode() != RenderAttrib::M_always) {
245 have_alpha_test =
true;
248 rs->get_attrib_def(color_blend);
249 if (color_blend->
get_mode() != ColorBlendAttrib::M_none) {
250 have_alpha_blend =
true;
253 rs->get_attrib_def(transparency);
254 if (transparency->
get_mode() == TransparencyAttrib::M_alpha ||
255 transparency->
get_mode() == TransparencyAttrib::M_premultiplied_alpha ||
256 transparency->
get_mode() == TransparencyAttrib::M_dual) {
257 have_alpha_blend =
true;
261 if (key._outputs & AuxBitplaneAttrib::ABO_glow) {
262 if (have_alpha_blend) {
264 key._disable_alpha_write =
true;
265 }
else if (have_alpha_test) {
267 key._alpha_test_mode = alpha_test->
get_mode();
272 if (have_alpha_blend || have_alpha_test) {
273 key._calc_primary_alpha =
true;
278 rs->get_attrib_def(color);
279 key._color_type = color->get_color_type();
283 rs->get_attrib_def(material);
285 if (mat !=
nullptr) {
288 mat->mark_used_by_auto_shader();
289 key._material_flags = mat->get_flags();
291 if ((key._material_flags & Material::F_base_color) != 0) {
292 key._material_flags |= (Material::F_diffuse | Material::F_specular | Material::F_ambient);
293 key._material_flags &=
~Material::F_base_color;
299 rs->get_attrib_def(la);
300 bool have_ambient =
false;
306 nassertv(node !=
nullptr);
310 key._lighting =
true;
312 ShaderKey::LightInfo info;
313 info._type = node->get_type();
316 if (node->
is_of_type(LightLensNode::get_class_type())) {
318 if (shader_attrib->auto_shadow_on()) {
320 info._flags |= ShaderKey::LF_has_shadows;
328 info._flags |= ShaderKey::LF_has_specular_color;
332 key._lights.push_back(info);
333 key._lighting =
true;
341 rs->get_attrib_def(texture);
343 rs->get_attrib_def(tex_gen);
345 rs->get_attrib_def(tex_matrix);
348 for (
size_t i = 0; i < num_textures; ++i) {
351 nassertd(tex !=
nullptr) continue;
356 stage->mark_used_by_auto_shader();
358 ShaderKey::TextureInfo info;
359 info._type = tex->get_texture_type();
360 info._mode = stage->get_mode();
362 info._combine_rgb = 0u;
363 info._combine_alpha = 0u;
367 switch (info._mode) {
368 case TextureStage::M_modulate:
371 if (format != Texture::F_alpha) {
372 info._flags |= ShaderKey::TF_has_rgb;
375 info._flags |= ShaderKey::TF_has_alpha;
380 case TextureStage::M_modulate_glow:
381 if (shader_attrib->auto_glow_on()) {
382 info._flags = ShaderKey::TF_map_glow;
384 info._mode = TextureStage::M_modulate;
385 info._flags = ShaderKey::TF_has_rgb;
389 case TextureStage::M_modulate_gloss:
390 if (shader_attrib->auto_gloss_on()) {
391 info._flags = ShaderKey::TF_map_gloss;
393 info._mode = TextureStage::M_modulate;
394 info._flags = ShaderKey::TF_has_rgb;
398 case TextureStage::M_normal_height:
399 if (parallax_mapping_samples == 0) {
400 info._mode = TextureStage::M_normal;
401 }
else if (!shader_attrib->auto_normal_on() ||
402 (key._lights.empty() && (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) == 0)) {
403 info._mode = TextureStage::M_height;
404 info._flags = ShaderKey::TF_has_alpha;
406 info._flags = ShaderKey::TF_map_normal | ShaderKey::TF_map_height;
410 case TextureStage::M_normal_gloss:
411 if (!shader_attrib->auto_gloss_on() || key._lights.empty()) {
412 info._mode = TextureStage::M_normal;
413 }
else if (!shader_attrib->auto_normal_on()) {
414 info._mode = TextureStage::M_gloss;
416 info._flags = ShaderKey::TF_map_normal | ShaderKey::TF_map_gloss;
420 case TextureStage::M_combine:
426 info._flags |= ShaderKey::TF_rgb_scale_2;
429 info._flags |= ShaderKey::TF_rgb_scale_4;
432 info._flags |= ShaderKey::TF_alpha_scale_2;
435 info._flags |= ShaderKey::TF_alpha_scale_4;
438 info._combine_rgb = pack_combine(
442 info._combine_alpha = pack_combine(
448 info._flags |= ShaderKey::TF_uses_primary_color;
451 info._flags |= ShaderKey::TF_uses_last_saved_result;
461 switch (info._mode) {
462 case TextureStage::M_normal:
463 if (!shader_attrib->auto_normal_on() ||
464 (key._lights.empty() && (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) == 0)) {
467 info._flags = ShaderKey::TF_map_normal;
470 case TextureStage::M_glow:
471 if (shader_attrib->auto_glow_on()) {
472 info._flags = ShaderKey::TF_map_glow;
477 case TextureStage::M_gloss:
478 if (!key._lights.empty() && shader_attrib->auto_gloss_on()) {
479 info._flags = ShaderKey::TF_map_gloss;
484 case TextureStage::M_height:
485 if (parallax_mapping_samples > 0) {
486 info._flags = ShaderKey::TF_map_height;
491 case TextureStage::M_emission:
492 info._flags = ShaderKey::TF_map_emission;
501 info._type = Texture::TT_1d_texture;
502 info._mode = TextureStage::M_modulate;
504 key._textures.push_back(info);
510 if (tex_matrix->has_stage(stage)) {
512 if (!transform->is_identity()) {
515 if (transform->has_components() && !transform->has_nonzero_shear() &&
516 transform->get_pos() == LPoint3::zero() &&
517 transform->get_hpr() == LVecBase3::zero()) {
518 info._flags |= ShaderKey::TF_has_texscale;
520 info._flags |= ShaderKey::TF_has_texmat;
525 if (tex_gen->has_stage(stage)) {
526 info._texcoord_name =
nullptr;
527 info._gen_mode = tex_gen->get_mode(stage);
530 info._gen_mode = TexGenAttrib::M_off;
535 info._flags |= ShaderKey::TF_saved_result;
540 info._flags |= ShaderKey::TF_uses_color;
543 key._textures.push_back(info);
544 key._texture_flags |= info._flags;
548 if ((key._texture_flags & ShaderKey::TF_uses_last_saved_result) == 0 &&
549 (key._texture_flags & ShaderKey::TF_saved_result) != 0) {
552 for (it = key._textures.begin(); it != key._textures.end(); ++it) {
553 (*it)._flags &= ~ShaderKey::TF_saved_result;
555 key._texture_flags &= ~ShaderKey::TF_saved_result;
560 if (key._material_flags & Material::F_ambient) {
561 key._have_separate_ambient =
true;
563 if (key._material_flags & Material::F_diffuse) {
564 key._have_separate_ambient =
true;
566 key._have_separate_ambient =
false;
571 if (shader_attrib->auto_ramp_on()) {
573 if (rs->get_attrib(light_ramp)) {
574 key._light_ramp = light_ramp;
576 key._have_separate_ambient =
true;
583 rs->get_attrib_def(clip_plane);
588 if (rs->get_attrib(fog) && !fog->
is_off()) {
589 key._fog_mode = (int)fog->
get_fog()->get_mode() + 1;
595 key._fog_mode |= 0x10000;
609void ShaderGenerator::
610rehash_generated_shaders() {
616 for (
size_t si = 0; si < size; ++si) {
619 if (state->_generated_shader !=
nullptr) {
621 analyze_renderstate(key, state);
623 GeneratedShaders::const_iterator si;
624 si = _generated_shaders.find(key);
625 if (si != _generated_shaders.end()) {
626 if (si->second != state->_generated_shader) {
627 state->_generated_shader = si->second;
628 state->_munged_states.
clear();
632 state->_generated_shader.clear();
633 state->_munged_states.
clear();
641 if (!uniquify_states) {
642 GraphicsStateGuardianBase::mark_rehash_generated_shaders();
652void ShaderGenerator::
653clear_generated_shaders() {
657 for (
size_t si = 0; si < size; ++si) {
659 state->_generated_shader.clear();
662 _generated_shaders.clear();
666 if (!uniquify_states) {
667 GraphicsStateGuardianBase::mark_rehash_generated_shaders();
706 key._anim_spec = anim;
707 analyze_renderstate(key, rs);
709 GeneratedShaders::const_iterator si;
710 si = _generated_shaders.find(key);
711 if (si != _generated_shaders.end()) {
719 reset_register_allocator();
721 if (pgraphnodes_cat.is_debug()) {
722 pgraphnodes_cat.debug()
723 <<
"Generating shader for render state " << rs <<
":\n";
724 rs->write(pgraphnodes_cat.debug(
false), 2);
729 const char *tangent_freg =
nullptr;
730 const char *binormal_freg =
nullptr;
731 string tangent_input;
732 string binormal_input;
735 const char *world_position_freg =
nullptr;
736 const char *world_normal_freg =
nullptr;
737 const char *eye_position_freg =
nullptr;
738 const char *eye_normal_freg =
nullptr;
739 const char *hpos_freg =
nullptr;
740 const char *pointcoord_freg =
nullptr;
742 const char *position_vreg;
743 const char *transform_weight_vreg =
nullptr;
744 const char *normal_vreg;
745 const char *color_vreg =
nullptr;
746 const char *transform_index_vreg =
nullptr;
748 if (_use_generic_attr) {
749 position_vreg =
"ATTR0";
750 transform_weight_vreg =
"ATTR1";
751 normal_vreg =
"ATTR2";
752 transform_index_vreg =
"ATTR7";
754 position_vreg =
"POSITION";
755 normal_vreg =
"NORMAL";
758 if (key._color_type == ColorAttrib::T_vertex) {
760 color_vreg = _use_generic_attr ?
"ATTR3" :
"COLOR0";
767 std::ostringstream text;
771 text <<
"/* Generated shader for render state:\n";
775 int map_index_glow = -1;
776 int map_index_gloss = -1;
777 int map_index_emission = -1;
780 bool need_world_position = (key._num_clip_planes > 0);
781 bool need_world_normal =
false;
782 bool need_eye_position = key._lighting;
783 bool need_eye_normal = !key._lights.empty() || ((key._outputs & AuxBitplaneAttrib::ABO_aux_normal) != 0);
784 bool need_tangents = ((key._texture_flags & ShaderKey::TF_map_normal) != 0);
785 bool need_point_size = (key._fog_mode & 0x10000) != 0;
786 bool need_point_coord =
false;
790 bool pack_eye_normal = need_eye_normal && need_tangents && need_eye_position;
792 bool have_specular =
false;
794 if (key._material_flags & Material::F_specular) {
795 have_specular =
true;
796 }
else if ((key._texture_flags & ShaderKey::TF_map_gloss) != 0) {
797 have_specular =
true;
801 bool need_color =
false;
802 if (key._color_type != ColorAttrib::T_off) {
804 if (((key._material_flags & Material::F_ambient) == 0 && key._have_separate_ambient) ||
805 (key._material_flags & Material::F_diffuse) == 0 ||
806 key._calc_primary_alpha) {
814 bool need_eye_reflection =
false;
815 bool need_fragment_view_to_world =
false;
817 text <<
"void vshader(\n";
818 for (
size_t i = 0; i < key._textures.size(); ++i) {
819 const ShaderKey::TextureInfo &tex = key._textures[i];
821 switch (tex._gen_mode) {
822 case TexGenAttrib::M_world_cube_map:
823 need_fragment_view_to_world =
true;
824 case TexGenAttrib::M_eye_sphere_map:
825 case TexGenAttrib::M_eye_cube_map:
826 need_eye_position =
true;
827 need_eye_normal =
true;
828 need_eye_reflection =
true;
830 case TexGenAttrib::M_world_normal:
831 need_world_normal =
true;
833 case TexGenAttrib::M_eye_normal:
834 need_eye_normal =
true;
836 case TexGenAttrib::M_world_position:
837 need_world_position =
true;
839 case TexGenAttrib::M_eye_position:
840 need_eye_position =
true;
842 case TexGenAttrib::M_point_sprite:
843 need_point_coord =
true;
849 if (tex._texcoord_name !=
nullptr) {
850 if (texcoord_fregs.count(tex._texcoord_name) == 0) {
851 const char *freg = alloc_freg();
852 texcoord_fregs[tex._texcoord_name] = freg;
854 string tcname = tex._texcoord_name->join(
"_");
855 text <<
"\t in float4 vtx_" << tcname <<
" : " << alloc_vreg() <<
",\n";
856 text <<
"\t out float4 l_" << tcname <<
" : " << freg <<
",\n";
860 if (tangent_input.empty() &&
861 (tex._flags & (ShaderKey::TF_map_normal | ShaderKey::TF_map_height)) != 0) {
862 PT(
InternalName) tangent_name = InternalName::get_tangent();
863 PT(
InternalName) binormal_name = InternalName::get_binormal();
865 if (tex._texcoord_name !=
nullptr &&
866 tex._texcoord_name != InternalName::get_texcoord()) {
867 tangent_name = tangent_name->append(tex._texcoord_name->get_basename());
868 binormal_name = binormal_name->append(tex._texcoord_name->get_basename());
871 tangent_input = tangent_name->join(
"_");
872 binormal_input = binormal_name->join(
"_");
874 text <<
"\t in float4 vtx_" << tangent_input <<
" : " << alloc_vreg() <<
",\n";
875 text <<
"\t in float4 vtx_" << binormal_input <<
" : " << alloc_vreg() <<
",\n";
878 if (tex._flags & ShaderKey::TF_map_glow) {
881 if (tex._flags & ShaderKey::TF_map_gloss) {
884 if (tex._flags & ShaderKey::TF_map_emission) {
885 map_index_emission = i;
889 tangent_freg = alloc_freg();
890 binormal_freg = alloc_freg();
891 text <<
"\t out float4 l_tangent : " << tangent_freg <<
",\n";
892 text <<
"\t out float4 l_binormal : " << binormal_freg <<
",\n";
894 if (need_color && key._color_type == ColorAttrib::T_vertex) {
895 text <<
"\t in float4 vtx_color : " << color_vreg <<
",\n";
896 text <<
"\t out float4 l_color : COLOR0,\n";
898 if (need_world_position || need_world_normal) {
899 text <<
"\t uniform float4x4 trans_model_to_world,\n";
901 if (need_world_position) {
902 world_position_freg = alloc_freg();
903 text <<
"\t out float4 l_world_position : " << world_position_freg <<
",\n";
905 if (need_world_normal) {
906 world_normal_freg = alloc_freg();
907 text <<
"\t out float4 l_world_normal : " << world_normal_freg <<
",\n";
909 if (need_eye_position) {
910 text <<
"\t uniform float4x4 trans_model_to_view,\n";
911 eye_position_freg = alloc_freg();
912 text <<
"\t out float4 l_eye_position : " << eye_position_freg <<
",\n";
914 else if (need_tangents || need_point_size) {
915 text <<
"\t uniform float4x4 trans_model_to_view,\n";
917 if (need_eye_normal) {
918 text <<
"\t uniform float4x4 tpose_view_to_model,\n";
919 if (!pack_eye_normal) {
920 eye_normal_freg = alloc_freg();
921 text <<
"\t out float3 l_eye_normal : " << eye_normal_freg <<
",\n";
924 if ((key._texture_flags & ShaderKey::TF_map_height) != 0 || need_world_normal || need_eye_normal) {
925 text <<
"\t in float3 vtx_normal : " << normal_vreg <<
",\n";
927 if (key._texture_flags & ShaderKey::TF_map_height) {
928 text <<
"\t uniform float4 mspos_view,\n";
929 text <<
"\t out float3 l_eyevec,\n";
931 if ((key._fog_mode & 0xffff) != 0) {
932 hpos_freg = alloc_freg();
933 text <<
"\t out float4 l_hpos : " << hpos_freg <<
",\n";
935 for (
size_t i = 0; i < key._lights.size(); ++i) {
936 const ShaderKey::LightInfo &light = key._lights[i];
937 if (light._flags & ShaderKey::LF_has_shadows) {
938 if (_ftregs_used >= 8) {
941 lightcoord_fregs.push_back(
nullptr);
943 lightcoord_fregs.push_back(alloc_freg());
944 text <<
"\t uniform float4x4 mat_shadow_" << i <<
",\n";
945 text <<
"\t out float4 l_lightcoord" << i <<
" : " << lightcoord_fregs[i] <<
",\n";
948 lightcoord_fregs.push_back(
nullptr);
951 if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware &&
952 key._anim_spec.get_num_transforms() > 0) {
954 if (key._anim_spec.get_indexed_transforms()) {
955 num_transforms = 120;
957 num_transforms = key._anim_spec.get_num_transforms();
959 if (transform_weight_vreg ==
nullptr) {
960 transform_weight_vreg = alloc_vreg();
962 if (transform_index_vreg ==
nullptr) {
963 transform_index_vreg = alloc_vreg();
965 text <<
"\t uniform float4x4 tbl_transforms[" << num_transforms <<
"],\n";
966 text <<
"\t in float4 vtx_transform_weight : " << transform_weight_vreg <<
",\n";
967 if (key._anim_spec.get_indexed_transforms()) {
968 text <<
"\t in uint4 vtx_transform_index : " << transform_index_vreg <<
",\n";
971 if (need_point_size) {
972 text <<
"\t uniform float3 attr_pointparams,\n";
973 text <<
"\t out float l_point_size : PSIZE,\n";
975 if (need_point_coord && !_use_pointcoord) {
976 if (!need_point_size) {
977 text <<
"\t uniform float3 attr_pointparams,\n";
979 pointcoord_freg = alloc_freg();
980 text <<
"\t out float3 l_pointcoord : " << pointcoord_freg <<
",\n";
982 text <<
"\t in float4 vtx_position : " << position_vreg <<
",\n";
983 text <<
"\t out float4 l_position : POSITION,\n";
984 text <<
"\t uniform float4x4 mat_modelproj\n";
987 if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware &&
988 key._anim_spec.get_num_transforms() > 0) {
990 if (!key._anim_spec.get_indexed_transforms()) {
991 text <<
"\t const uint4 vtx_transform_index = uint4(0, 1, 2, 3);\n";
994 text <<
"\t float4x4 matrix = tbl_transforms[vtx_transform_index.x] * vtx_transform_weight.x";
995 if (key._anim_spec.get_num_transforms() > 1) {
996 text <<
"\n\t + tbl_transforms[vtx_transform_index.y] * vtx_transform_weight.y";
998 if (key._anim_spec.get_num_transforms() > 2) {
999 text <<
"\n\t + tbl_transforms[vtx_transform_index.z] * vtx_transform_weight.z";
1001 if (key._anim_spec.get_num_transforms() > 3) {
1002 text <<
"\n\t + tbl_transforms[vtx_transform_index.w] * vtx_transform_weight.w";
1006 text <<
"\t vtx_position = mul(matrix, vtx_position);\n";
1007 if (need_world_normal || need_eye_normal) {
1008 text <<
"\t vtx_normal = mul((float3x3)matrix, vtx_normal);\n";
1012 text <<
"\t l_position = mul(mat_modelproj, vtx_position);\n";
1013 if ((key._fog_mode & 0xffff) != 0) {
1014 text <<
"\t l_hpos = l_position;\n";
1016 if (need_world_position) {
1017 text <<
"\t l_world_position = mul(trans_model_to_world, vtx_position);\n";
1019 if (need_world_normal) {
1020 text <<
"\t l_world_normal = mul(trans_model_to_world, float4(vtx_normal, 0));\n";
1022 if (need_eye_position) {
1023 text <<
"\t l_eye_position = mul(trans_model_to_view, vtx_position);\n";
1025 else if (need_point_size) {
1026 text <<
"\t float4 l_eye_position = mul(trans_model_to_view, vtx_position);\n";
1028 if (need_point_size) {
1029 text <<
"\t l_point_size = attr_pointparams.y + attr_pointparams.z / length(l_eye_position.xyz);\n";
1031 if (need_point_coord && !_use_pointcoord) {
1032 if (need_point_size) {
1033 text <<
"\t l_pointcoord = float3(l_position.xy / (2.0f * l_position.w) + float2(0.5f, 0.5f), 1.0f / l_point_size);\n";
1036 text <<
"\t l_pointcoord = float3(l_position.xy / (2.0f * l_position.w) + float2(0.5f, 0.5f), 1.0f / attr_pointparams.x);\n";
1041 for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
1043 string tcname = it->first->join(
"_");
1044 text <<
"\t l_" << tcname <<
" = vtx_" << tcname <<
";\n";
1046 if (need_color && key._color_type == ColorAttrib::T_vertex) {
1047 text <<
"\t l_color = vtx_color;\n";
1049 if (need_tangents) {
1050 text <<
"\t l_tangent.xyz = normalize(mul((float3x3)trans_model_to_view, vtx_" << tangent_input <<
".xyz));\n";
1051 text <<
"\t l_tangent.w = 0;\n";
1052 text <<
"\t l_binormal.xyz = normalize(mul((float3x3)trans_model_to_view, -vtx_" << binormal_input <<
".xyz));\n";
1053 text <<
"\t l_binormal.w = 0;\n";
1055 for (
size_t i = 0; i < key._lights.size(); ++i) {
1056 if (key._lights[i]._flags & ShaderKey::LF_has_shadows) {
1057 if (lightcoord_fregs[i] !=
nullptr) {
1058 text <<
"\t l_lightcoord" << i <<
" = mul(mat_shadow_" << i <<
", l_eye_position);\n";
1062 if (key._texture_flags & ShaderKey::TF_map_height) {
1063 text <<
"\t float3 eyedir = mspos_view.xyz - vtx_position.xyz;\n";
1064 text <<
"\t l_eyevec.x = dot(vtx_" << tangent_input <<
".xyz, eyedir);\n";
1065 text <<
"\t l_eyevec.y = dot(vtx_" << binormal_input <<
".xyz, eyedir);\n";
1066 text <<
"\t l_eyevec.z = dot(vtx_normal, eyedir);\n";
1067 text <<
"\t l_eyevec = normalize(l_eyevec);\n";
1069 if (need_eye_normal) {
1070 if (pack_eye_normal) {
1072 text <<
"\t float3 eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n";
1073 text <<
"\t l_tangent.w = eye_normal.x;\n";
1074 text <<
"\t l_binormal.w = eye_normal.y;\n";
1075 text <<
"\t l_eye_position.w = eye_normal.z;\n";
1077 text <<
"\t l_eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n";
1084 text <<
"void fshader(\n";
1085 if ((key._fog_mode & 0xffff) != 0) {
1086 text <<
"\t in float4 l_hpos : " << hpos_freg <<
",\n";
1087 text <<
"\t in uniform float4 attr_fog,\n";
1088 text <<
"\t in uniform float4 attr_fogcolor,\n";
1090 if (need_point_coord) {
1091 if (_use_pointcoord) {
1093 text <<
"\t in float2 l_pointcoord : POINTCOORD,\n";
1096 text <<
"\t in float3 l_pointcoord : " << pointcoord_freg <<
",\n";
1097 text <<
"\t in float2 l_fragcoord : WPOS,\n";
1098 text <<
"\t in uniform float2 sys_windowsize,\n";
1101 if (need_world_position) {
1102 text <<
"\t in float4 l_world_position : " << world_position_freg <<
",\n";
1104 if (need_world_normal) {
1105 text <<
"\t in float4 l_world_normal : " << world_normal_freg <<
",\n";
1107 if (need_eye_position) {
1108 text <<
"\t in float4 l_eye_position : " << eye_position_freg <<
",\n";
1110 if (need_eye_normal && !pack_eye_normal) {
1111 text <<
"\t in float3 l_eye_normal : " << eye_normal_freg <<
",\n";
1113 for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
1114 text <<
"\t in float4 l_" << it->first->join(
"_") <<
" : " << it->second <<
",\n";
1116 for (
size_t i = 0; i < key._textures.size(); ++i) {
1117 const ShaderKey::TextureInfo &tex = key._textures[i];
1118 if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1123 text <<
"\t uniform sampler" << texture_type_as_string(tex._type) <<
" tex_" << i <<
",\n";
1125 if (tex._flags & ShaderKey::TF_has_texscale) {
1126 text <<
"\t uniform float3 texscale_" << i <<
",\n";
1127 }
else if (tex._flags & ShaderKey::TF_has_texmat) {
1128 text <<
"\t uniform float4x4 texmat_" << i <<
",\n";
1131 if (tex._flags & ShaderKey::TF_uses_color) {
1132 text <<
"\t uniform float4 texcolor_" << i <<
",\n";
1135 if (tex._gen_mode == TexGenAttrib::M_constant) {
1136 text <<
"\t uniform float4 texconst_" << i <<
",\n";
1139 if (need_fragment_view_to_world) {
1140 text <<
"\t uniform float3x3 trans_view_to_world,\n";
1142 if (need_tangents) {
1143 text <<
"\t in float4 l_tangent : " << tangent_freg <<
",\n";
1144 text <<
"\t in float4 l_binormal : " << binormal_freg <<
",\n";
1146 for (
size_t i = 0; i < key._lights.size(); ++i) {
1147 text <<
"\t uniform float4x4 attr_light" << i <<
",\n";
1149 const ShaderKey::LightInfo &light = key._lights[i];
1150 if (light._flags & ShaderKey::LF_has_shadows) {
1151 if (light._type.is_derived_from(PointLight::get_class_type())) {
1152 text <<
"\t uniform samplerCUBE shadow_" << i <<
",\n";
1153 }
else if (_use_shadow_filter) {
1154 text <<
"\t uniform sampler2DShadow shadow_" << i <<
",\n";
1156 text <<
"\t uniform sampler2D shadow_" << i <<
",\n";
1158 if (lightcoord_fregs[i] !=
nullptr) {
1159 text <<
"\t in float4 l_lightcoord" << i <<
" : " << lightcoord_fregs[i] <<
",\n";
1161 text <<
"\t uniform float4x4 mat_shadow_" << i <<
",\n";
1164 if (light._flags & ShaderKey::LF_has_specular_color) {
1165 text <<
"\t uniform float4 attr_lspec" << i <<
",\n";
1170 if (key._material_flags & (Material::F_ambient | Material::F_diffuse | Material::F_emission | Material::F_specular)) {
1171 text <<
"\t uniform float4x4 attr_material,\n";
1173 if (key._texture_flags & ShaderKey::TF_map_height) {
1174 text <<
"\t float3 l_eyevec,\n";
1176 if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
1177 text <<
"\t out float4 o_aux : COLOR1,\n";
1179 text <<
"\t out float4 o_color : COLOR0,\n";
1182 if (key._color_type == ColorAttrib::T_vertex) {
1183 text <<
"\t in float4 l_color : COLOR0,\n";
1184 }
else if (key._color_type == ColorAttrib::T_flat) {
1185 text <<
"\t uniform float4 attr_color,\n";
1189 for (
int i = 0; i < key._num_clip_planes; ++i) {
1190 text <<
"\t uniform float4 clipplane_" << i <<
",\n";
1193 if (key._lighting) {
1194 text <<
"\t uniform float4 attr_ambient,\n";
1196 text <<
"\t uniform float4 attr_colorscale\n";
1200 for (
int i = 0; i < key._num_clip_planes; ++i) {
1201 text <<
"\t if (l_world_position.x * clipplane_" << i <<
".x + l_world_position.y ";
1202 text <<
"* clipplane_" << i <<
".y + l_world_position.z * clipplane_" << i <<
".z + clipplane_" << i <<
".w <= 0) {\n";
1203 text <<
"\t discard;\n";
1208 if (need_eye_normal && pack_eye_normal) {
1209 text <<
"\t float3 l_eye_normal = float3(l_tangent.w, l_binormal.w, l_eye_position.w);\n";
1211 if (need_eye_normal) {
1212 text <<
"\t // Correct the surface normal for interpolation effects\n";
1213 text <<
"\t l_eye_normal = normalize(l_eye_normal);\n";
1215 if (need_eye_reflection ||
1216 (need_eye_position && have_specular && (key._material_flags & Material::F_local) != 0 && !key._lights.empty())) {
1217 text <<
"\t float3 norm_eye_position = normalize(l_eye_position.xyz);\n";
1219 if (need_eye_reflection) {
1220 text <<
"\t float3 eye_reflection = norm_eye_position - l_eye_normal * 2 * dot(l_eye_normal, norm_eye_position);\n";
1223 text <<
"\t float4 result;\n";
1224 if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
1225 text <<
"\t o_aux = float4(0, 0, 0, 0);\n";
1229 for (
size_t i = 0; i < key._textures.size(); ++i) {
1230 const ShaderKey::TextureInfo &tex = key._textures[i];
1231 if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1235 switch (tex._gen_mode) {
1236 case TexGenAttrib::M_off:
1238 text <<
"\t float4 texcoord" << i <<
" = l_" << tex._texcoord_name->join(
"_") <<
";\n";
1240 case TexGenAttrib::M_eye_sphere_map:
1241 text <<
"\t float4 texcoord" << i <<
" = float4(eye_reflection.xz * (1.0f / (2.0f * length(eye_reflection + float3(0, -1, 0)))) + float2(0.5f, 0.5f), 0.0f, 1.0f);\n";
1243 case TexGenAttrib::M_world_cube_map:
1244 text <<
"\t float4 texcoord" << i <<
" = float4(mul(trans_view_to_world, eye_reflection), 1.0f);\n";
1246 case TexGenAttrib::M_eye_cube_map:
1247 text <<
"\t float4 texcoord" << i <<
" = float4(eye_reflection, 1.0f);\n";
1249 case TexGenAttrib::M_world_normal:
1250 text <<
"\t float4 texcoord" << i <<
" = l_world_normal;\n";
1252 case TexGenAttrib::M_eye_normal:
1253 text <<
"\t float4 texcoord" << i <<
" = float4(l_eye_normal, 1.0f);\n";
1255 case TexGenAttrib::M_world_position:
1256 text <<
"\t float4 texcoord" << i <<
" = l_world_position;\n";
1258 case TexGenAttrib::M_eye_position:
1259 text <<
"\t float4 texcoord" << i <<
" = float4(l_eye_position.xyz, 1.0f);\n";
1261 case TexGenAttrib::M_point_sprite:
1262 if (_use_pointcoord) {
1263 text <<
"\t float4 texcoord" << i <<
" = float4(l_pointcoord, 0.0f, 1.0f);\n";
1265 if (!_use_generic_attr) {
1266 text <<
"\t l_fragcoord.y = sys_windowsize.y - l_fragcoord.y;\n";
1268 text <<
"\t float4 texcoord" << i <<
" = float4((l_fragcoord - l_pointcoord.xy * sys_windowsize) * l_pointcoord.z * float2(1.0f, -1.0f) - float2(0.5f, 0.5f), 0.0f, 1.0f);\n";
1271 case TexGenAttrib::M_constant:
1272 text <<
"\t float4 texcoord" << i <<
" = texconst_" << i <<
";\n";
1275 text <<
"\t float4 texcoord" << i <<
" = float4(0, 0, 0, 0);\n";
1276 pgraphnodes_cat.error()
1277 <<
"Unsupported TexGenAttrib mode: " << tex._gen_mode <<
"\n";
1279 if (tex._flags & ShaderKey::TF_has_texscale) {
1280 text <<
"\t texcoord" << i <<
".xyz *= texscale_" << i <<
";\n";
1281 }
else if (tex._flags & ShaderKey::TF_has_texmat) {
1282 text <<
"\t texcoord" << i <<
" = mul(texmat_" << i <<
", texcoord" << i <<
");\n";
1283 text <<
"\t texcoord" << i <<
".xyz /= texcoord" << i <<
".w;\n";
1286 text <<
"\t // Fetch all textures.\n";
1287 for (
size_t i = 0; i < key._textures.size(); ++i) {
1288 const ShaderKey::TextureInfo &tex = key._textures[i];
1289 if ((tex._flags & ShaderKey::TF_map_height) == 0) {
1293 text <<
"\t float4 tex" << i <<
" = tex" << texture_type_as_string(tex._type);
1294 text <<
"(tex_" << i <<
", texcoord" << i <<
".";
1295 switch (tex._type) {
1296 case Texture::TT_cube_map_array:
1299 case Texture::TT_cube_map:
1300 case Texture::TT_3d_texture:
1301 case Texture::TT_2d_texture_array:
1304 case Texture::TT_2d_texture:
1305 case Texture::TT_1d_texture_array:
1308 case Texture::TT_1d_texture:
1309 case Texture::TT_buffer_texture:
1315 text <<
");\n\t float3 parallax_offset = l_eyevec.xyz * (tex" << i;
1316 if (tex._mode == TextureStage::M_normal_height ||
1317 (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1322 text <<
" * 2.0 - 1.0) * " << parallax_mapping_scale <<
";\n";
1324 for (
int j = 0; j < parallax_mapping_samples - 1; ++j) {
1325 text <<
"\t parallax_offset = l_eyevec.xyz * (parallax_offset + (tex" << i;
1326 if (tex._mode == TextureStage::M_normal_height ||
1327 (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1332 text <<
" * 2.0 - 1.0)) * " << 0.5 * parallax_mapping_scale <<
";\n";
1335 for (
size_t i = 0; i < key._textures.size(); ++i) {
1336 ShaderKey::TextureInfo &tex = key._textures[i];
1337 if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1341 if ((tex._flags & ShaderKey::TF_map_height) == 0) {
1344 if (key._texture_flags & ShaderKey::TF_map_height) {
1345 text <<
"\t texcoord" << i <<
".xyz -= parallax_offset;\n";
1347 text <<
"\t float4 tex" << i <<
" = tex" << texture_type_as_string(tex._type);
1348 text <<
"(tex_" << i <<
", texcoord" << i <<
".";
1349 switch (tex._type) {
1350 case Texture::TT_cube_map_array:
1353 case Texture::TT_cube_map:
1354 case Texture::TT_3d_texture:
1355 case Texture::TT_2d_texture_array:
1358 case Texture::TT_2d_texture:
1359 case Texture::TT_1d_texture_array:
1362 case Texture::TT_1d_texture:
1363 case Texture::TT_buffer_texture:
1372 if (need_tangents) {
1373 text <<
"\t // Translate tangent-space normal in map to view-space.\n";
1376 bool is_first =
true;
1377 for (
size_t i = 0; i < key._textures.size(); ++i) {
1378 const ShaderKey::TextureInfo &tex = key._textures[i];
1379 if (tex._flags & ShaderKey::TF_map_normal) {
1381 if (tex._flags & ShaderKey::TF_has_texscale) {
1382 text <<
"\t float3 tsnormal = normalize(((tex" << i <<
".xyz * 2) - 1) * texscale_" << i <<
");\n";
1383 }
else if (tex._flags & ShaderKey::TF_has_texmat) {
1384 text <<
"\t float3 tsnormal = normalize(mul(texmat_" << i <<
", float4((tex" << i <<
".xyz * 2) - 1, 0)).xyz);\n";
1386 text <<
"\t float3 tsnormal = normalize((tex" << i <<
".xyz * 2) - 1);\n";
1391 text <<
"\t tsnormal.z += 1;\n";
1392 text <<
"\t float3 tmp" << i <<
" = tex" << i <<
".xyz * float3(-2, -2, 2) + float3(1, 1, -1);\n";
1393 if (tex._flags & ShaderKey::TF_has_texscale) {
1394 text <<
"\t tmp" << i <<
" *= texscale_" << i <<
";\n";
1395 }
else if (tex._flags & ShaderKey::TF_has_texmat) {
1396 text <<
"\t tmp" << i <<
" = mul(texmat_" << i <<
", float4(tmp" << i <<
", 0)).xyz;\n";
1398 text <<
"\t tsnormal = normalize(tsnormal * dot(tsnormal, tmp" << i <<
") - tmp" << i <<
" * tsnormal.z);\n";
1401 text <<
"\t l_eye_normal *= tsnormal.z;\n";
1402 text <<
"\t l_eye_normal += normalize(l_tangent.xyz) * tsnormal.x;\n";
1403 text <<
"\t l_eye_normal += normalize(l_binormal.xyz) * tsnormal.y;\n";
1404 text <<
"\t l_eye_normal = normalize(l_eye_normal);\n";
1406 if (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) {
1407 text <<
"\t // Output the camera-space surface normal\n";
1408 text <<
"\t o_aux.rgb = (l_eye_normal*0.5) + float3(0.5,0.5,0.5);\n";
1410 if (key._lighting) {
1411 text <<
"\t // Begin view-space light calculations\n";
1412 text <<
"\t float ldist,lattenv,langle,lshad;\n";
1413 text <<
"\t float4 lcolor,lspec,lpoint,latten,ldir,leye;\n";
1414 text <<
"\t float3 lvec,lhalf;\n";
1415 if (key._have_separate_ambient) {
1416 text <<
"\t float4 tot_ambient = float4(0,0,0,0);\n";
1418 text <<
"\t float4 tot_diffuse = float4(0,0,0,0);\n";
1419 if (have_specular) {
1420 text <<
"\t float4 tot_specular = float4(0,0,0,0);\n";
1421 if (key._material_flags & Material::F_specular) {
1422 text <<
"\t float shininess = attr_material[3].w;\n";
1424 text <<
"\t float shininess = 50; // no shininess specified, using default\n";
1427 if (key._have_separate_ambient) {
1428 text <<
"\t tot_ambient += attr_ambient;\n";
1430 text <<
"\t tot_diffuse += attr_ambient;\n";
1433 for (
size_t i = 0; i < key._lights.size(); ++i) {
1434 const ShaderKey::LightInfo &light = key._lights[i];
1436 if (light._flags & ShaderKey::LF_has_shadows) {
1437 if (lightcoord_fregs[i] ==
nullptr) {
1440 text <<
"\t float4 l_lightcoord" << i <<
" = mul(mat_shadow_" << i <<
", float4(l_eye_position.xyz, 1.0f));\n";
1444 if (light._type.is_derived_from(DirectionalLight::get_class_type())) {
1445 text <<
"\t // Directional Light " << i <<
"\n";
1446 text <<
"\t lcolor = attr_light" << i <<
"[0];\n";
1447 if (light._flags & ShaderKey::LF_has_specular_color) {
1448 text <<
"\t lspec = attr_lspec" << i <<
";\n";
1450 text <<
"\t lspec = lcolor;\n";
1452 text <<
"\t lvec = attr_light" << i <<
"[3].xyz;\n";
1453 text <<
"\t lcolor *= saturate(dot(l_eye_normal, lvec.xyz));\n";
1454 if (light._flags & ShaderKey::LF_has_shadows) {
1455 if (_use_shadow_filter) {
1456 text <<
"\t lshad = shadow2DProj(shadow_" << i <<
", l_lightcoord" << i <<
").r;\n";
1458 text <<
"\t lshad = tex2Dproj(shadow_" << i <<
", l_lightcoord" << i <<
").r > l_lightcoord" << i <<
".z / l_lightcoord" << i <<
".w;\n";
1460 text <<
"\t lcolor *= lshad;\n";
1461 text <<
"\t lspec *= lshad;\n";
1463 text <<
"\t tot_diffuse += lcolor;\n";
1464 if (have_specular) {
1465 if (key._material_flags & Material::F_local) {
1466 text <<
"\t lhalf = normalize(lvec - norm_eye_position);\n";
1468 text <<
"\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1470 text <<
"\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1471 text <<
"\t tot_specular += lspec;\n";
1473 }
else if (light._type.is_derived_from(PointLight::get_class_type())) {
1474 text <<
"\t // Point Light " << i <<
"\n";
1475 text <<
"\t lcolor = attr_light" << i <<
"[0];\n";
1476 if (light._flags & ShaderKey::LF_has_specular_color) {
1477 text <<
"\t lspec = attr_lspec" << i <<
";\n";
1479 text <<
"\t lspec = lcolor;\n";
1481 text <<
"\t latten = attr_light" << i <<
"[1];\n";
1482 text <<
"\t lpoint = attr_light" << i <<
"[3];\n";
1483 text <<
"\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
1484 text <<
"\t ldist = length(lvec);\n";
1485 text <<
"\t lvec /= ldist;\n";
1486 if (light._type.is_derived_from(SphereLight::get_class_type())) {
1487 text <<
"\t ldist = max(ldist, attr_light" << i <<
"[2].w);\n";
1489 text <<
"\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1490 text <<
"\t lcolor *= lattenv * saturate(dot(l_eye_normal, lvec));\n";
1491 if (light._flags & ShaderKey::LF_has_shadows) {
1492 text <<
"\t ldist = max(abs(l_lightcoord" << i <<
".x), max(abs(l_lightcoord" << i <<
".y), abs(l_lightcoord" << i <<
".z)));\n";
1493 text <<
"\t ldist = ((latten.w+lpoint.w)/(latten.w-lpoint.w))+((-2*latten.w*lpoint.w)/(ldist * (latten.w-lpoint.w)));\n";
1494 text <<
"\t lshad = texCUBE(shadow_" << i <<
", l_lightcoord" << i <<
".xyz).r >= ldist * 0.5 + 0.5;\n";
1495 text <<
"\t lcolor *= lshad;\n";
1496 text <<
"\t lspec *= lshad;\n";
1498 text <<
"\t tot_diffuse += lcolor;\n";
1499 if (have_specular) {
1500 if (key._material_flags & Material::F_local) {
1501 text <<
"\t lhalf = normalize(lvec - norm_eye_position);\n";
1503 text <<
"\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1505 text <<
"\t lspec *= lattenv;\n";
1506 text <<
"\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1507 text <<
"\t tot_specular += lspec;\n";
1509 }
else if (light._type.is_derived_from(Spotlight::get_class_type())) {
1510 text <<
"\t // Spot Light " << i <<
"\n";
1511 text <<
"\t lcolor = attr_light" << i <<
"[0];\n";
1512 if (light._flags & ShaderKey::LF_has_specular_color) {
1513 text <<
"\t lspec = attr_lspec" << i <<
";\n";
1515 text <<
"\t lspec = lcolor;\n";
1517 text <<
"\t latten = attr_light" << i <<
"[1];\n";
1518 text <<
"\t ldir = attr_light" << i <<
"[2];\n";
1519 text <<
"\t lpoint = attr_light" << i <<
"[3];\n";
1520 text <<
"\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
1521 text <<
"\t ldist = length(lvec);\n";
1522 text <<
"\t lvec /= ldist;\n";
1523 text <<
"\t langle = saturate(dot(ldir.xyz, lvec));\n";
1524 text <<
"\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1525 text <<
"\t lattenv *= pow(langle, latten.w);\n";
1526 text <<
"\t if (langle < ldir.w) lattenv = 0;\n";
1527 text <<
"\t lcolor *= lattenv * saturate(dot(l_eye_normal, lvec));\n";
1528 if (light._flags & ShaderKey::LF_has_shadows) {
1529 if (_use_shadow_filter) {
1530 text <<
"\t lshad = shadow2DProj(shadow_" << i <<
", l_lightcoord" << i <<
").r;\n";
1532 text <<
"\t lshad = tex2Dproj(shadow_" << i <<
", l_lightcoord" << i <<
").r > l_lightcoord" << i <<
".z / l_lightcoord" << i <<
".w;\n";
1534 text <<
"\t lcolor *= lshad;\n";
1535 text <<
"\t lspec *= lshad;\n";
1538 text <<
"\t tot_diffuse += lcolor;\n";
1539 if (have_specular) {
1540 if (key._material_flags & Material::F_local) {
1541 text <<
"\t lhalf = normalize(lvec - norm_eye_position);\n";
1543 text <<
"\t lhalf = normalize(lvec - float3(0,1,0));\n";
1545 text <<
"\t lspec *= lattenv;\n";
1546 text <<
"\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1547 text <<
"\t tot_specular += lspec;\n";
1551 if (key._lighting) {
1552 if (key._light_ramp !=
nullptr) {
1553 switch (key._light_ramp->get_mode()) {
1554 case LightRampAttrib::LRT_single_threshold:
1556 PN_stdfloat t = key._light_ramp->get_threshold(0);
1557 PN_stdfloat l0 = key._light_ramp->get_level(0);
1558 text <<
"\t // Single-threshold light ramp\n";
1559 text <<
"\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1560 text <<
"\t float lr_scale = (lr_in < " << t <<
") ? 0.0 : (" << l0 <<
"/lr_in);\n";
1561 text <<
"\t tot_diffuse = tot_diffuse * lr_scale;\n";
1564 case LightRampAttrib::LRT_double_threshold:
1566 PN_stdfloat t0 = key._light_ramp->get_threshold(0);
1567 PN_stdfloat t1 = key._light_ramp->get_threshold(1);
1568 PN_stdfloat l0 = key._light_ramp->get_level(0);
1569 PN_stdfloat l1 = key._light_ramp->get_level(1);
1570 text <<
"\t // Double-threshold light ramp\n";
1571 text <<
"\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1572 text <<
"\t float lr_out = 0.0;\n";
1573 text <<
"\t if (lr_in > " << t0 <<
") lr_out=" << l0 <<
";\n";
1574 text <<
"\t if (lr_in > " << t1 <<
") lr_out=" << l1 <<
";\n";
1575 text <<
"\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n";
1582 text <<
"\t // Begin view-space light summation\n";
1583 if (key._material_flags & Material::F_emission) {
1584 text <<
"\t result = attr_material[2];\n";
1585 }
else if (key._texture_flags & (ShaderKey::TF_map_glow | ShaderKey::TF_map_emission)) {
1586 text <<
"\t result = float4(1,1,1,0);\n";
1588 text <<
"\t result = float4(0,0,0,0);\n";
1590 if (key._texture_flags & ShaderKey::TF_map_emission) {
1591 text <<
"\t result.rgb *= tex" << map_index_emission <<
".rgb;\n";
1593 if (key._texture_flags & ShaderKey::TF_map_glow) {
1594 text <<
"\t result *= saturate(2 * (tex" << map_index_glow <<
".a - 0.5));\n";
1596 if (key._have_separate_ambient) {
1597 if (key._material_flags & Material::F_ambient) {
1598 text <<
"\t result += tot_ambient * attr_material[0];\n";
1599 }
else if (key._color_type == ColorAttrib::T_vertex) {
1600 text <<
"\t result += tot_ambient * l_color;\n";
1601 }
else if (key._color_type == ColorAttrib::T_flat) {
1602 text <<
"\t result += tot_ambient * attr_color;\n";
1604 text <<
"\t result += tot_ambient;\n";
1607 if (key._material_flags & Material::F_diffuse) {
1608 text <<
"\t result += tot_diffuse * attr_material[1];\n";
1609 }
else if (key._color_type == ColorAttrib::T_vertex) {
1610 text <<
"\t result += tot_diffuse * l_color;\n";
1611 }
else if (key._color_type == ColorAttrib::T_flat) {
1612 text <<
"\t result += tot_diffuse * attr_color;\n";
1614 text <<
"\t result += tot_diffuse;\n";
1616 if (key._light_ramp ==
nullptr ||
1617 key._light_ramp->get_mode() == LightRampAttrib::LRT_default) {
1618 text <<
"\t result = saturate(result);\n";
1620 text <<
"\t // End view-space light calculations\n";
1624 if (key._calc_primary_alpha) {
1625 if (key._material_flags & Material::F_diffuse) {
1626 text <<
"\t result.a = attr_material[1].w;\n";
1627 }
else if (key._color_type == ColorAttrib::T_vertex) {
1628 text <<
"\t result.a = l_color.a;\n";
1629 }
else if (key._color_type == ColorAttrib::T_flat) {
1630 text <<
"\t result.a = attr_color.a;\n";
1632 text <<
"\t result.a = 1;\n";
1636 if (key._color_type == ColorAttrib::T_vertex) {
1637 text <<
"\t result = l_color;\n";
1638 }
else if (key._color_type == ColorAttrib::T_flat) {
1639 text <<
"\t result = attr_color;\n";
1641 text <<
"\t result = float4(1, 1, 1, 1);\n";
1646 text <<
"\t result *= attr_colorscale;\n";
1649 if (key._texture_flags & ShaderKey::TF_uses_primary_color) {
1650 text <<
"\t float4 primary_color = result;\n";
1652 if (key._texture_flags & ShaderKey::TF_uses_last_saved_result) {
1653 text <<
"\t float4 last_saved_result = result;\n";
1657 for (
size_t i = 0; i < key._textures.size(); ++i) {
1658 const ShaderKey::TextureInfo &tex = key._textures[i];
1659 TextureStage::CombineMode combine_rgb, combine_alpha;
1661 switch (tex._mode) {
1662 case TextureStage::M_modulate:
1663 if ((tex._flags & ShaderKey::TF_has_rgb) != 0 &&
1664 (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1665 text <<
"\t result.rgba *= tex" << i <<
".rgba;\n";
1666 }
else if (tex._flags & ShaderKey::TF_has_alpha) {
1667 text <<
"\t result.a *= tex" << i <<
".a;\n";
1668 }
else if (tex._flags & ShaderKey::TF_has_rgb) {
1669 text <<
"\t result.rgb *= tex" << i <<
".rgb;\n";
1672 case TextureStage::M_modulate_glow:
1673 case TextureStage::M_modulate_gloss:
1679 text <<
"\t result.rgb *= tex" << i <<
";\n";
1681 case TextureStage::M_decal:
1682 text <<
"\t result.rgb = lerp(result, tex" << i <<
", tex" << i <<
".a).rgb;\n";
1684 case TextureStage::M_blend:
1685 text <<
"\t result.rgb = lerp(result.rgb, texcolor_" << i <<
".rgb, tex" << i <<
".rgb);\n";
1686 if (key._calc_primary_alpha) {
1687 text <<
"\t result.a *= tex" << i <<
".a;\n";
1690 case TextureStage::M_replace:
1691 text <<
"\t result = tex" << i <<
";\n";
1693 case TextureStage::M_add:
1694 text <<
"\t result.rgb += tex" << i <<
".rgb;\n";
1695 if (key._calc_primary_alpha) {
1696 text <<
"\t result.a *= tex" << i <<
".a;\n";
1699 case TextureStage::M_combine:
1700 combine_rgb = (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_RGB_MODE_MASK) >> ShaderKey::TF_COMBINE_RGB_MODE_SHIFT);
1701 combine_alpha = (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_ALPHA_MODE_MASK) >> ShaderKey::TF_COMBINE_ALPHA_MODE_SHIFT);
1702 if (combine_rgb == TextureStage::CM_dot3_rgba) {
1703 text <<
"\t result = ";
1704 text << combine_mode_as_string(tex, combine_rgb,
false, i);
1707 text <<
"\t result.rgb = ";
1708 text << combine_mode_as_string(tex, combine_rgb,
false, i);
1709 text <<
";\n\t result.a = ";
1710 text << combine_mode_as_string(tex, combine_alpha,
true, i);
1713 if (tex._flags & ShaderKey::TF_rgb_scale_2) {
1714 text <<
"\t result.rgb *= 2;\n";
1716 if (tex._flags & ShaderKey::TF_rgb_scale_4) {
1717 text <<
"\t result.rgb *= 4;\n";
1719 if (tex._flags & ShaderKey::TF_alpha_scale_2) {
1720 text <<
"\t result.a *= 2;\n";
1722 if (tex._flags & ShaderKey::TF_alpha_scale_4) {
1723 text <<
"\t result.a *= 4;\n";
1726 case TextureStage::M_blend_color_scale:
1727 text <<
"\t result.rgb = lerp(result.rgb, texcolor_" << i <<
".rgb * attr_colorscale.rgb, tex" << i <<
".rgb);\n";
1728 if (key._calc_primary_alpha) {
1729 text <<
"\t result.a *= texcolor_" << i <<
".a * attr_colorscale.a;\n";
1735 if (tex._flags & ShaderKey::TF_saved_result) {
1736 text <<
"\t last_saved_result = result;\n";
1740 if (key._alpha_test_mode != RenderAttrib::M_none) {
1741 text <<
"\t // Shader includes alpha test:\n";
1742 double ref = key._alpha_test_ref;
1743 switch (key._alpha_test_mode) {
1744 case RenderAttrib::M_never:
1745 text <<
"\t discard;\n";
1747 case RenderAttrib::M_less:
1748 text <<
"\t if (result.a >= " <<
ref <<
") discard;\n";
1750 case RenderAttrib::M_equal:
1751 text <<
"\t if (result.a != " <<
ref <<
") discard;\n";
1753 case RenderAttrib::M_less_equal:
1754 text <<
"\t if (result.a > " <<
ref <<
") discard;\n";
1756 case RenderAttrib::M_greater:
1757 text <<
"\t if (result.a <= " <<
ref <<
") discard;\n";
1759 case RenderAttrib::M_not_equal:
1760 text <<
"\t if (result.a == " <<
ref <<
") discard;\n";
1762 case RenderAttrib::M_greater_equal:
1763 text <<
"\t if (result.a < " <<
ref <<
") discard;\n";
1765 case RenderAttrib::M_none:
1766 case RenderAttrib::M_always:
1771 if (key._outputs & AuxBitplaneAttrib::ABO_glow) {
1772 if (key._texture_flags & ShaderKey::TF_map_glow) {
1773 text <<
"\t result.a = tex" << map_index_glow <<
".a;\n";
1775 text <<
"\t result.a = 0.5;\n";
1778 if (key._outputs & AuxBitplaneAttrib::ABO_aux_glow) {
1779 if (key._texture_flags & ShaderKey::TF_map_glow) {
1780 text <<
"\t o_aux.a = tex" << map_index_glow <<
".a;\n";
1782 text <<
"\t o_aux.a = 0.5;\n";
1786 if (have_specular) {
1787 if (key._material_flags & Material::F_specular) {
1788 text <<
"\t tot_specular *= attr_material[3];\n";
1790 if (key._texture_flags & ShaderKey::TF_map_gloss) {
1791 text <<
"\t tot_specular *= tex" << map_index_gloss <<
".a;\n";
1793 text <<
"\t result.rgb = result.rgb + tot_specular.rgb;\n";
1795 if (key._light_ramp !=
nullptr) {
1796 switch (key._light_ramp->get_mode()) {
1797 case LightRampAttrib::LRT_hdr0:
1798 text <<
"\t result.rgb = (result*result*result + result*result + result) / (result*result*result + result*result + result + 1);\n";
1800 case LightRampAttrib::LRT_hdr1:
1801 text <<
"\t result.rgb = (result*result + result) / (result*result + result + 1);\n";
1803 case LightRampAttrib::LRT_hdr2:
1804 text <<
"\t result.rgb = result / (result + 1);\n";
1811 if ((key._fog_mode & 0xffff) != 0) {
1812 Fog::Mode fog_mode = (Fog::Mode)((key._fog_mode & 0xffff) - 1);
1815 text <<
"\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate((attr_fog.z - l_hpos.z) * attr_fog.w));\n";
1817 case Fog::M_exponential:
1818 text <<
"\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate(exp2(attr_fog.x * l_hpos.z * -1.442695f)));\n";
1820 case Fog::M_exponential_squared:
1821 text <<
"\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate(exp2(attr_fog.x * attr_fog.x * l_hpos.z * l_hpos.z * -1.442695f)));\n";
1828 text <<
"\t o_color = result * 1.000001;\n";
1829 if (key._alpha_test_mode != RenderAttrib::M_none) {
1830 text <<
"\t // Shader subsumes normal alpha test.\n";
1832 if (key._disable_alpha_write) {
1833 text <<
"\t // Shader disables alpha write.\n";
1837 if (pgraphnodes_cat.is_spam()) {
1838 pgraphnodes_cat.spam() <<
"Generated shader:\n"
1839 << text.str() <<
"\n";
1843 PT(
Shader) shader = Shader::make(text.str(), Shader::SL_Cg);
1844 nassertr(shader !=
nullptr,
nullptr);
1847 if (key._alpha_test_mode != RenderAttrib::M_none) {
1848 shattr = DCAST(
ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_subsume_alpha_test,
true);
1850 if (key._disable_alpha_write) {
1851 shattr = DCAST(
ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_disable_alpha_write,
true);
1853 if (need_point_size) {
1854 shattr = DCAST(
ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_shader_point_size,
true);
1857 reset_register_allocator();
1860 _generated_shaders[key] = attr;
1867string ShaderGenerator::
1868combine_mode_as_string(
const ShaderKey::TextureInfo &info, TextureStage::CombineMode c_mode,
bool alpha,
short texindex) {
1869 std::ostringstream text;
1871 case TextureStage::CM_modulate:
1872 text << combine_source_as_string(info, 0, alpha, texindex);
1874 text << combine_source_as_string(info, 1, alpha, texindex);
1876 case TextureStage::CM_add:
1877 text << combine_source_as_string(info, 0, alpha, texindex);
1879 text << combine_source_as_string(info, 1, alpha, texindex);
1881 case TextureStage::CM_add_signed:
1882 text << combine_source_as_string(info, 0, alpha, texindex);
1884 text << combine_source_as_string(info, 1, alpha, texindex);
1888 text <<
" - float3(0.5, 0.5, 0.5)";
1891 case TextureStage::CM_interpolate:
1893 text << combine_source_as_string(info, 1, alpha, texindex);
1895 text << combine_source_as_string(info, 0, alpha, texindex);
1897 text << combine_source_as_string(info, 2, alpha, texindex);
1900 case TextureStage::CM_subtract:
1901 text << combine_source_as_string(info, 0, alpha, texindex);
1903 text << combine_source_as_string(info, 1, alpha, texindex);
1905 case TextureStage::CM_dot3_rgb:
1906 case TextureStage::CM_dot3_rgba:
1908 text << combine_source_as_string(info, 0, alpha, texindex);
1909 text <<
" - float3(0.5), ";
1910 text << combine_source_as_string(info, 1, alpha, texindex);
1911 text <<
" - float3(0.5))";
1913 case TextureStage::CM_replace:
1915 text << combine_source_as_string(info, 0, alpha, texindex);
1924string ShaderGenerator::
1925combine_source_as_string(
const ShaderKey::TextureInfo &info,
short num,
bool alpha,
short texindex) {
1926 TextureStage::CombineSource c_src;
1927 TextureStage::CombineOperand c_op;
1929 c_src = UNPACK_COMBINE_SRC(info._combine_rgb, num);
1930 c_op = UNPACK_COMBINE_OP(info._combine_rgb, num);
1932 c_src = UNPACK_COMBINE_SRC(info._combine_alpha, num);
1933 c_op = UNPACK_COMBINE_OP(info._combine_alpha, num);
1935 std::ostringstream csource;
1936 if (c_op == TextureStage::CO_one_minus_src_color ||
1937 c_op == TextureStage::CO_one_minus_src_alpha) {
1938 csource <<
"saturate(1.0f - ";
1941 case TextureStage::CS_undefined:
1942 case TextureStage::CS_texture:
1943 csource <<
"tex" << texindex;
1945 case TextureStage::CS_constant:
1946 csource <<
"texcolor_" << texindex;
1948 case TextureStage::CS_primary_color:
1949 csource <<
"primary_color";
1951 case TextureStage::CS_previous:
1952 csource <<
"result";
1954 case TextureStage::CS_constant_color_scale:
1955 csource <<
"attr_colorscale";
1957 case TextureStage::CS_last_saved_result:
1958 csource <<
"last_saved_result";
1961 if (c_op == TextureStage::CO_one_minus_src_color ||
1962 c_op == TextureStage::CO_one_minus_src_alpha) {
1965 if (c_op == TextureStage::CO_src_color || c_op == TextureStage::CO_one_minus_src_color) {
1971 return "float3(" + csource.str() +
")";
1974 return csource.str();
1980const char *ShaderGenerator::
1981texture_type_as_string(Texture::TextureType ttype) {
1983 case Texture::TT_1d_texture:
1986 case Texture::TT_2d_texture:
1989 case Texture::TT_3d_texture:
1992 case Texture::TT_2d_texture_array:
1995 case Texture::TT_cube_map:
1998 case Texture::TT_buffer_texture:
2001 case Texture::TT_cube_map_array:
2004 case Texture::TT_1d_texture_array:
2008 pgraphnodes_cat.error() <<
"Unsupported texture type!\n";
2016ShaderGenerator::ShaderKey::
2022 _have_separate_ambient(false),
2025 _calc_primary_alpha(false),
2026 _disable_alpha_write(false),
2028 _alpha_test_ref(0.0),
2029 _num_clip_planes(0),
2030 _light_ramp(nullptr) {
2037bool ShaderGenerator::ShaderKey::
2038operator < (
const ShaderKey &other)
const {
2039 if (_anim_spec != other._anim_spec) {
2040 return _anim_spec < other._anim_spec;
2042 if (_color_type != other._color_type) {
2043 return _color_type < other._color_type;
2045 if (_material_flags != other._material_flags) {
2046 return _material_flags < other._material_flags;
2048 if (_texture_flags != other._texture_flags) {
2049 return _texture_flags < other._texture_flags;
2051 if (_textures.size() != other._textures.size()) {
2052 return _textures.size() < other._textures.size();
2054 for (
size_t i = 0; i < _textures.size(); ++i) {
2055 const ShaderKey::TextureInfo &tex = _textures[i];
2056 const ShaderKey::TextureInfo &other_tex = other._textures[i];
2057 if (tex._texcoord_name != other_tex._texcoord_name) {
2058 return tex._texcoord_name < other_tex._texcoord_name;
2060 if (tex._type != other_tex._type) {
2061 return tex._type < other_tex._type;
2063 if (tex._mode != other_tex._mode) {
2064 return tex._mode < other_tex._mode;
2066 if (tex._gen_mode != other_tex._gen_mode) {
2067 return tex._gen_mode < other_tex._gen_mode;
2069 if (tex._flags != other_tex._flags) {
2070 return tex._flags < other_tex._flags;
2072 if (tex._combine_rgb != other_tex._combine_rgb) {
2073 return tex._combine_rgb < other_tex._combine_rgb;
2075 if (tex._combine_alpha != other_tex._combine_alpha) {
2076 return tex._combine_alpha < other_tex._combine_alpha;
2079 if (_lights.size() != other._lights.size()) {
2080 return _lights.size() < other._lights.size();
2082 for (
size_t i = 0; i < _lights.size(); ++i) {
2083 const ShaderKey::LightInfo &light = _lights[i];
2084 const ShaderKey::LightInfo &other_light = other._lights[i];
2085 if (light._type != other_light._type) {
2086 return light._type < other_light._type;
2088 if (light._flags != other_light._flags) {
2089 return light._flags < other_light._flags;
2092 if (_lighting != other._lighting) {
2093 return _lighting < other._lighting;
2095 if (_have_separate_ambient != other._have_separate_ambient) {
2096 return _have_separate_ambient < other._have_separate_ambient;
2098 if (_fog_mode != other._fog_mode) {
2099 return _fog_mode < other._fog_mode;
2101 if (_outputs != other._outputs) {
2102 return _outputs < other._outputs;
2104 if (_calc_primary_alpha != other._calc_primary_alpha) {
2105 return _calc_primary_alpha < other._calc_primary_alpha;
2107 if (_disable_alpha_write != other._disable_alpha_write) {
2108 return _disable_alpha_write < other._disable_alpha_write;
2110 if (_alpha_test_mode != other._alpha_test_mode) {
2111 return _alpha_test_mode < other._alpha_test_mode;
2113 if (_alpha_test_ref != other._alpha_test_ref) {
2114 return _alpha_test_ref < other._alpha_test_ref;
2116 if (_num_clip_planes != other._num_clip_planes) {
2117 return _num_clip_planes < other._num_clip_planes;
2119 return _light_ramp < other._light_ramp;
2125bool ShaderGenerator::ShaderKey::
2126operator == (
const ShaderKey &other)
const {
2127 if (_anim_spec != other._anim_spec) {
2130 if (_color_type != other._color_type) {
2133 if (_material_flags != other._material_flags) {
2136 if (_texture_flags != other._texture_flags) {
2139 if (_textures.size() != other._textures.size()) {
2142 for (
size_t i = 0; i < _textures.size(); ++i) {
2143 const ShaderKey::TextureInfo &tex = _textures[i];
2144 const ShaderKey::TextureInfo &other_tex = other._textures[i];
2145 if (tex._texcoord_name != other_tex._texcoord_name ||
2146 tex._type != other_tex._type ||
2147 tex._mode != other_tex._mode ||
2148 tex._gen_mode != other_tex._gen_mode ||
2149 tex._flags != other_tex._flags ||
2150 tex._combine_rgb != other_tex._combine_rgb ||
2151 tex._combine_alpha != other_tex._combine_alpha) {
2155 if (_lights.size() != other._lights.size()) {
2158 for (
size_t i = 0; i < _lights.size(); ++i) {
2159 const ShaderKey::LightInfo &light = _lights[i];
2160 const ShaderKey::LightInfo &other_light = other._lights[i];
2161 if (light._type != other_light._type ||
2162 light._flags != other_light._flags) {
2166 return _lighting == other._lighting
2167 && _have_separate_ambient == other._have_separate_ambient
2168 && _fog_mode == other._fog_mode
2169 && _outputs == other._outputs
2170 && _calc_primary_alpha == other._calc_primary_alpha
2171 && _disable_alpha_write == other._disable_alpha_write
2172 && _alpha_test_mode == other._alpha_test_mode
2173 && _alpha_test_ref == other._alpha_test_ref
2174 && _num_clip_planes == other._num_clip_planes
2175 && _light_ramp == other._light_ramp;
2189void ShaderGenerator::
2190rehash_generated_shaders() {
2193void ShaderGenerator::
2194clear_generated_shaders() {
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Enables or disables writing of pixel to framebuffer based on its alpha value relative to a reference ...
get_reference_alpha
Returns the alpha reference value.
get_mode
Returns the alpha write mode.
Modern frame buffers can have 'aux' bitplanes, which are additional bitplanes above and beyond the st...
get_outputs
Returns the AuxBitplaneAttrib output bits.
This functions similarly to a LightAttrib.
get_num_on_planes
Returns the number of planes that are enabled by the attribute.
Indicates what color should be applied to renderable geometry.
This specifies how colors are blended into the frame buffer, for special effects.
get_mode
Returns the blending mode for the RGB channels.
Applies a Fog to the geometry at and below this node.
get_fog
If the FogAttrib is not an 'off' FogAttrib, returns the fog that is associated.
bool is_off() const
Returns true if the FogAttrib is an 'off' FogAttrib, indicating that it should disable fog.
This object describes how the vertex animation, if any, represented in a GeomVertexData is encoded.
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.
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
get_num_on_lights
Returns the number of lights that are turned on by the attribute.
get_on_light
Returns the nth light turned on by the attribute, sorted in render order.
A derivative of Light and of Camera.
is_shadow_caster
Returns whether this light is configured to cast shadows or not.
bool has_specular_color() const
Returns true if this light defines a specular color, false if the specular color is derived automatic...
void mark_used_by_auto_shader() const
Marks this light as having been used by the auto shader.
A Light Ramp is any unary operator that takes a rendered pixel as input, and adjusts the brightness o...
Similar to MutexHolder, but for a light reentrant mutex.
Indicates which, if any, material should be applied to geometry.
get_material
If the MaterialAttrib is not an 'off' MaterialAttrib, returns the material that is associated.
Defines the way an object appears in the presence of lighting.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
bool is_empty() const
Returns true if the NodePath contains no nodes.
PandaNode * node() const
Returns the referenced node of the path.
A lightweight class that represents a single element that may be timed and/or counted via stats.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
A basic node of the scene graph or data graph.
virtual bool is_ambient_light() const
Returns true if this is an AmbientLight, false if it is not a light, or it is some other kind of ligh...
void ref() const
Explicitly increments the reference count.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Specifies how polygons are to be drawn.
get_perspective
Returns the perspective flag.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
bool auto_shader() const
If true, then this ShaderAttrib does not contain an explicit shader - instead, it requests the automa...
const Key & get_key(size_t n) const
Returns the key in the nth entry of the table.
void clear()
Completely empties the table.
size_t get_num_entries() const
Returns the number of active entries in the table.
Computes texture coordinates for geometry automatically based on vertex position and/or normal.
Applies a transform matrix to UV's before they are rendered.
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
get_num_on_stages
Returns the number of stages that are turned on by the attribute.
get_on_texture
Returns the texture associated with the indicated stage, or NULL if no texture is associated.
get_on_stage
Returns the nth stage turned on by the attribute, sorted in render order.
Defines the properties of a named stage of the multitexture pipeline.
bool uses_primary_color() const
Returns true if the TextureStage makes use of the CS_primary_color combine source.
CombineMode get_combine_alpha_mode() const
Get combine_alpha_mode.
get_saved_result
Returns the current setting of the saved_result flag.
CombineOperand get_combine_rgb_operand2() const
Get operand2 of combine_rgb_mode.
CombineSource get_combine_alpha_source1() const
Get source1 of combine_alpha_mode.
CombineMode get_combine_rgb_mode() const
Get the combine_rgb_mode.
CombineSource get_combine_rgb_source1() const
Get source1 of combine_rgb_mode.
CombineOperand get_combine_alpha_operand0() const
Get operand0 of combine_alpha_mode.
CombineOperand get_combine_rgb_operand1() const
Get operand1 of combine_rgb_mode.
CombineSource get_combine_alpha_source0() const
Get source0 of combine_alpha_mode.
get_rgb_scale
See set_rgb_scale().
get_alpha_scale
See set_alpha_scale().
CombineOperand get_combine_alpha_operand1() const
Get operand1 of combine_alpha_mode.
CombineSource get_combine_rgb_source0() const
Get source0 of combine_rgb_mode.
CombineSource get_combine_rgb_source2() const
Get source2 of combine_rgb_mode.
bool uses_color() const
Returns true if the TextureStage makes use of whatever color is specified in set_color(),...
CombineOperand get_combine_rgb_operand0() const
Get operand0 of combine_rgb_mode.
CombineSource get_combine_alpha_source2() const
Get source2 of combine_alpha_mode.
get_texcoord_name
See set_texcoord_name.
bool uses_last_saved_result() const
Returns true if the TextureStage makes use of the CS_primary_color combine source.
CombineOperand get_combine_alpha_operand2() const
Get operand2 of combine_alpha_mode.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
get_format
Returns the format of the texture, which represents both the semantic meaning of the texels and,...
static bool has_alpha(Format format)
Returns true if the indicated format includes alpha, false otherwise.
This controls the enabling of transparency.
get_mode
Returns the transparency mode.
TypeHandle is the identifier used to differentiate C++ class types.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
This is our own Panda specialization on the default STL map.
This is our own Panda specialization on the default STL vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.