56 #define UNPACK_COMBINE_SRC(from, n) (TextureStage::CombineSource)((from >> ((uint16_t)n * 5u)) & 7u)
57 #define UNPACK_COMBINE_OP(from, n) (TextureStage::CombineOperand)(((from >> (((uint16_t)n * 5u) + 3u)) & 3u) + 1u)
59 static inline uint16_t
60 pack_combine(TextureStage::CombineSource src0, TextureStage::CombineOperand op0,
61 TextureStage::CombineSource src1, TextureStage::CombineOperand op1,
62 TextureStage::CombineSource src2, TextureStage::CombineOperand op2) {
63 if (op0 == TextureStage::CO_undefined) op0 = TextureStage::CO_src_alpha;
64 if (op1 == TextureStage::CO_undefined) op1 = TextureStage::CO_src_alpha;
65 if (op2 == TextureStage::CO_undefined) op2 = TextureStage::CO_src_alpha;
67 return ((uint16_t)src0) | ((((uint16_t)op0 - 1u) & 3u) << 3u) |
68 ((uint16_t)src1 << 5u) | ((((uint16_t)op1 - 1u) & 3u) << 8u) |
69 ((uint16_t)src2 << 10u) | ((((uint16_t)op2 - 1u) & 3u) << 13u);
72 static PStatCollector lookup_collector(
"*:Munge:ShaderGen:Lookup");
73 static PStatCollector synthesize_collector(
"*:Munge:ShaderGen:Synthesize");
86 _use_generic_attr = !gsg->get_supports_hlsl();
88 _use_generic_attr =
true;
93 _use_shadow_filter = gsg->get_supports_shadow_filter();
107 void ShaderGenerator::
108 reset_register_allocator() {
118 const char *ShaderGenerator::
120 if (_use_generic_attr) {
122 switch (_vtregs_used) {
123 case 0: _vtregs_used += 1;
return "ATTR8";
124 case 1: _vtregs_used += 1;
return "ATTR9";
125 case 2: _vtregs_used += 1;
return "ATTR10";
126 case 3: _vtregs_used += 1;
return "ATTR11";
127 case 4: _vtregs_used += 1;
return "ATTR12";
128 case 5: _vtregs_used += 1;
return "ATTR13";
129 case 6: _vtregs_used += 1;
return "ATTR14";
130 case 7: _vtregs_used += 1;
return "ATTR15";
132 switch (_vcregs_used) {
133 case 0: _vcregs_used += 1;
return "ATTR3";
134 case 1: _vcregs_used += 1;
return "ATTR4";
135 case 2: _vcregs_used += 1;
return "ATTR5";
136 case 3: _vcregs_used += 1;
return "ATTR6";
137 case 4: _vcregs_used += 1;
return "ATTR7";
138 case 5: _vcregs_used += 1;
return "ATTR1";
142 switch (_vtregs_used) {
143 case 0: _vtregs_used += 1;
return "TEXCOORD0";
144 case 1: _vtregs_used += 1;
return "TEXCOORD1";
145 case 2: _vtregs_used += 1;
return "TEXCOORD2";
146 case 3: _vtregs_used += 1;
return "TEXCOORD3";
147 case 4: _vtregs_used += 1;
return "TEXCOORD4";
148 case 5: _vtregs_used += 1;
return "TEXCOORD5";
149 case 6: _vtregs_used += 1;
return "TEXCOORD6";
150 case 7: _vtregs_used += 1;
return "TEXCOORD7";
152 switch (_vcregs_used) {
153 case 0: _vcregs_used += 1;
return "COLOR0";
154 case 1: _vcregs_used += 1;
return "COLOR1";
159 switch (_vtregs_used) {
160 case 8: _vtregs_used += 1;
return "TEXCOORD8";
161 case 9: _vtregs_used += 1;
return "TEXCOORD9";
162 case 10: _vtregs_used += 1;
return "TEXCOORD10";
163 case 11: _vtregs_used += 1;
return "TEXCOORD11";
164 case 12: _vtregs_used += 1;
return "TEXCOORD12";
165 case 13: _vtregs_used += 1;
return "TEXCOORD13";
166 case 14: _vtregs_used += 1;
return "TEXCOORD14";
167 case 15: _vtregs_used += 1;
return "TEXCOORD15";
175 const char *ShaderGenerator::
177 switch (_ftregs_used) {
178 case 0: _ftregs_used += 1;
return "TEXCOORD0";
179 case 1: _ftregs_used += 1;
return "TEXCOORD1";
180 case 2: _ftregs_used += 1;
return "TEXCOORD2";
181 case 3: _ftregs_used += 1;
return "TEXCOORD3";
182 case 4: _ftregs_used += 1;
return "TEXCOORD4";
183 case 5: _ftregs_used += 1;
return "TEXCOORD5";
184 case 6: _ftregs_used += 1;
return "TEXCOORD6";
185 case 7: _ftregs_used += 1;
return "TEXCOORD7";
189 switch (_ftregs_used) {
190 case 8: _ftregs_used += 1;
return "TEXCOORD8";
191 case 9: _ftregs_used += 1;
return "TEXCOORD9";
192 case 10: _ftregs_used += 1;
return "TEXCOORD10";
193 case 11: _ftregs_used += 1;
return "TEXCOORD11";
194 case 12: _ftregs_used += 1;
return "TEXCOORD12";
195 case 13: _ftregs_used += 1;
return "TEXCOORD13";
196 case 14: _ftregs_used += 1;
return "TEXCOORD14";
197 case 15: _ftregs_used += 1;
return "TEXCOORD15";
206 void ShaderGenerator::
207 analyze_renderstate(ShaderKey &key,
const RenderState *rs) {
209 rs->get_attrib_def(shader_attrib);
214 rs->get_attrib_def(aux_bitplane);
218 bool have_alpha_test =
false;
219 bool have_alpha_blend =
false;
221 rs->get_attrib_def(alpha_test);
222 if (alpha_test->
get_mode() != RenderAttrib::M_none &&
223 alpha_test->
get_mode() != RenderAttrib::M_always) {
224 have_alpha_test =
true;
227 rs->get_attrib_def(color_blend);
228 if (color_blend->
get_mode() != ColorBlendAttrib::M_none) {
229 have_alpha_blend =
true;
232 rs->get_attrib_def(transparency);
233 if (transparency->
get_mode() == TransparencyAttrib::M_alpha ||
234 transparency->
get_mode() == TransparencyAttrib::M_premultiplied_alpha ||
235 transparency->
get_mode() == TransparencyAttrib::M_dual) {
236 have_alpha_blend =
true;
240 if (key._outputs & AuxBitplaneAttrib::ABO_glow) {
241 if (have_alpha_blend) {
243 key._disable_alpha_write =
true;
244 }
else if (have_alpha_test) {
246 key._alpha_test_mode = alpha_test->
get_mode();
251 if (have_alpha_blend || have_alpha_test) {
252 key._calc_primary_alpha =
true;
257 rs->get_attrib_def(color);
262 rs->get_attrib_def(material);
264 if (mat !=
nullptr) {
267 mat->mark_used_by_auto_shader();
268 key._material_flags = mat->get_flags();
270 if ((key._material_flags & Material::F_base_color) != 0) {
271 key._material_flags |= (Material::F_diffuse | Material::F_specular | Material::F_ambient);
272 key._material_flags &= ~
Material::F_base_color;
278 rs->get_attrib_def(la);
279 bool have_ambient =
false;
285 nassertv(node !=
nullptr);
289 key._lighting =
true;
291 ShaderKey::LightInfo info;
292 info._type = node->get_type();
295 if (node->
is_of_type(LightLensNode::get_class_type())) {
297 if (shader_attrib->auto_shadow_on()) {
299 info._flags |= ShaderKey::LF_has_shadows;
307 info._flags |= ShaderKey::LF_has_specular_color;
311 key._lights.push_back(info);
312 key._lighting =
true;
320 rs->get_attrib_def(texture);
322 rs->get_attrib_def(tex_gen);
324 rs->get_attrib_def(tex_matrix);
327 for (
size_t i = 0; i < num_textures; ++i) {
330 nassertd(tex !=
nullptr) continue;
335 stage->mark_used_by_auto_shader();
337 ShaderKey::TextureInfo info;
338 info._type = tex->get_texture_type();
339 info._mode = stage->get_mode();
341 info._combine_rgb = 0u;
342 info._combine_alpha = 0u;
346 switch (info._mode) {
347 case TextureStage::M_modulate:
350 if (format != Texture::F_alpha) {
351 info._flags |= ShaderKey::TF_has_rgb;
354 info._flags |= ShaderKey::TF_has_alpha;
359 case TextureStage::M_modulate_glow:
360 if (shader_attrib->auto_glow_on()) {
361 info._flags = ShaderKey::TF_map_glow;
363 info._mode = TextureStage::M_modulate;
364 info._flags = ShaderKey::TF_has_rgb;
368 case TextureStage::M_modulate_gloss:
369 if (shader_attrib->auto_gloss_on()) {
370 info._flags = ShaderKey::TF_map_gloss;
372 info._mode = TextureStage::M_modulate;
373 info._flags = ShaderKey::TF_has_rgb;
377 case TextureStage::M_normal_height:
378 if (parallax_mapping_samples == 0) {
379 info._mode = TextureStage::M_normal;
380 }
else if (!shader_attrib->auto_normal_on() ||
381 (key._lights.empty() && (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) == 0)) {
382 info._mode = TextureStage::M_height;
383 info._flags = ShaderKey::TF_has_alpha;
385 info._flags = ShaderKey::TF_map_normal | ShaderKey::TF_map_height;
389 case TextureStage::M_normal_gloss:
390 if (!shader_attrib->auto_gloss_on() || key._lights.empty()) {
391 info._mode = TextureStage::M_normal;
392 }
else if (!shader_attrib->auto_normal_on()) {
393 info._mode = TextureStage::M_gloss;
395 info._flags = ShaderKey::TF_map_normal | ShaderKey::TF_map_gloss;
399 case TextureStage::M_combine:
405 info._flags |= ShaderKey::TF_rgb_scale_2;
408 info._flags |= ShaderKey::TF_rgb_scale_4;
411 info._flags |= ShaderKey::TF_alpha_scale_2;
414 info._flags |= ShaderKey::TF_alpha_scale_4;
417 info._combine_rgb = pack_combine(
421 info._combine_alpha = pack_combine(
427 info._flags |= ShaderKey::TF_uses_primary_color;
430 info._flags |= ShaderKey::TF_uses_last_saved_result;
440 switch (info._mode) {
441 case TextureStage::M_normal:
442 if (!shader_attrib->auto_normal_on() ||
443 (key._lights.empty() && (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) == 0)) {
446 info._flags = ShaderKey::TF_map_normal;
449 case TextureStage::M_glow:
450 if (shader_attrib->auto_glow_on()) {
451 info._flags = ShaderKey::TF_map_glow;
456 case TextureStage::M_gloss:
457 if (!key._lights.empty() && shader_attrib->auto_gloss_on()) {
458 info._flags = ShaderKey::TF_map_gloss;
463 case TextureStage::M_height:
464 if (parallax_mapping_samples > 0) {
465 info._flags = ShaderKey::TF_map_height;
470 case TextureStage::M_emission:
471 info._flags = ShaderKey::TF_map_emission;
480 info._type = Texture::TT_1d_texture;
481 info._mode = TextureStage::M_modulate;
483 key._textures.push_back(info);
489 if (tex_matrix->has_stage(stage)) {
491 if (!transform->is_identity()) {
494 if (transform->has_components() && !transform->has_nonzero_shear() &&
495 transform->get_pos() == LPoint3::zero() &&
496 transform->get_hpr() == LVecBase3::zero()) {
497 info._flags |= ShaderKey::TF_has_texscale;
499 info._flags |= ShaderKey::TF_has_texmat;
504 if (tex_gen->has_stage(stage)) {
505 info._texcoord_name =
nullptr;
506 info._gen_mode = tex_gen->get_mode(stage);
509 info._gen_mode = TexGenAttrib::M_off;
514 info._flags |= ShaderKey::TF_saved_result;
519 info._flags |= ShaderKey::TF_uses_color;
522 key._textures.push_back(info);
523 key._texture_flags |= info._flags;
527 if ((key._texture_flags & ShaderKey::TF_uses_last_saved_result) == 0 &&
528 (key._texture_flags & ShaderKey::TF_saved_result) != 0) {
531 for (it = key._textures.begin(); it != key._textures.end(); ++it) {
532 (*it)._flags &= ~ShaderKey::TF_saved_result;
534 key._texture_flags &= ~ShaderKey::TF_saved_result;
539 if (key._material_flags & Material::F_ambient) {
540 key._have_separate_ambient =
true;
542 if (key._material_flags & Material::F_diffuse) {
543 key._have_separate_ambient =
true;
545 key._have_separate_ambient =
false;
550 if (shader_attrib->auto_ramp_on()) {
552 if (rs->get_attrib(light_ramp)) {
553 key._light_ramp = light_ramp;
555 key._have_separate_ambient =
true;
562 rs->get_attrib_def(clip_plane);
567 if (rs->get_attrib(fog) && !fog->
is_off()) {
568 key._fog_mode = (int)fog->
get_fog()->get_mode() + 1;
582 void ShaderGenerator::
583 rehash_generated_shaders() {
589 for (
size_t si = 0; si < size; ++si) {
592 if (state->_generated_shader !=
nullptr) {
594 analyze_renderstate(key, state);
596 GeneratedShaders::const_iterator si;
597 si = _generated_shaders.find(key);
598 if (si != _generated_shaders.end()) {
599 if (si->second != state->_generated_shader) {
600 state->_generated_shader = si->second;
601 state->_munged_states.
clear();
605 state->_generated_shader.clear();
606 state->_munged_states.
clear();
614 if (!uniquify_states) {
615 GraphicsStateGuardianBase::mark_rehash_generated_shaders();
625 void ShaderGenerator::
626 clear_generated_shaders() {
630 for (
size_t si = 0; si < size; ++si) {
632 state->_generated_shader.clear();
635 _generated_shaders.clear();
639 if (!uniquify_states) {
640 GraphicsStateGuardianBase::mark_rehash_generated_shaders();
679 key._anim_spec = anim;
680 analyze_renderstate(key, rs);
682 GeneratedShaders::const_iterator si;
683 si = _generated_shaders.find(key);
684 if (si != _generated_shaders.end()) {
692 reset_register_allocator();
694 if (pgraphnodes_cat.is_debug()) {
695 pgraphnodes_cat.debug()
696 <<
"Generating shader for render state " << rs <<
":\n";
697 rs->write(pgraphnodes_cat.debug(
false), 2);
702 const char *tangent_freg =
nullptr;
703 const char *binormal_freg =
nullptr;
704 string tangent_input;
705 string binormal_input;
708 const char *world_position_freg =
nullptr;
709 const char *world_normal_freg =
nullptr;
710 const char *eye_position_freg =
nullptr;
711 const char *eye_normal_freg =
nullptr;
712 const char *hpos_freg =
nullptr;
714 const char *position_vreg;
715 const char *transform_weight_vreg =
nullptr;
716 const char *normal_vreg;
717 const char *color_vreg =
nullptr;
718 const char *transform_index_vreg =
nullptr;
720 if (_use_generic_attr) {
721 position_vreg =
"ATTR0";
722 transform_weight_vreg =
"ATTR1";
723 normal_vreg =
"ATTR2";
724 transform_index_vreg =
"ATTR7";
726 position_vreg =
"POSITION";
727 normal_vreg =
"NORMAL";
730 if (key._color_type == ColorAttrib::T_vertex) {
732 color_vreg = _use_generic_attr ?
"ATTR3" :
"COLOR0";
739 std::ostringstream text;
743 text <<
"/* Generated shader for render state:\n";
747 int map_index_glow = -1;
748 int map_index_gloss = -1;
749 int map_index_emission = -1;
752 bool need_world_position = (key._num_clip_planes > 0);
753 bool need_world_normal =
false;
754 bool need_eye_position = key._lighting;
755 bool need_eye_normal = !key._lights.empty() || ((key._outputs & AuxBitplaneAttrib::ABO_aux_normal) != 0);
756 bool need_tangents = ((key._texture_flags & ShaderKey::TF_map_normal) != 0);
760 bool pack_eye_normal = need_eye_normal && need_tangents && need_eye_position;
762 bool have_specular =
false;
764 if (key._material_flags & Material::F_specular) {
765 have_specular =
true;
766 }
else if ((key._texture_flags & ShaderKey::TF_map_gloss) != 0) {
767 have_specular =
true;
771 bool need_color =
false;
772 if (key._color_type != ColorAttrib::T_off) {
774 if (((key._material_flags & Material::F_ambient) == 0 && key._have_separate_ambient) ||
775 (key._material_flags & Material::F_diffuse) == 0 ||
776 key._calc_primary_alpha) {
784 text <<
"void vshader(\n";
785 for (
size_t i = 0; i < key._textures.size(); ++i) {
786 const ShaderKey::TextureInfo &tex = key._textures[i];
788 switch (tex._gen_mode) {
789 case TexGenAttrib::M_world_position:
790 need_world_position =
true;
792 case TexGenAttrib::M_world_normal:
793 need_world_normal =
true;
795 case TexGenAttrib::M_eye_position:
796 need_eye_position =
true;
798 case TexGenAttrib::M_eye_normal:
799 need_eye_normal =
true;
805 if (tex._texcoord_name !=
nullptr) {
806 if (texcoord_fregs.count(tex._texcoord_name) == 0) {
807 const char *freg = alloc_freg();
808 texcoord_fregs[tex._texcoord_name] = freg;
810 string tcname = tex._texcoord_name->join(
"_");
811 text <<
"\t in float4 vtx_" << tcname <<
" : " << alloc_vreg() <<
",\n";
812 text <<
"\t out float4 l_" << tcname <<
" : " << freg <<
",\n";
816 if (tangent_input.empty() &&
817 (tex._flags & (ShaderKey::TF_map_normal | ShaderKey::TF_map_height)) != 0) {
818 PT(
InternalName) tangent_name = InternalName::get_tangent();
819 PT(
InternalName) binormal_name = InternalName::get_binormal();
821 if (tex._texcoord_name !=
nullptr &&
822 tex._texcoord_name != InternalName::get_texcoord()) {
823 tangent_name = tangent_name->append(tex._texcoord_name->get_basename());
824 binormal_name = binormal_name->append(tex._texcoord_name->get_basename());
827 tangent_input = tangent_name->join(
"_");
828 binormal_input = binormal_name->join(
"_");
830 text <<
"\t in float4 vtx_" << tangent_input <<
" : " << alloc_vreg() <<
",\n";
831 text <<
"\t in float4 vtx_" << binormal_input <<
" : " << alloc_vreg() <<
",\n";
834 if (tex._flags & ShaderKey::TF_map_glow) {
837 if (tex._flags & ShaderKey::TF_map_gloss) {
840 if (tex._flags & ShaderKey::TF_map_emission) {
841 map_index_emission = i;
845 tangent_freg = alloc_freg();
846 binormal_freg = alloc_freg();
847 text <<
"\t out float4 l_tangent : " << tangent_freg <<
",\n";
848 text <<
"\t out float4 l_binormal : " << binormal_freg <<
",\n";
850 if (need_color && key._color_type == ColorAttrib::T_vertex) {
851 text <<
"\t in float4 vtx_color : " << color_vreg <<
",\n";
852 text <<
"\t out float4 l_color : COLOR0,\n";
854 if (need_world_position || need_world_normal) {
855 text <<
"\t uniform float4x4 trans_model_to_world,\n";
857 if (need_world_position) {
858 world_position_freg = alloc_freg();
859 text <<
"\t out float4 l_world_position : " << world_position_freg <<
",\n";
861 if (need_world_normal) {
862 world_normal_freg = alloc_freg();
863 text <<
"\t out float4 l_world_normal : " << world_normal_freg <<
",\n";
865 if (need_eye_position) {
866 text <<
"\t uniform float4x4 trans_model_to_view,\n";
867 eye_position_freg = alloc_freg();
868 text <<
"\t out float4 l_eye_position : " << eye_position_freg <<
",\n";
869 }
else if (need_tangents) {
870 text <<
"\t uniform float4x4 trans_model_to_view,\n";
872 if (need_eye_normal) {
873 text <<
"\t uniform float4x4 tpose_view_to_model,\n";
874 if (!pack_eye_normal) {
875 eye_normal_freg = alloc_freg();
876 text <<
"\t out float3 l_eye_normal : " << eye_normal_freg <<
",\n";
879 if ((key._texture_flags & ShaderKey::TF_map_height) != 0 || need_world_normal || need_eye_normal) {
880 text <<
"\t in float3 vtx_normal : " << normal_vreg <<
",\n";
882 if (key._texture_flags & ShaderKey::TF_map_height) {
883 text <<
"\t uniform float4 mspos_view,\n";
884 text <<
"\t out float3 l_eyevec,\n";
886 if (key._fog_mode != 0) {
887 hpos_freg = alloc_freg();
888 text <<
"\t out float4 l_hpos : " << hpos_freg <<
",\n";
890 for (
size_t i = 0; i < key._lights.size(); ++i) {
891 const ShaderKey::LightInfo &light = key._lights[i];
892 if (light._flags & ShaderKey::LF_has_shadows) {
893 if (_ftregs_used >= 8) {
896 lightcoord_fregs.push_back(
nullptr);
898 lightcoord_fregs.push_back(alloc_freg());
899 text <<
"\t uniform float4x4 mat_shadow_" << i <<
",\n";
900 text <<
"\t out float4 l_lightcoord" << i <<
" : " << lightcoord_fregs[i] <<
",\n";
903 lightcoord_fregs.push_back(
nullptr);
906 if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware &&
907 key._anim_spec.get_num_transforms() > 0) {
909 if (key._anim_spec.get_indexed_transforms()) {
910 num_transforms = 120;
912 num_transforms = key._anim_spec.get_num_transforms();
914 if (transform_weight_vreg ==
nullptr) {
915 transform_weight_vreg = alloc_vreg();
917 if (transform_index_vreg ==
nullptr) {
918 transform_index_vreg = alloc_vreg();
920 text <<
"\t uniform float4x4 tbl_transforms[" << num_transforms <<
"],\n";
921 text <<
"\t in float4 vtx_transform_weight : " << transform_weight_vreg <<
",\n";
922 if (key._anim_spec.get_indexed_transforms()) {
923 text <<
"\t in uint4 vtx_transform_index : " << transform_index_vreg <<
",\n";
926 text <<
"\t in float4 vtx_position : " << position_vreg <<
",\n";
927 text <<
"\t out float4 l_position : POSITION,\n";
928 text <<
"\t uniform float4x4 mat_modelproj\n";
931 if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware &&
932 key._anim_spec.get_num_transforms() > 0) {
934 if (!key._anim_spec.get_indexed_transforms()) {
935 text <<
"\t const uint4 vtx_transform_index = uint4(0, 1, 2, 3);\n";
938 text <<
"\t float4x4 matrix = tbl_transforms[vtx_transform_index.x] * vtx_transform_weight.x";
939 if (key._anim_spec.get_num_transforms() > 1) {
940 text <<
"\n\t + tbl_transforms[vtx_transform_index.y] * vtx_transform_weight.y";
942 if (key._anim_spec.get_num_transforms() > 2) {
943 text <<
"\n\t + tbl_transforms[vtx_transform_index.z] * vtx_transform_weight.z";
945 if (key._anim_spec.get_num_transforms() > 3) {
946 text <<
"\n\t + tbl_transforms[vtx_transform_index.w] * vtx_transform_weight.w";
950 text <<
"\t vtx_position = mul(matrix, vtx_position);\n";
951 if (need_world_normal || need_eye_normal) {
952 text <<
"\t vtx_normal = mul((float3x3)matrix, vtx_normal);\n";
956 text <<
"\t l_position = mul(mat_modelproj, vtx_position);\n";
957 if (key._fog_mode != 0) {
958 text <<
"\t l_hpos = l_position;\n";
960 if (need_world_position) {
961 text <<
"\t l_world_position = mul(trans_model_to_world, vtx_position);\n";
963 if (need_world_normal) {
964 text <<
"\t l_world_normal = mul(trans_model_to_world, float4(vtx_normal, 0));\n";
966 if (need_eye_position) {
967 text <<
"\t l_eye_position = mul(trans_model_to_view, vtx_position);\n";
970 for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
972 string tcname = it->first->join(
"_");
973 text <<
"\t l_" << tcname <<
" = vtx_" << tcname <<
";\n";
975 if (need_color && key._color_type == ColorAttrib::T_vertex) {
976 text <<
"\t l_color = vtx_color;\n";
979 text <<
"\t l_tangent.xyz = normalize(mul((float3x3)trans_model_to_view, vtx_" << tangent_input <<
".xyz));\n";
980 text <<
"\t l_tangent.w = 0;\n";
981 text <<
"\t l_binormal.xyz = normalize(mul((float3x3)trans_model_to_view, -vtx_" << binormal_input <<
".xyz));\n";
982 text <<
"\t l_binormal.w = 0;\n";
984 for (
size_t i = 0; i < key._lights.size(); ++i) {
985 if (key._lights[i]._flags & ShaderKey::LF_has_shadows) {
986 if (lightcoord_fregs[i] !=
nullptr) {
987 text <<
"\t l_lightcoord" << i <<
" = mul(mat_shadow_" << i <<
", l_eye_position);\n";
991 if (key._texture_flags & ShaderKey::TF_map_height) {
992 text <<
"\t float3 eyedir = mspos_view.xyz - vtx_position.xyz;\n";
993 text <<
"\t l_eyevec.x = dot(vtx_" << tangent_input <<
".xyz, eyedir);\n";
994 text <<
"\t l_eyevec.y = dot(vtx_" << binormal_input <<
".xyz, eyedir);\n";
995 text <<
"\t l_eyevec.z = dot(vtx_normal, eyedir);\n";
996 text <<
"\t l_eyevec = normalize(l_eyevec);\n";
998 if (need_eye_normal) {
999 if (pack_eye_normal) {
1001 text <<
"\t float3 eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n";
1002 text <<
"\t l_tangent.w = eye_normal.x;\n";
1003 text <<
"\t l_binormal.w = eye_normal.y;\n";
1004 text <<
"\t l_eye_position.w = eye_normal.z;\n";
1006 text <<
"\t l_eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n";
1013 text <<
"void fshader(\n";
1014 if (key._fog_mode != 0) {
1015 text <<
"\t in float4 l_hpos : " << hpos_freg <<
",\n";
1016 text <<
"\t in uniform float4 attr_fog,\n";
1017 text <<
"\t in uniform float4 attr_fogcolor,\n";
1019 if (need_world_position) {
1020 text <<
"\t in float4 l_world_position : " << world_position_freg <<
",\n";
1022 if (need_world_normal) {
1023 text <<
"\t in float4 l_world_normal : " << world_normal_freg <<
",\n";
1025 if (need_eye_position) {
1026 text <<
"\t in float4 l_eye_position : " << eye_position_freg <<
",\n";
1028 if (need_eye_normal && !pack_eye_normal) {
1029 text <<
"\t in float3 l_eye_normal : " << eye_normal_freg <<
",\n";
1031 for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
1032 text <<
"\t in float4 l_" << it->first->join(
"_") <<
" : " << it->second <<
",\n";
1034 for (
size_t i = 0; i < key._textures.size(); ++i) {
1035 const ShaderKey::TextureInfo &tex = key._textures[i];
1036 if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1041 text <<
"\t uniform sampler" << texture_type_as_string(tex._type) <<
" tex_" << i <<
",\n";
1043 if (tex._flags & ShaderKey::TF_has_texscale) {
1044 text <<
"\t uniform float3 texscale_" << i <<
",\n";
1045 }
else if (tex._flags & ShaderKey::TF_has_texmat) {
1046 text <<
"\t uniform float4x4 texmat_" << i <<
",\n";
1049 if (tex._flags & ShaderKey::TF_uses_color) {
1050 text <<
"\t uniform float4 texcolor_" << i <<
",\n";
1053 if (need_tangents) {
1054 text <<
"\t in float4 l_tangent : " << tangent_freg <<
",\n";
1055 text <<
"\t in float4 l_binormal : " << binormal_freg <<
",\n";
1057 for (
size_t i = 0; i < key._lights.size(); ++i) {
1058 text <<
"\t uniform float4x4 attr_light" << i <<
",\n";
1060 const ShaderKey::LightInfo &light = key._lights[i];
1061 if (light._flags & ShaderKey::LF_has_shadows) {
1062 if (light._type.is_derived_from(PointLight::get_class_type())) {
1063 text <<
"\t uniform samplerCUBE shadow_" << i <<
",\n";
1064 }
else if (_use_shadow_filter) {
1065 text <<
"\t uniform sampler2DShadow shadow_" << i <<
",\n";
1067 text <<
"\t uniform sampler2D shadow_" << i <<
",\n";
1069 if (lightcoord_fregs[i] !=
nullptr) {
1070 text <<
"\t in float4 l_lightcoord" << i <<
" : " << lightcoord_fregs[i] <<
",\n";
1072 text <<
"\t uniform float4x4 mat_shadow_" << i <<
",\n";
1075 if (light._flags & ShaderKey::LF_has_specular_color) {
1076 text <<
"\t uniform float4 attr_lspec" << i <<
",\n";
1081 if (key._material_flags & (Material::F_ambient | Material::F_diffuse | Material::F_emission | Material::F_specular)) {
1082 text <<
"\t uniform float4x4 attr_material,\n";
1084 if (key._texture_flags & ShaderKey::TF_map_height) {
1085 text <<
"\t float3 l_eyevec,\n";
1087 if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
1088 text <<
"\t out float4 o_aux : COLOR1,\n";
1090 text <<
"\t out float4 o_color : COLOR0,\n";
1093 if (key._color_type == ColorAttrib::T_vertex) {
1094 text <<
"\t in float4 l_color : COLOR0,\n";
1095 }
else if (key._color_type == ColorAttrib::T_flat) {
1096 text <<
"\t uniform float4 attr_color,\n";
1100 for (
int i = 0; i < key._num_clip_planes; ++i) {
1101 text <<
"\t uniform float4 clipplane_" << i <<
",\n";
1104 if (key._lighting) {
1105 text <<
"\t uniform float4 attr_ambient,\n";
1107 text <<
"\t uniform float4 attr_colorscale\n";
1111 for (
int i = 0; i < key._num_clip_planes; ++i) {
1112 text <<
"\t if (l_world_position.x * clipplane_" << i <<
".x + l_world_position.y ";
1113 text <<
"* clipplane_" << i <<
".y + l_world_position.z * clipplane_" << i <<
".z + clipplane_" << i <<
".w <= 0) {\n";
1114 text <<
"\t discard;\n";
1119 if (need_eye_normal && pack_eye_normal) {
1120 text <<
"\t float3 l_eye_normal = float3(l_tangent.w, l_binormal.w, l_eye_position.w);\n";
1123 text <<
"\t float4 result;\n";
1124 if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
1125 text <<
"\t o_aux = float4(0, 0, 0, 0);\n";
1129 for (
size_t i = 0; i < key._textures.size(); ++i) {
1130 const ShaderKey::TextureInfo &tex = key._textures[i];
1131 if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1135 switch (tex._gen_mode) {
1136 case TexGenAttrib::M_off:
1138 text <<
"\t float4 texcoord" << i <<
" = l_" << tex._texcoord_name->join(
"_") <<
";\n";
1140 case TexGenAttrib::M_world_position:
1141 text <<
"\t float4 texcoord" << i <<
" = l_world_position;\n";
1143 case TexGenAttrib::M_world_normal:
1144 text <<
"\t float4 texcoord" << i <<
" = l_world_normal;\n";
1146 case TexGenAttrib::M_eye_position:
1147 text <<
"\t float4 texcoord" << i <<
" = float4(l_eye_position.xyz, 1.0f);\n";
1149 case TexGenAttrib::M_eye_normal:
1150 text <<
"\t float4 texcoord" << i <<
" = float4(l_eye_normal, 1.0f);\n";
1153 text <<
"\t float4 texcoord" << i <<
" = float4(0, 0, 0, 0);\n";
1154 pgraphnodes_cat.error()
1155 <<
"Unsupported TexGenAttrib mode: " << tex._gen_mode <<
"\n";
1157 if (tex._flags & ShaderKey::TF_has_texscale) {
1158 text <<
"\t texcoord" << i <<
".xyz *= texscale_" << i <<
";\n";
1159 }
else if (tex._flags & ShaderKey::TF_has_texmat) {
1160 text <<
"\t texcoord" << i <<
" = mul(texmat_" << i <<
", texcoord" << i <<
");\n";
1161 text <<
"\t texcoord" << i <<
".xyz /= texcoord" << i <<
".w;\n";
1164 text <<
"\t // Fetch all textures.\n";
1165 for (
size_t i = 0; i < key._textures.size(); ++i) {
1166 const ShaderKey::TextureInfo &tex = key._textures[i];
1167 if ((tex._flags & ShaderKey::TF_map_height) == 0) {
1171 text <<
"\t float4 tex" << i <<
" = tex" << texture_type_as_string(tex._type);
1172 text <<
"(tex_" << i <<
", texcoord" << i <<
".";
1173 switch (tex._type) {
1174 case Texture::TT_cube_map:
1175 case Texture::TT_3d_texture:
1176 case Texture::TT_2d_texture_array:
1179 case Texture::TT_2d_texture:
1182 case Texture::TT_1d_texture:
1188 text <<
");\n\t float3 parallax_offset = l_eyevec.xyz * (tex" << i;
1189 if (tex._mode == TextureStage::M_normal_height ||
1190 (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1195 text <<
" * 2.0 - 1.0) * " << parallax_mapping_scale <<
";\n";
1197 for (
int j = 0; j < parallax_mapping_samples - 1; ++j) {
1198 text <<
"\t parallax_offset = l_eyevec.xyz * (parallax_offset + (tex" << i;
1199 if (tex._mode == TextureStage::M_normal_height ||
1200 (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1205 text <<
" * 2.0 - 1.0)) * " << 0.5 * parallax_mapping_scale <<
";\n";
1208 for (
size_t i = 0; i < key._textures.size(); ++i) {
1209 ShaderKey::TextureInfo &tex = key._textures[i];
1210 if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1214 if ((tex._flags & ShaderKey::TF_map_height) == 0) {
1217 if (key._texture_flags & ShaderKey::TF_map_height) {
1218 text <<
"\t texcoord" << i <<
".xyz -= parallax_offset;\n";
1220 text <<
"\t float4 tex" << i <<
" = tex" << texture_type_as_string(tex._type);
1221 text <<
"(tex_" << i <<
", texcoord" << i <<
".";
1222 switch (tex._type) {
1223 case Texture::TT_cube_map:
1224 case Texture::TT_3d_texture:
1225 case Texture::TT_2d_texture_array:
1228 case Texture::TT_2d_texture:
1231 case Texture::TT_1d_texture:
1240 if (need_eye_normal) {
1241 text <<
"\t // Correct the surface normal for interpolation effects\n";
1242 text <<
"\t l_eye_normal = normalize(l_eye_normal);\n";
1244 if (need_tangents) {
1245 text <<
"\t // Translate tangent-space normal in map to view-space.\n";
1248 bool is_first =
true;
1249 for (
size_t i = 0; i < key._textures.size(); ++i) {
1250 const ShaderKey::TextureInfo &tex = key._textures[i];
1251 if (tex._flags & ShaderKey::TF_map_normal) {
1253 if (tex._flags & ShaderKey::TF_has_texscale) {
1254 text <<
"\t float3 tsnormal = normalize(((tex" << i <<
".xyz * 2) - 1) * texscale_" << i <<
");\n";
1255 }
else if (tex._flags & ShaderKey::TF_has_texmat) {
1256 text <<
"\t float3 tsnormal = normalize(mul(texmat_" << i <<
", float4((tex" << i <<
".xyz * 2) - 1, 0)).xyz);\n";
1258 text <<
"\t float3 tsnormal = normalize((tex" << i <<
".xyz * 2) - 1);\n";
1263 text <<
"\t tsnormal.z += 1;\n";
1264 text <<
"\t float3 tmp" << i <<
" = tex" << i <<
".xyz * float3(-2, -2, 2) + float3(1, 1, -1);\n";
1265 if (tex._flags & ShaderKey::TF_has_texscale) {
1266 text <<
"\t tmp" << i <<
" *= texscale_" << i <<
";\n";
1267 }
else if (tex._flags & ShaderKey::TF_has_texmat) {
1268 text <<
"\t tmp" << i <<
" = mul(texmat_" << i <<
", float4(tmp" << i <<
", 0)).xyz;\n";
1270 text <<
"\t tsnormal = normalize(tsnormal * dot(tsnormal, tmp" << i <<
") - tmp" << i <<
" * tsnormal.z);\n";
1273 text <<
"\t l_eye_normal *= tsnormal.z;\n";
1274 text <<
"\t l_eye_normal += normalize(l_tangent.xyz) * tsnormal.x;\n";
1275 text <<
"\t l_eye_normal += normalize(l_binormal.xyz) * tsnormal.y;\n";
1276 text <<
"\t l_eye_normal = normalize(l_eye_normal);\n";
1278 if (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) {
1279 text <<
"\t // Output the camera-space surface normal\n";
1280 text <<
"\t o_aux.rgb = (l_eye_normal*0.5) + float3(0.5,0.5,0.5);\n";
1282 if (key._lighting) {
1283 text <<
"\t // Begin view-space light calculations\n";
1284 text <<
"\t float ldist,lattenv,langle,lshad;\n";
1285 text <<
"\t float4 lcolor,lspec,lpoint,latten,ldir,leye;\n";
1286 text <<
"\t float3 lvec,lhalf;\n";
1287 if (key._have_separate_ambient) {
1288 text <<
"\t float4 tot_ambient = float4(0,0,0,0);\n";
1290 text <<
"\t float4 tot_diffuse = float4(0,0,0,0);\n";
1291 if (have_specular) {
1292 text <<
"\t float4 tot_specular = float4(0,0,0,0);\n";
1293 if (key._material_flags & Material::F_specular) {
1294 text <<
"\t float shininess = attr_material[3].w;\n";
1296 text <<
"\t float shininess = 50; // no shininess specified, using default\n";
1299 if (key._have_separate_ambient) {
1300 text <<
"\t tot_ambient += attr_ambient;\n";
1302 text <<
"\t tot_diffuse += attr_ambient;\n";
1305 for (
size_t i = 0; i < key._lights.size(); ++i) {
1306 const ShaderKey::LightInfo &light = key._lights[i];
1308 if (light._flags & ShaderKey::LF_has_shadows) {
1309 if (lightcoord_fregs[i] ==
nullptr) {
1312 text <<
"\t float4 l_lightcoord" << i <<
" = mul(mat_shadow_" << i <<
", float4(l_eye_position.xyz, 1.0f));\n";
1316 if (light._type.is_derived_from(DirectionalLight::get_class_type())) {
1317 text <<
"\t // Directional Light " << i <<
"\n";
1318 text <<
"\t lcolor = attr_light" << i <<
"[0];\n";
1319 if (light._flags & ShaderKey::LF_has_specular_color) {
1320 text <<
"\t lspec = attr_lspec" << i <<
";\n";
1322 text <<
"\t lspec = lcolor;\n";
1324 text <<
"\t lvec = attr_light" << i <<
"[3].xyz;\n";
1325 text <<
"\t lcolor *= saturate(dot(l_eye_normal, lvec.xyz));\n";
1326 if (light._flags & ShaderKey::LF_has_shadows) {
1327 if (_use_shadow_filter) {
1328 text <<
"\t lshad = shadow2DProj(shadow_" << i <<
", l_lightcoord" << i <<
").r;\n";
1330 text <<
"\t lshad = tex2Dproj(shadow_" << i <<
", l_lightcoord" << i <<
").r > l_lightcoord" << i <<
".z / l_lightcoord" << i <<
".w;\n";
1332 text <<
"\t lcolor *= lshad;\n";
1333 text <<
"\t lspec *= lshad;\n";
1335 text <<
"\t tot_diffuse += lcolor;\n";
1336 if (have_specular) {
1337 if (key._material_flags & Material::F_local) {
1338 text <<
"\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1340 text <<
"\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1342 text <<
"\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1343 text <<
"\t tot_specular += lspec;\n";
1345 }
else if (light._type.is_derived_from(PointLight::get_class_type())) {
1346 text <<
"\t // Point Light " << i <<
"\n";
1347 text <<
"\t lcolor = attr_light" << i <<
"[0];\n";
1348 if (light._flags & ShaderKey::LF_has_specular_color) {
1349 text <<
"\t lspec = attr_lspec" << i <<
";\n";
1351 text <<
"\t lspec = lcolor;\n";
1353 text <<
"\t latten = attr_light" << i <<
"[1];\n";
1354 text <<
"\t lpoint = attr_light" << i <<
"[3];\n";
1355 text <<
"\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
1356 text <<
"\t ldist = length(lvec);\n";
1357 text <<
"\t lvec /= ldist;\n";
1358 if (light._type.is_derived_from(SphereLight::get_class_type())) {
1359 text <<
"\t ldist = max(ldist, attr_light" << i <<
"[2].w);\n";
1361 text <<
"\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1362 text <<
"\t lcolor *= lattenv * saturate(dot(l_eye_normal, lvec));\n";
1363 if (light._flags & ShaderKey::LF_has_shadows) {
1364 text <<
"\t ldist = max(abs(l_lightcoord" << i <<
".x), max(abs(l_lightcoord" << i <<
".y), abs(l_lightcoord" << i <<
".z)));\n";
1365 text <<
"\t ldist = ((latten.w+lpoint.w)/(latten.w-lpoint.w))+((-2*latten.w*lpoint.w)/(ldist * (latten.w-lpoint.w)));\n";
1366 text <<
"\t lshad = texCUBE(shadow_" << i <<
", l_lightcoord" << i <<
".xyz).r >= ldist * 0.5 + 0.5;\n";
1367 text <<
"\t lcolor *= lshad;\n";
1368 text <<
"\t lspec *= lshad;\n";
1370 text <<
"\t tot_diffuse += lcolor;\n";
1371 if (have_specular) {
1372 if (key._material_flags & Material::F_local) {
1373 text <<
"\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1375 text <<
"\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1377 text <<
"\t lspec *= lattenv;\n";
1378 text <<
"\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1379 text <<
"\t tot_specular += lspec;\n";
1381 }
else if (light._type.is_derived_from(Spotlight::get_class_type())) {
1382 text <<
"\t // Spot Light " << i <<
"\n";
1383 text <<
"\t lcolor = attr_light" << i <<
"[0];\n";
1384 if (light._flags & ShaderKey::LF_has_specular_color) {
1385 text <<
"\t lspec = attr_lspec" << i <<
";\n";
1387 text <<
"\t lspec = lcolor;\n";
1389 text <<
"\t latten = attr_light" << i <<
"[1];\n";
1390 text <<
"\t ldir = attr_light" << i <<
"[2];\n";
1391 text <<
"\t lpoint = attr_light" << i <<
"[3];\n";
1392 text <<
"\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
1393 text <<
"\t ldist = length(lvec);\n";
1394 text <<
"\t lvec /= ldist;\n";
1395 text <<
"\t langle = saturate(dot(ldir.xyz, lvec));\n";
1396 text <<
"\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1397 text <<
"\t lattenv *= pow(langle, latten.w);\n";
1398 text <<
"\t if (langle < ldir.w) lattenv = 0;\n";
1399 text <<
"\t lcolor *= lattenv * saturate(dot(l_eye_normal, lvec));\n";
1400 if (light._flags & ShaderKey::LF_has_shadows) {
1401 if (_use_shadow_filter) {
1402 text <<
"\t lshad = shadow2DProj(shadow_" << i <<
", l_lightcoord" << i <<
").r;\n";
1404 text <<
"\t lshad = tex2Dproj(shadow_" << i <<
", l_lightcoord" << i <<
").r > l_lightcoord" << i <<
".z / l_lightcoord" << i <<
".w;\n";
1406 text <<
"\t lcolor *= lshad;\n";
1407 text <<
"\t lspec *= lshad;\n";
1410 text <<
"\t tot_diffuse += lcolor;\n";
1411 if (have_specular) {
1412 if (key._material_flags & Material::F_local) {
1413 text <<
"\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1415 text <<
"\t lhalf = normalize(lvec - float3(0,1,0));\n";
1417 text <<
"\t lspec *= lattenv;\n";
1418 text <<
"\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1419 text <<
"\t tot_specular += lspec;\n";
1423 if (key._lighting) {
1424 if (key._light_ramp !=
nullptr) {
1425 switch (key._light_ramp->get_mode()) {
1426 case LightRampAttrib::LRT_single_threshold:
1428 PN_stdfloat t = key._light_ramp->get_threshold(0);
1429 PN_stdfloat l0 = key._light_ramp->get_level(0);
1430 text <<
"\t // Single-threshold light ramp\n";
1431 text <<
"\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1432 text <<
"\t float lr_scale = (lr_in < " << t <<
") ? 0.0 : (" << l0 <<
"/lr_in);\n";
1433 text <<
"\t tot_diffuse = tot_diffuse * lr_scale;\n";
1436 case LightRampAttrib::LRT_double_threshold:
1438 PN_stdfloat t0 = key._light_ramp->get_threshold(0);
1439 PN_stdfloat t1 = key._light_ramp->get_threshold(1);
1440 PN_stdfloat l0 = key._light_ramp->get_level(0);
1441 PN_stdfloat l1 = key._light_ramp->get_level(1);
1442 text <<
"\t // Double-threshold light ramp\n";
1443 text <<
"\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1444 text <<
"\t float lr_out = 0.0;\n";
1445 text <<
"\t if (lr_in > " << t0 <<
") lr_out=" << l0 <<
";\n";
1446 text <<
"\t if (lr_in > " << t1 <<
") lr_out=" << l1 <<
";\n";
1447 text <<
"\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n";
1454 text <<
"\t // Begin view-space light summation\n";
1455 if (key._material_flags & Material::F_emission) {
1456 text <<
"\t result = attr_material[2];\n";
1457 }
else if (key._texture_flags & (ShaderKey::TF_map_glow | ShaderKey::TF_map_emission)) {
1458 text <<
"\t result = float4(1,1,1,0);\n";
1460 text <<
"\t result = float4(0,0,0,0);\n";
1462 if (key._texture_flags & ShaderKey::TF_map_emission) {
1463 text <<
"\t result.rgb *= tex" << map_index_emission <<
".rgb;\n";
1465 if (key._texture_flags & ShaderKey::TF_map_glow) {
1466 text <<
"\t result *= saturate(2 * (tex" << map_index_glow <<
".a - 0.5));\n";
1468 if (key._have_separate_ambient) {
1469 if (key._material_flags & Material::F_ambient) {
1470 text <<
"\t result += tot_ambient * attr_material[0];\n";
1471 }
else if (key._color_type == ColorAttrib::T_vertex) {
1472 text <<
"\t result += tot_ambient * l_color;\n";
1473 }
else if (key._color_type == ColorAttrib::T_flat) {
1474 text <<
"\t result += tot_ambient * attr_color;\n";
1476 text <<
"\t result += tot_ambient;\n";
1479 if (key._material_flags & Material::F_diffuse) {
1480 text <<
"\t result += tot_diffuse * attr_material[1];\n";
1481 }
else if (key._color_type == ColorAttrib::T_vertex) {
1482 text <<
"\t result += tot_diffuse * l_color;\n";
1483 }
else if (key._color_type == ColorAttrib::T_flat) {
1484 text <<
"\t result += tot_diffuse * attr_color;\n";
1486 text <<
"\t result += tot_diffuse;\n";
1488 if (key._light_ramp ==
nullptr ||
1489 key._light_ramp->get_mode() == LightRampAttrib::LRT_default) {
1490 text <<
"\t result = saturate(result);\n";
1492 text <<
"\t // End view-space light calculations\n";
1496 if (key._calc_primary_alpha) {
1497 if (key._material_flags & Material::F_diffuse) {
1498 text <<
"\t result.a = attr_material[1].w;\n";
1499 }
else if (key._color_type == ColorAttrib::T_vertex) {
1500 text <<
"\t result.a = l_color.a;\n";
1501 }
else if (key._color_type == ColorAttrib::T_flat) {
1502 text <<
"\t result.a = attr_color.a;\n";
1504 text <<
"\t result.a = 1;\n";
1508 if (key._color_type == ColorAttrib::T_vertex) {
1509 text <<
"\t result = l_color;\n";
1510 }
else if (key._color_type == ColorAttrib::T_flat) {
1511 text <<
"\t result = attr_color;\n";
1513 text <<
"\t result = float4(1, 1, 1, 1);\n";
1518 text <<
"\t result *= attr_colorscale;\n";
1521 if (key._texture_flags & ShaderKey::TF_uses_primary_color) {
1522 text <<
"\t float4 primary_color = result;\n";
1524 if (key._texture_flags & ShaderKey::TF_uses_last_saved_result) {
1525 text <<
"\t float4 last_saved_result = result;\n";
1529 for (
size_t i = 0; i < key._textures.size(); ++i) {
1530 const ShaderKey::TextureInfo &tex = key._textures[i];
1531 TextureStage::CombineMode combine_rgb, combine_alpha;
1533 switch (tex._mode) {
1534 case TextureStage::M_modulate:
1535 if ((tex._flags & ShaderKey::TF_has_rgb) != 0 &&
1536 (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1537 text <<
"\t result.rgba *= tex" << i <<
".rgba;\n";
1538 }
else if (tex._flags & ShaderKey::TF_has_alpha) {
1539 text <<
"\t result.a *= tex" << i <<
".a;\n";
1540 }
else if (tex._flags & ShaderKey::TF_has_rgb) {
1541 text <<
"\t result.rgb *= tex" << i <<
".rgb;\n";
1544 case TextureStage::M_modulate_glow:
1545 case TextureStage::M_modulate_gloss:
1551 text <<
"\t result.rgb *= tex" << i <<
";\n";
1553 case TextureStage::M_decal:
1554 text <<
"\t result.rgb = lerp(result, tex" << i <<
", tex" << i <<
".a).rgb;\n";
1556 case TextureStage::M_blend:
1557 text <<
"\t result.rgb = lerp(result.rgb, texcolor_" << i <<
".rgb, tex" << i <<
".rgb);\n";
1558 if (key._calc_primary_alpha) {
1559 text <<
"\t result.a *= tex" << i <<
".a;\n";
1562 case TextureStage::M_replace:
1563 text <<
"\t result = tex" << i <<
";\n";
1565 case TextureStage::M_add:
1566 text <<
"\t result.rgb += tex" << i <<
".rgb;\n";
1567 if (key._calc_primary_alpha) {
1568 text <<
"\t result.a *= tex" << i <<
".a;\n";
1571 case TextureStage::M_combine:
1572 combine_rgb = (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_RGB_MODE_MASK) >> ShaderKey::TF_COMBINE_RGB_MODE_SHIFT);
1573 combine_alpha = (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_ALPHA_MODE_MASK) >> ShaderKey::TF_COMBINE_ALPHA_MODE_SHIFT);
1574 if (combine_rgb == TextureStage::CM_dot3_rgba) {
1575 text <<
"\t result = ";
1576 text << combine_mode_as_string(tex, combine_rgb,
false, i);
1579 text <<
"\t result.rgb = ";
1580 text << combine_mode_as_string(tex, combine_rgb,
false, i);
1581 text <<
";\n\t result.a = ";
1582 text << combine_mode_as_string(tex, combine_alpha,
true, i);
1585 if (tex._flags & ShaderKey::TF_rgb_scale_2) {
1586 text <<
"\t result.rgb *= 2;\n";
1588 if (tex._flags & ShaderKey::TF_rgb_scale_4) {
1589 text <<
"\t result.rgb *= 4;\n";
1591 if (tex._flags & ShaderKey::TF_alpha_scale_2) {
1592 text <<
"\t result.a *= 2;\n";
1594 if (tex._flags & ShaderKey::TF_alpha_scale_4) {
1595 text <<
"\t result.a *= 4;\n";
1598 case TextureStage::M_blend_color_scale:
1599 text <<
"\t result.rgb = lerp(result.rgb, texcolor_" << i <<
".rgb * attr_colorscale.rgb, tex" << i <<
".rgb);\n";
1600 if (key._calc_primary_alpha) {
1601 text <<
"\t result.a *= texcolor_" << i <<
".a * attr_colorscale.a;\n";
1607 if (tex._flags & ShaderKey::TF_saved_result) {
1608 text <<
"\t last_saved_result = result;\n";
1612 if (key._alpha_test_mode != RenderAttrib::M_none) {
1613 text <<
"\t // Shader includes alpha test:\n";
1614 double ref = key._alpha_test_ref;
1615 switch (key._alpha_test_mode) {
1616 case RenderAttrib::M_never:
1617 text <<
"\t discard;\n";
1619 case RenderAttrib::M_less:
1620 text <<
"\t if (result.a >= " <<
ref <<
") discard;\n";
1622 case RenderAttrib::M_equal:
1623 text <<
"\t if (result.a != " <<
ref <<
") discard;\n";
1625 case RenderAttrib::M_less_equal:
1626 text <<
"\t if (result.a > " <<
ref <<
") discard;\n";
1628 case RenderAttrib::M_greater:
1629 text <<
"\t if (result.a <= " <<
ref <<
") discard;\n";
1631 case RenderAttrib::M_not_equal:
1632 text <<
"\t if (result.a == " <<
ref <<
") discard;\n";
1634 case RenderAttrib::M_greater_equal:
1635 text <<
"\t if (result.a < " <<
ref <<
") discard;\n";
1637 case RenderAttrib::M_none:
1638 case RenderAttrib::M_always:
1643 if (key._outputs & AuxBitplaneAttrib::ABO_glow) {
1644 if (key._texture_flags & ShaderKey::TF_map_glow) {
1645 text <<
"\t result.a = tex" << map_index_glow <<
".a;\n";
1647 text <<
"\t result.a = 0.5;\n";
1650 if (key._outputs & AuxBitplaneAttrib::ABO_aux_glow) {
1651 if (key._texture_flags & ShaderKey::TF_map_glow) {
1652 text <<
"\t o_aux.a = tex" << map_index_glow <<
".a;\n";
1654 text <<
"\t o_aux.a = 0.5;\n";
1658 if (have_specular) {
1659 if (key._material_flags & Material::F_specular) {
1660 text <<
"\t tot_specular *= attr_material[3];\n";
1662 if (key._texture_flags & ShaderKey::TF_map_gloss) {
1663 text <<
"\t tot_specular *= tex" << map_index_gloss <<
".a;\n";
1665 text <<
"\t result.rgb = result.rgb + tot_specular.rgb;\n";
1667 if (key._light_ramp !=
nullptr) {
1668 switch (key._light_ramp->get_mode()) {
1669 case LightRampAttrib::LRT_hdr0:
1670 text <<
"\t result.rgb = (result*result*result + result*result + result) / (result*result*result + result*result + result + 1);\n";
1672 case LightRampAttrib::LRT_hdr1:
1673 text <<
"\t result.rgb = (result*result + result) / (result*result + result + 1);\n";
1675 case LightRampAttrib::LRT_hdr2:
1676 text <<
"\t result.rgb = result / (result + 1);\n";
1683 if (key._fog_mode != 0) {
1684 Fog::Mode fog_mode = (Fog::Mode)(key._fog_mode - 1);
1687 text <<
"\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate((attr_fog.z - l_hpos.z) * attr_fog.w));\n";
1689 case Fog::M_exponential:
1690 text <<
"\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate(exp2(attr_fog.x * l_hpos.z * -1.442695f)));\n";
1692 case Fog::M_exponential_squared:
1693 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";
1700 text <<
"\t o_color = result * 1.000001;\n";
1701 if (key._alpha_test_mode != RenderAttrib::M_none) {
1702 text <<
"\t // Shader subsumes normal alpha test.\n";
1704 if (key._disable_alpha_write) {
1705 text <<
"\t // Shader disables alpha write.\n";
1709 if (pgraphnodes_cat.is_spam()) {
1710 pgraphnodes_cat.spam() <<
"Generated shader:\n"
1711 << text.str() <<
"\n";
1715 PT(
Shader) shader = Shader::make(text.str(), Shader::SL_Cg);
1716 nassertr(shader !=
nullptr,
nullptr);
1719 if (key._alpha_test_mode != RenderAttrib::M_none) {
1720 shattr = DCAST(
ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_subsume_alpha_test,
true);
1722 if (key._disable_alpha_write) {
1723 shattr = DCAST(
ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_disable_alpha_write,
true);
1726 reset_register_allocator();
1729 _generated_shaders[key] = attr;
1736 string ShaderGenerator::
1737 combine_mode_as_string(
const ShaderKey::TextureInfo &info, TextureStage::CombineMode c_mode,
bool alpha,
short texindex) {
1738 std::ostringstream text;
1740 case TextureStage::CM_modulate:
1741 text << combine_source_as_string(info, 0, alpha, texindex);
1743 text << combine_source_as_string(info, 1, alpha, texindex);
1745 case TextureStage::CM_add:
1746 text << combine_source_as_string(info, 0, alpha, texindex);
1748 text << combine_source_as_string(info, 1, alpha, texindex);
1750 case TextureStage::CM_add_signed:
1751 text << combine_source_as_string(info, 0, alpha, texindex);
1753 text << combine_source_as_string(info, 1, alpha, texindex);
1757 text <<
" - float3(0.5, 0.5, 0.5)";
1760 case TextureStage::CM_interpolate:
1762 text << combine_source_as_string(info, 1, alpha, texindex);
1764 text << combine_source_as_string(info, 0, alpha, texindex);
1766 text << combine_source_as_string(info, 2, alpha, texindex);
1769 case TextureStage::CM_subtract:
1770 text << combine_source_as_string(info, 0, alpha, texindex);
1772 text << combine_source_as_string(info, 1, alpha, texindex);
1774 case TextureStage::CM_dot3_rgb:
1775 case TextureStage::CM_dot3_rgba:
1777 text << combine_source_as_string(info, 0, alpha, texindex);
1778 text <<
" - float3(0.5), ";
1779 text << combine_source_as_string(info, 1, alpha, texindex);
1780 text <<
" - float3(0.5))";
1782 case TextureStage::CM_replace:
1784 text << combine_source_as_string(info, 0, alpha, texindex);
1793 string ShaderGenerator::
1794 combine_source_as_string(
const ShaderKey::TextureInfo &info,
short num,
bool alpha,
short texindex) {
1795 TextureStage::CombineSource c_src;
1796 TextureStage::CombineOperand c_op;
1798 c_src = UNPACK_COMBINE_SRC(info._combine_rgb, num);
1799 c_op = UNPACK_COMBINE_OP(info._combine_rgb, num);
1801 c_src = UNPACK_COMBINE_SRC(info._combine_alpha, num);
1802 c_op = UNPACK_COMBINE_OP(info._combine_alpha, num);
1804 std::ostringstream csource;
1805 if (c_op == TextureStage::CO_one_minus_src_color ||
1806 c_op == TextureStage::CO_one_minus_src_alpha) {
1807 csource <<
"saturate(1.0f - ";
1810 case TextureStage::CS_undefined:
1811 case TextureStage::CS_texture:
1812 csource <<
"tex" << texindex;
1814 case TextureStage::CS_constant:
1815 csource <<
"texcolor_" << texindex;
1817 case TextureStage::CS_primary_color:
1818 csource <<
"primary_color";
1820 case TextureStage::CS_previous:
1821 csource <<
"result";
1823 case TextureStage::CS_constant_color_scale:
1824 csource <<
"attr_colorscale";
1826 case TextureStage::CS_last_saved_result:
1827 csource <<
"last_saved_result";
1830 if (c_op == TextureStage::CO_one_minus_src_color ||
1831 c_op == TextureStage::CO_one_minus_src_alpha) {
1834 if (c_op == TextureStage::CO_src_color || c_op == TextureStage::CO_one_minus_src_color) {
1840 return "float3(" + csource.str() +
")";
1843 return csource.str();
1849 const char *ShaderGenerator::
1850 texture_type_as_string(Texture::TextureType ttype) {
1852 case Texture::TT_1d_texture:
1855 case Texture::TT_2d_texture:
1858 case Texture::TT_3d_texture:
1861 case Texture::TT_cube_map:
1864 case Texture::TT_2d_texture_array:
1868 pgraphnodes_cat.error() <<
"Unsupported texture type!\n";
1876 ShaderGenerator::ShaderKey::
1882 _have_separate_ambient(false),
1885 _calc_primary_alpha(false),
1886 _disable_alpha_write(false),
1888 _alpha_test_ref(0.0),
1889 _num_clip_planes(0),
1890 _light_ramp(nullptr) {
1897 bool ShaderGenerator::ShaderKey::
1898 operator < (
const ShaderKey &other)
const {
1899 if (_anim_spec != other._anim_spec) {
1900 return _anim_spec < other._anim_spec;
1902 if (_color_type != other._color_type) {
1903 return _color_type < other._color_type;
1905 if (_material_flags != other._material_flags) {
1906 return _material_flags < other._material_flags;
1908 if (_texture_flags != other._texture_flags) {
1909 return _texture_flags < other._texture_flags;
1911 if (_textures.size() != other._textures.size()) {
1912 return _textures.size() < other._textures.size();
1914 for (
size_t i = 0; i < _textures.size(); ++i) {
1915 const ShaderKey::TextureInfo &tex = _textures[i];
1916 const ShaderKey::TextureInfo &other_tex = other._textures[i];
1917 if (tex._texcoord_name != other_tex._texcoord_name) {
1918 return tex._texcoord_name < other_tex._texcoord_name;
1920 if (tex._type != other_tex._type) {
1921 return tex._type < other_tex._type;
1923 if (tex._mode != other_tex._mode) {
1924 return tex._mode < other_tex._mode;
1926 if (tex._gen_mode != other_tex._gen_mode) {
1927 return tex._gen_mode < other_tex._gen_mode;
1929 if (tex._flags != other_tex._flags) {
1930 return tex._flags < other_tex._flags;
1932 if (tex._combine_rgb != other_tex._combine_rgb) {
1933 return tex._combine_rgb < other_tex._combine_rgb;
1935 if (tex._combine_alpha != other_tex._combine_alpha) {
1936 return tex._combine_alpha < other_tex._combine_alpha;
1939 if (_lights.size() != other._lights.size()) {
1940 return _lights.size() < other._lights.size();
1942 for (
size_t i = 0; i < _lights.size(); ++i) {
1943 const ShaderKey::LightInfo &light = _lights[i];
1944 const ShaderKey::LightInfo &other_light = other._lights[i];
1945 if (light._type != other_light._type) {
1946 return light._type < other_light._type;
1948 if (light._flags != other_light._flags) {
1949 return light._flags < other_light._flags;
1952 if (_lighting != other._lighting) {
1953 return _lighting < other._lighting;
1955 if (_have_separate_ambient != other._have_separate_ambient) {
1956 return _have_separate_ambient < other._have_separate_ambient;
1958 if (_fog_mode != other._fog_mode) {
1959 return _fog_mode < other._fog_mode;
1961 if (_outputs != other._outputs) {
1962 return _outputs < other._outputs;
1964 if (_calc_primary_alpha != other._calc_primary_alpha) {
1965 return _calc_primary_alpha < other._calc_primary_alpha;
1967 if (_disable_alpha_write != other._disable_alpha_write) {
1968 return _disable_alpha_write < other._disable_alpha_write;
1970 if (_alpha_test_mode != other._alpha_test_mode) {
1971 return _alpha_test_mode < other._alpha_test_mode;
1973 if (_alpha_test_ref != other._alpha_test_ref) {
1974 return _alpha_test_ref < other._alpha_test_ref;
1976 if (_num_clip_planes != other._num_clip_planes) {
1977 return _num_clip_planes < other._num_clip_planes;
1979 return _light_ramp < other._light_ramp;
1985 bool ShaderGenerator::ShaderKey::
1986 operator == (
const ShaderKey &other)
const {
1987 if (_anim_spec != other._anim_spec) {
1990 if (_color_type != other._color_type) {
1993 if (_material_flags != other._material_flags) {
1996 if (_texture_flags != other._texture_flags) {
1999 if (_textures.size() != other._textures.size()) {
2002 for (
size_t i = 0; i < _textures.size(); ++i) {
2003 const ShaderKey::TextureInfo &tex = _textures[i];
2004 const ShaderKey::TextureInfo &other_tex = other._textures[i];
2005 if (tex._texcoord_name != other_tex._texcoord_name ||
2006 tex._type != other_tex._type ||
2007 tex._mode != other_tex._mode ||
2008 tex._gen_mode != other_tex._gen_mode ||
2009 tex._flags != other_tex._flags ||
2010 tex._combine_rgb != other_tex._combine_rgb ||
2011 tex._combine_alpha != other_tex._combine_alpha) {
2015 if (_lights.size() != other._lights.size()) {
2018 for (
size_t i = 0; i < _lights.size(); ++i) {
2019 const ShaderKey::LightInfo &light = _lights[i];
2020 const ShaderKey::LightInfo &other_light = other._lights[i];
2021 if (light._type != other_light._type ||
2022 light._flags != other_light._flags) {
2026 return _lighting == other._lighting
2027 && _have_separate_ambient == other._have_separate_ambient
2028 && _fog_mode == other._fog_mode
2029 && _outputs == other._outputs
2030 && _calc_primary_alpha == other._calc_primary_alpha
2031 && _disable_alpha_write == other._disable_alpha_write
2032 && _alpha_test_mode == other._alpha_test_mode
2033 && _alpha_test_ref == other._alpha_test_ref
2034 && _num_clip_planes == other._num_clip_planes
2035 && _light_ramp == other._light_ramp;
2046 ~ShaderGenerator() {
2049 void ShaderGenerator::
2050 rehash_generated_shaders() {
2053 void ShaderGenerator::
2054 clear_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.
get_color_type
Returns the type of color specified by this ColorAttrib.
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...
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.