Panda3D
shaderGenerator.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file shaderGenerator.cxx
10 * @author jyelon
11 * @date 2007-12-15
12 * @author weifengh, PandaSE
13 * @date 2010-04-15
14 * @author agartner, PandaSE
15 * @date 2010-04-16
16 * TextureStage::M_modulate (before this, separate textures formatted as
17 * alpha wiped color off resulting rgb)
18 */
19
20#include "shaderGenerator.h"
21
22#include "renderState.h"
23#include "shaderAttrib.h"
24#include "auxBitplaneAttrib.h"
25#include "alphaTestAttrib.h"
26#include "colorBlendAttrib.h"
27#include "transparencyAttrib.h"
28#include "textureAttrib.h"
29#include "colorAttrib.h"
30#include "lightAttrib.h"
31#include "materialAttrib.h"
32#include "lightRampAttrib.h"
33#include "texMatrixAttrib.h"
34#include "texGenAttrib.h"
35#include "colorScaleAttrib.h"
36#include "clipPlaneAttrib.h"
37#include "fogAttrib.h"
38#include "texture.h"
39#include "ambientLight.h"
40#include "directionalLight.h"
41#include "rescaleNormalAttrib.h"
42#include "pointLight.h"
43#include "sphereLight.h"
44#include "spotlight.h"
45#include "lightLensNode.h"
46#include "lvector4.h"
47#include "config_pgraphnodes.h"
48#include "pStatTimer.h"
49
50using std::string;
51
52TypeHandle ShaderGenerator::_type_handle;
53
54#ifdef HAVE_CG
55
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)
58
59static inline uint16_t
60pack_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;
66
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);
70}
71
72static PStatCollector lookup_collector("*:Munge:ShaderGen:Lookup");
73static PStatCollector synthesize_collector("*:Munge:ShaderGen:Synthesize");
74
75/**
76 * Create a ShaderGenerator. This has no state, except possibly to cache
77 * certain results. The parameter that must be passed is the GSG to which the
78 * shader generator belongs.
79 */
80ShaderGenerator::
81ShaderGenerator(const GraphicsStateGuardianBase *gsg) {
82 // The ATTR# input semantics seem to map to generic vertex attributes in
83 // both arbvp1 and glslv, which behave more consistently. However, they
84 // don't exist in Direct3D 9. Use this silly little check for now.
85#ifdef _WIN32
86 _use_generic_attr = !gsg->get_supports_hlsl();
87#else
88 _use_generic_attr = true;
89#endif
90
91 // Do we want to use the ARB_shadow extension? This also allows us to use
92 // hardware shadows PCF.
93 _use_shadow_filter = gsg->get_supports_shadow_filter();
94}
95
96/**
97 * Destroy a ShaderGenerator.
98 */
99ShaderGenerator::
100~ShaderGenerator() {
101}
102
103/**
104 * Clears the register allocator. Initially, the pool of available registers
105 * is empty. You have to add some if you want there to be any.
106 */
107void ShaderGenerator::
108reset_register_allocator() {
109 _vtregs_used = 0;
110 _vcregs_used = 0;
111 _ftregs_used = 0;
112 _fcregs_used = 0;
113}
114
115/**
116 * Allocate a vreg.
117 */
118const char *ShaderGenerator::
119alloc_vreg() {
120 if (_use_generic_attr) {
121 // OpenGL case.
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";
131 }
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";
139 }
140 } else {
141 // DirectX 9 case.
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";
151 }
152 switch (_vcregs_used) {
153 case 0: _vcregs_used += 1; return "COLOR0";
154 case 1: _vcregs_used += 1; return "COLOR1";
155 }
156 }
157 // These don't exist in arbvp1, though they're reportedly supported by other
158 // profiles.
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";
168 }
169 return "UNKNOWN";
170}
171
172/**
173 * Allocate a freg.
174 */
175const char *ShaderGenerator::
176alloc_freg() {
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";
186 }
187 // NB. We really shouldn't use the COLOR fregs, since the clamping can have
188 // unexpected side-effects.
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";
198 }
199 return "UNKNOWN";
200}
201
202/**
203 * Analyzes the RenderState prior to shader generation. The results of the
204 * analysis are stored in instance variables of the Shader Generator.
205 */
206void ShaderGenerator::
207analyze_renderstate(ShaderKey &key, const RenderState *rs) {
208 const ShaderAttrib *shader_attrib;
209 rs->get_attrib_def(shader_attrib);
210 nassertv(shader_attrib->auto_shader());
211
212 // verify_enforce_attrib_lock();
213 const AuxBitplaneAttrib *aux_bitplane;
214 rs->get_attrib_def(aux_bitplane);
215 key._outputs = aux_bitplane->get_outputs();
216
217 // Decide whether or not we need alpha testing or alpha blending.
218 bool have_alpha_test = false;
219 bool have_alpha_blend = false;
220 const AlphaTestAttrib *alpha_test;
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;
225 }
226 const ColorBlendAttrib *color_blend;
227 rs->get_attrib_def(color_blend);
228 if (color_blend->get_mode() != ColorBlendAttrib::M_none) {
229 have_alpha_blend = true;
230 }
231 const TransparencyAttrib *transparency;
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;
237 }
238
239 // Decide what to send to the framebuffer alpha, if anything.
240 if (key._outputs & AuxBitplaneAttrib::ABO_glow) {
241 if (have_alpha_blend) {
242 key._outputs &= ~AuxBitplaneAttrib::ABO_glow;
243 key._disable_alpha_write = true;
244 } else if (have_alpha_test) {
245 // Subsume the alpha test in our shader.
246 key._alpha_test_mode = alpha_test->get_mode();
247 key._alpha_test_ref = alpha_test->get_reference_alpha();
248 }
249 }
250
251 if (have_alpha_blend || have_alpha_test) {
252 key._calc_primary_alpha = true;
253 }
254
255 // Determine whether or not vertex colors or flat colors are present.
256 const ColorAttrib *color;
257 rs->get_attrib_def(color);
258 key._color_type = color->get_color_type();
259
260 // Store the material flags (not the material values itself).
261 const MaterialAttrib *material;
262 rs->get_attrib_def(material);
263 Material *mat = material->get_material();
264 if (mat != nullptr) {
265 // The next time the Material flags change, the Material should cause the
266 // states to be rehashed.
267 mat->mark_used_by_auto_shader();
268 key._material_flags = mat->get_flags();
269
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;
273 }
274 }
275
276 // Break out the lights by type.
277 const LightAttrib *la;
278 rs->get_attrib_def(la);
279 bool have_ambient = false;
280
281 for (size_t i = 0; i < la->get_num_on_lights(); ++i) {
282 NodePath np = la->get_on_light(i);
283 nassertv(!np.is_empty());
284 PandaNode *node = np.node();
285 nassertv(node != nullptr);
286
287 if (node->is_ambient_light()) {
288 have_ambient = true;
289 key._lighting = true;
290 } else {
291 ShaderKey::LightInfo info;
292 info._type = node->get_type();
293 info._flags = 0;
294
295 if (node->is_of_type(LightLensNode::get_class_type())) {
296 const LightLensNode *llnode = (const LightLensNode *)node;
297 if (shader_attrib->auto_shadow_on()) {
298 if (llnode->is_shadow_caster()) {
299 info._flags |= ShaderKey::LF_has_shadows;
300 }
301
302 // Make sure that the next time the shadows are toggled on this
303 // light, it triggers a state rehash.
304 llnode->mark_used_by_auto_shader();
305 }
306 if (llnode->has_specular_color()) {
307 info._flags |= ShaderKey::LF_has_specular_color;
308 }
309 }
310
311 key._lights.push_back(info);
312 key._lighting = true;
313 }
314 }
315
316 // See if there is a normal map, height map, gloss map, or glow map. Also
317 // check if anything has TexGen.
318
319 const TextureAttrib *texture;
320 rs->get_attrib_def(texture);
321 const TexGenAttrib *tex_gen;
322 rs->get_attrib_def(tex_gen);
323 const TexMatrixAttrib *tex_matrix;
324 rs->get_attrib_def(tex_matrix);
325
326 size_t num_textures = texture->get_num_on_stages();
327 for (size_t i = 0; i < num_textures; ++i) {
328 TextureStage *stage = texture->get_on_stage(i);
329 Texture *tex = texture->get_on_texture(stage);
330 nassertd(tex != nullptr) continue;
331
332 // Mark this TextureStage as having been used by the shader generator, so
333 // that the next time its properties change, it will cause the state to be
334 // rehashed to ensure that the shader is regenerated if needed.
335 stage->mark_used_by_auto_shader();
336
337 ShaderKey::TextureInfo info;
338 info._type = tex->get_texture_type();
339 info._mode = stage->get_mode();
340 info._flags = 0;
341 info._combine_rgb = 0u;
342 info._combine_alpha = 0u;
343
344 // While we look at the mode, determine whether we need to change the mode
345 // in order to reflect disabled features.
346 switch (info._mode) {
347 case TextureStage::M_modulate:
348 {
349 Texture::Format format = tex->get_format();
350 if (format != Texture::F_alpha) {
351 info._flags |= ShaderKey::TF_has_rgb;
352 }
353 if (Texture::has_alpha(format)) {
354 info._flags |= ShaderKey::TF_has_alpha;
355 }
356 }
357 break;
358
359 case TextureStage::M_modulate_glow:
360 if (shader_attrib->auto_glow_on()) {
361 info._flags = ShaderKey::TF_map_glow;
362 } else {
363 info._mode = TextureStage::M_modulate;
364 info._flags = ShaderKey::TF_has_rgb;
365 }
366 break;
367
368 case TextureStage::M_modulate_gloss:
369 if (shader_attrib->auto_gloss_on()) {
370 info._flags = ShaderKey::TF_map_gloss;
371 } else {
372 info._mode = TextureStage::M_modulate;
373 info._flags = ShaderKey::TF_has_rgb;
374 }
375 break;
376
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;
384 } else {
385 info._flags = ShaderKey::TF_map_normal | ShaderKey::TF_map_height;
386 }
387 break;
388
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;
394 } else {
395 info._flags = ShaderKey::TF_map_normal | ShaderKey::TF_map_gloss;
396 }
397 break;
398
399 case TextureStage::M_combine:
400 // If we have this rare, special mode, we encode all these extra
401 // parameters as flags to prevent bloating the shader key.
402 info._flags |= (uint32_t)stage->get_combine_rgb_mode() << ShaderKey::TF_COMBINE_RGB_MODE_SHIFT;
403 info._flags |= (uint32_t)stage->get_combine_alpha_mode() << ShaderKey::TF_COMBINE_ALPHA_MODE_SHIFT;
404 if (stage->get_rgb_scale() == 2) {
405 info._flags |= ShaderKey::TF_rgb_scale_2;
406 }
407 if (stage->get_rgb_scale() == 4) {
408 info._flags |= ShaderKey::TF_rgb_scale_4;
409 }
410 if (stage->get_alpha_scale() == 2) {
411 info._flags |= ShaderKey::TF_alpha_scale_2;
412 }
413 if (stage->get_alpha_scale() == 4) {
414 info._flags |= ShaderKey::TF_alpha_scale_4;
415 }
416
417 info._combine_rgb = pack_combine(
421 info._combine_alpha = pack_combine(
425
426 if (stage->uses_primary_color()) {
427 info._flags |= ShaderKey::TF_uses_primary_color;
428 }
429 if (stage->uses_last_saved_result()) {
430 info._flags |= ShaderKey::TF_uses_last_saved_result;
431 }
432 break;
433
434 default:
435 break;
436 }
437
438 // In fact, perhaps this stage should be disabled altogether?
439 bool skip = false;
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)) {
444 skip = true;
445 } else {
446 info._flags = ShaderKey::TF_map_normal;
447 }
448 break;
449 case TextureStage::M_glow:
450 if (shader_attrib->auto_glow_on()) {
451 info._flags = ShaderKey::TF_map_glow;
452 } else {
453 skip = true;
454 }
455 break;
456 case TextureStage::M_gloss:
457 if (!key._lights.empty() && shader_attrib->auto_gloss_on()) {
458 info._flags = ShaderKey::TF_map_gloss;
459 } else {
460 skip = true;
461 }
462 break;
463 case TextureStage::M_height:
464 if (parallax_mapping_samples > 0) {
465 info._flags = ShaderKey::TF_map_height;
466 } else {
467 skip = true;
468 }
469 break;
470 case TextureStage::M_emission:
471 info._flags = ShaderKey::TF_map_emission;
472 break;
473 default:
474 break;
475 }
476 // We can't just drop a disabled slot from the list, since then the
477 // indices for the texture stages will no longer match up. So we keep it,
478 // but set it to a noop state to indicate that it should be skipped.
479 if (skip) {
480 info._type = Texture::TT_1d_texture;
481 info._mode = TextureStage::M_modulate;
482 info._flags = 0;
483 key._textures.push_back(info);
484 continue;
485 }
486
487 // Check if this state has a texture matrix to transform the texture
488 // coordinates.
489 if (tex_matrix->has_stage(stage)) {
490 CPT(TransformState) transform = tex_matrix->get_transform(stage);
491 if (!transform->is_identity()) {
492 // Optimize for common case: if we only have a scale component, we
493 // can get away with fewer shader inputs and operations.
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;
498 } else {
499 info._flags |= ShaderKey::TF_has_texmat;
500 }
501 }
502 }
503
504 if (tex_gen->has_stage(stage)) {
505 info._texcoord_name = nullptr;
506 info._gen_mode = tex_gen->get_mode(stage);
507 } else {
508 info._texcoord_name = stage->get_texcoord_name();
509 info._gen_mode = TexGenAttrib::M_off;
510 }
511
512 // Does this stage require saving its result?
513 if (stage->get_saved_result()) {
514 info._flags |= ShaderKey::TF_saved_result;
515 }
516
517 // Does this stage need a texcolor_# input?
518 if (stage->uses_color()) {
519 info._flags |= ShaderKey::TF_uses_color;
520 }
521
522 key._textures.push_back(info);
523 key._texture_flags |= info._flags;
524 }
525
526 // Does nothing use the saved result? If so, don't bother saving it.
527 if ((key._texture_flags & ShaderKey::TF_uses_last_saved_result) == 0 &&
528 (key._texture_flags & ShaderKey::TF_saved_result) != 0) {
529
531 for (it = key._textures.begin(); it != key._textures.end(); ++it) {
532 (*it)._flags &= ~ShaderKey::TF_saved_result;
533 }
534 key._texture_flags &= ~ShaderKey::TF_saved_result;
535 }
536
537 // Decide whether to separate ambient and diffuse calculations.
538 if (have_ambient) {
539 if (key._material_flags & Material::F_ambient) {
540 key._have_separate_ambient = true;
541 } else {
542 if (key._material_flags & Material::F_diffuse) {
543 key._have_separate_ambient = true;
544 } else {
545 key._have_separate_ambient = false;
546 }
547 }
548 }
549
550 if (shader_attrib->auto_ramp_on()) {
551 const LightRampAttrib *light_ramp;
552 if (rs->get_attrib(light_ramp)) {
553 key._light_ramp = light_ramp;
554 if (key._lighting) {
555 key._have_separate_ambient = true;
556 }
557 }
558 }
559
560 // Check for clip planes.
561 const ClipPlaneAttrib *clip_plane;
562 rs->get_attrib_def(clip_plane);
563 key._num_clip_planes = clip_plane->get_num_on_planes();
564
565 // Check for fog.
566 const FogAttrib *fog;
567 if (rs->get_attrib(fog) && !fog->is_off()) {
568 key._fog_mode = (int)fog->get_fog()->get_mode() + 1;
569 }
570}
571
572/**
573 * Rehashes all the states with generated shaders, removing the ones that are
574 * no longer fresh.
575 *
576 * Call this if certain state has changed in such a way as to require a rerun
577 * of the shader generator. This should be rare because in most cases, the
578 * shader generator will automatically regenerate shaders as necessary.
579 *
580 * @since 1.10.0
581 */
582void ShaderGenerator::
583rehash_generated_shaders() {
584 LightReMutexHolder holder(*RenderState::_states_lock);
585
586 // With uniquify-states turned on, we can actually go through all the states
587 // and check whether their generated shader is still OK.
588 size_t size = RenderState::_states->get_num_entries();
589 for (size_t si = 0; si < size; ++si) {
590 const RenderState *state = RenderState::_states->get_key(si);
591
592 if (state->_generated_shader != nullptr) {
593 ShaderKey key;
594 analyze_renderstate(key, state);
595
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();
602 }
603 } else {
604 // We have not yet generated a shader for this modified state.
605 state->_generated_shader.clear();
606 state->_munged_states.clear();
607 }
608 }
609 }
610
611 // If we don't have uniquify-states, however, the above list won't contain
612 // all the state. We can change a global seq value to require Panda to
613 // rehash the states the next time it tries to render an object with it.
614 if (!uniquify_states) {
615 GraphicsStateGuardianBase::mark_rehash_generated_shaders();
616 }
617}
618
619/**
620 * Removes all previously generated shaders, requiring all shaders to be
621 * regenerated. Does not clear cache of compiled shaders.
622 *
623 * @since 1.10.0
624 */
625void ShaderGenerator::
626clear_generated_shaders() {
627 LightReMutexHolder holder(*RenderState::_states_lock);
628
629 size_t size = RenderState::_states->get_num_entries();
630 for (size_t si = 0; si < size; ++si) {
631 const RenderState *state = RenderState::_states->get_key(si);
632 state->_generated_shader.clear();
633 }
634
635 _generated_shaders.clear();
636
637 // If we don't have uniquify-states, we can't clear all the ShaderAttribs
638 // that are cached on the states, but we can simulate the effect of that.
639 if (!uniquify_states) {
640 GraphicsStateGuardianBase::mark_rehash_generated_shaders();
641 }
642}
643
644/**
645 * This is the routine that implements the next-gen fixed function pipeline by
646 * synthesizing a shader. It also takes care of setting up any buffers needed
647 * to produce the requested effects.
648 *
649 * Currently supports:
650 * - flat colors
651 * - vertex colors
652 * - lighting
653 * - normal maps, even multiple
654 * - gloss maps, but not multiple
655 * - glow maps, but not multiple
656 * - materials, but not updates to materials
657 * - 2D textures
658 * - all texture stage modes, including combine modes
659 * - color scale attrib
660 * - light ramps (for cartoon shading)
661 * - shadow mapping
662 * - most texgen modes
663 * - texmatrix
664 * - 1D/2D/3D textures, cube textures, 2D tex arrays
665 * - linear/exp/exp2 fog
666 * - animation
667 *
668 * Potential optimizations
669 * - omit attenuation calculations if attenuation off
670 *
671 */
672CPT(ShaderAttrib) ShaderGenerator::
673synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
674 ShaderKey key;
675
676 // First look up the state key in the table of already generated shaders.
677 {
678 PStatTimer timer(lookup_collector);
679 key._anim_spec = anim;
680 analyze_renderstate(key, rs);
681
682 GeneratedShaders::const_iterator si;
683 si = _generated_shaders.find(key);
684 if (si != _generated_shaders.end()) {
685 // We've already generated a shader for this state.
686 return si->second;
687 }
688 }
689
690 PStatTimer timer(synthesize_collector);
691
692 reset_register_allocator();
693
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);
698 }
699
700 // These variables will hold the results of register allocation.
701
702 const char *tangent_freg = nullptr;
703 const char *binormal_freg = nullptr;
704 string tangent_input;
705 string binormal_input;
707 pvector<const char *> lightcoord_fregs;
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;
713
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;
719
720 if (_use_generic_attr) {
721 position_vreg = "ATTR0";
722 transform_weight_vreg = "ATTR1";
723 normal_vreg = "ATTR2";
724 transform_index_vreg = "ATTR7";
725 } else {
726 position_vreg = "POSITION";
727 normal_vreg = "NORMAL";
728 }
729
730 if (key._color_type == ColorAttrib::T_vertex) {
731 // Reserve COLOR0
732 color_vreg = _use_generic_attr ? "ATTR3" : "COLOR0";
733 _vcregs_used = 1;
734 _fcregs_used = 1;
735 }
736
737 // Generate the shader's text.
738
739 std::ostringstream text;
740
741 text << "//Cg\n";
742
743 text << "/* Generated shader for render state:\n";
744 rs->write(text, 2);
745 text << "*/\n";
746
747 int map_index_glow = -1;
748 int map_index_gloss = -1;
749 int map_index_emission = -1;
750
751 // Figure out whether we need to calculate any of these variables.
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);
757
758 // If we have binormal/tangent and eye position, we can pack eye normal in
759 // the w channels of the others.
760 bool pack_eye_normal = need_eye_normal && need_tangents && need_eye_position;
761
762 bool have_specular = false;
763 if (key._lighting) {
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;
768 }
769 }
770
771 bool need_color = false;
772 if (key._color_type != ColorAttrib::T_off) {
773 if (key._lighting) {
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) {
777 need_color = true;
778 }
779 } else {
780 need_color = true;
781 }
782 }
783
784 text << "void vshader(\n";
785 for (size_t i = 0; i < key._textures.size(); ++i) {
786 const ShaderKey::TextureInfo &tex = key._textures[i];
787
788 switch (tex._gen_mode) {
789 case TexGenAttrib::M_world_position:
790 need_world_position = true;
791 break;
792 case TexGenAttrib::M_world_normal:
793 need_world_normal = true;
794 break;
795 case TexGenAttrib::M_eye_position:
796 need_eye_position = true;
797 break;
798 case TexGenAttrib::M_eye_normal:
799 need_eye_normal = true;
800 break;
801 default:
802 break;
803 }
804
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;
809
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";
813 }
814 }
815
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();
820
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());
825 }
826
827 tangent_input = tangent_name->join("_");
828 binormal_input = binormal_name->join("_");
829
830 text << "\t in float4 vtx_" << tangent_input << " : " << alloc_vreg() << ",\n";
831 text << "\t in float4 vtx_" << binormal_input << " : " << alloc_vreg() << ",\n";
832 }
833
834 if (tex._flags & ShaderKey::TF_map_glow) {
835 map_index_glow = i;
836 }
837 if (tex._flags & ShaderKey::TF_map_gloss) {
838 map_index_gloss = i;
839 }
840 if (tex._flags & ShaderKey::TF_map_emission) {
841 map_index_emission = i;
842 }
843 }
844 if (need_tangents) {
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";
849 }
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";
853 }
854 if (need_world_position || need_world_normal) {
855 text << "\t uniform float4x4 trans_model_to_world,\n";
856 }
857 if (need_world_position) {
858 world_position_freg = alloc_freg();
859 text << "\t out float4 l_world_position : " << world_position_freg << ",\n";
860 }
861 if (need_world_normal) {
862 world_normal_freg = alloc_freg();
863 text << "\t out float4 l_world_normal : " << world_normal_freg << ",\n";
864 }
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";
871 }
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";
877 }
878 }
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";
881 }
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";
885 }
886 if (key._fog_mode != 0) {
887 hpos_freg = alloc_freg();
888 text << "\t out float4 l_hpos : " << hpos_freg << ",\n";
889 }
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) {
894 // We ran out of TEXCOORD registers. That means we have to do this
895 // calculation in the fragment shader, which is slower.
896 lightcoord_fregs.push_back(nullptr);
897 } else {
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";
901 }
902 } else {
903 lightcoord_fregs.push_back(nullptr);
904 }
905 }
906 if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware &&
907 key._anim_spec.get_num_transforms() > 0) {
908 int num_transforms;
909 if (key._anim_spec.get_indexed_transforms()) {
910 num_transforms = 120;
911 } else {
912 num_transforms = key._anim_spec.get_num_transforms();
913 }
914 if (transform_weight_vreg == nullptr) {
915 transform_weight_vreg = alloc_vreg();
916 }
917 if (transform_index_vreg == nullptr) {
918 transform_index_vreg = alloc_vreg();
919 }
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";
924 }
925 }
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";
929 text << ") {\n";
930
931 if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware &&
932 key._anim_spec.get_num_transforms() > 0) {
933
934 if (!key._anim_spec.get_indexed_transforms()) {
935 text << "\t const uint4 vtx_transform_index = uint4(0, 1, 2, 3);\n";
936 }
937
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";
941 }
942 if (key._anim_spec.get_num_transforms() > 2) {
943 text << "\n\t + tbl_transforms[vtx_transform_index.z] * vtx_transform_weight.z";
944 }
945 if (key._anim_spec.get_num_transforms() > 3) {
946 text << "\n\t + tbl_transforms[vtx_transform_index.w] * vtx_transform_weight.w";
947 }
948 text << ";\n";
949
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";
953 }
954 }
955
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";
959 }
960 if (need_world_position) {
961 text << "\t l_world_position = mul(trans_model_to_world, vtx_position);\n";
962 }
963 if (need_world_normal) {
964 text << "\t l_world_normal = mul(trans_model_to_world, float4(vtx_normal, 0));\n";
965 }
966 if (need_eye_position) {
967 text << "\t l_eye_position = mul(trans_model_to_view, vtx_position);\n";
968 }
970 for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
971 // Pass through all texcoord inputs as-is.
972 string tcname = it->first->join("_");
973 text << "\t l_" << tcname << " = vtx_" << tcname << ";\n";
974 }
975 if (need_color && key._color_type == ColorAttrib::T_vertex) {
976 text << "\t l_color = vtx_color;\n";
977 }
978 if (need_tangents) {
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";
983 }
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";
988 }
989 }
990 }
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";
997 }
998 if (need_eye_normal) {
999 if (pack_eye_normal) {
1000 // We can pack the normal into the w channels of these unused varyings.
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";
1005 } else {
1006 text << "\t l_eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n";
1007 }
1008 }
1009 text << "}\n\n";
1010
1011 // Fragment shader
1012
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";
1018 }
1019 if (need_world_position) {
1020 text << "\t in float4 l_world_position : " << world_position_freg << ",\n";
1021 }
1022 if (need_world_normal) {
1023 text << "\t in float4 l_world_normal : " << world_normal_freg << ",\n";
1024 }
1025 if (need_eye_position) {
1026 text << "\t in float4 l_eye_position : " << eye_position_freg << ",\n";
1027 }
1028 if (need_eye_normal && !pack_eye_normal) {
1029 text << "\t in float3 l_eye_normal : " << eye_normal_freg << ",\n";
1030 }
1031 for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
1032 text << "\t in float4 l_" << it->first->join("_") << " : " << it->second << ",\n";
1033 }
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) {
1037 // Skip this stage.
1038 continue;
1039 }
1040
1041 text << "\t uniform sampler" << texture_type_as_string(tex._type) << " tex_" << i << ",\n";
1042
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";
1047 }
1048
1049 if (tex._flags & ShaderKey::TF_uses_color) {
1050 text << "\t uniform float4 texcolor_" << i << ",\n";
1051 }
1052 }
1053 if (need_tangents) {
1054 text << "\t in float4 l_tangent : " << tangent_freg << ",\n";
1055 text << "\t in float4 l_binormal : " << binormal_freg << ",\n";
1056 }
1057 for (size_t i = 0; i < key._lights.size(); ++i) {
1058 text << "\t uniform float4x4 attr_light" << i << ",\n";
1059
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";
1066 } else {
1067 text << "\t uniform sampler2D shadow_" << i << ",\n";
1068 }
1069 if (lightcoord_fregs[i] != nullptr) {
1070 text << "\t in float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n";
1071 } else {
1072 text << "\t uniform float4x4 mat_shadow_" << i << ",\n";
1073 }
1074 }
1075 if (light._flags & ShaderKey::LF_has_specular_color) {
1076 text << "\t uniform float4 attr_lspec" << i << ",\n";
1077 }
1078 }
1079
1080 // Does the shader need material properties as input?
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";
1083 }
1084 if (key._texture_flags & ShaderKey::TF_map_height) {
1085 text << "\t float3 l_eyevec,\n";
1086 }
1087 if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
1088 text << "\t out float4 o_aux : COLOR1,\n";
1089 }
1090 text << "\t out float4 o_color : COLOR0,\n";
1091
1092 if (need_color) {
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";
1097 }
1098 }
1099
1100 for (int i = 0; i < key._num_clip_planes; ++i) {
1101 text << "\t uniform float4 clipplane_" << i << ",\n";
1102 }
1103
1104 if (key._lighting) {
1105 text << "\t uniform float4 attr_ambient,\n";
1106 }
1107 text << "\t uniform float4 attr_colorscale\n";
1108 text << ") {\n";
1109
1110 // Clipping first!
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";
1115 text << "\t }\n";
1116 }
1117
1118 // Reconstruct a packed normal vector.
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";
1121 }
1122
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";
1126 }
1127 // Now generate any texture coordinates according to TexGenAttrib. If it
1128 // has a TexMatrixAttrib, also transform them.
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) {
1132 // Skip this stage.
1133 continue;
1134 }
1135 switch (tex._gen_mode) {
1136 case TexGenAttrib::M_off:
1137 // Cg seems to be able to optimize this temporary away when appropriate.
1138 text << "\t float4 texcoord" << i << " = l_" << tex._texcoord_name->join("_") << ";\n";
1139 break;
1140 case TexGenAttrib::M_world_position:
1141 text << "\t float4 texcoord" << i << " = l_world_position;\n";
1142 break;
1143 case TexGenAttrib::M_world_normal:
1144 text << "\t float4 texcoord" << i << " = l_world_normal;\n";
1145 break;
1146 case TexGenAttrib::M_eye_position:
1147 text << "\t float4 texcoord" << i << " = float4(l_eye_position.xyz, 1.0f);\n";
1148 break;
1149 case TexGenAttrib::M_eye_normal:
1150 text << "\t float4 texcoord" << i << " = float4(l_eye_normal, 1.0f);\n";
1151 break;
1152 default:
1153 text << "\t float4 texcoord" << i << " = float4(0, 0, 0, 0);\n";
1154 pgraphnodes_cat.error()
1155 << "Unsupported TexGenAttrib mode: " << tex._gen_mode << "\n";
1156 }
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";
1162 }
1163 }
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) {
1168 continue;
1169 }
1170
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:
1177 text << "xyz";
1178 break;
1179 case Texture::TT_2d_texture:
1180 text << "xy";
1181 break;
1182 case Texture::TT_1d_texture:
1183 text << "x";
1184 break;
1185 default:
1186 break;
1187 }
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) {
1191 text << ".aaa";
1192 } else {
1193 text << ".rgb";
1194 }
1195 text << " * 2.0 - 1.0) * " << parallax_mapping_scale << ";\n";
1196 // Additional samples
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) {
1201 text << ".aaa";
1202 } else {
1203 text << ".rgb";
1204 }
1205 text << " * 2.0 - 1.0)) * " << 0.5 * parallax_mapping_scale << ";\n";
1206 }
1207 }
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) {
1211 // Skip this stage.
1212 continue;
1213 }
1214 if ((tex._flags & ShaderKey::TF_map_height) == 0) {
1215 // Parallax mapping pushes the texture coordinates of the other textures
1216 // away from the camera.
1217 if (key._texture_flags & ShaderKey::TF_map_height) {
1218 text << "\t texcoord" << i << ".xyz -= parallax_offset;\n";
1219 }
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:
1226 text << "xyz";
1227 break;
1228 case Texture::TT_2d_texture:
1229 text << "xy";
1230 break;
1231 case Texture::TT_1d_texture:
1232 text << "x";
1233 break;
1234 default:
1235 break;
1236 }
1237 text << ");\n";
1238 }
1239 }
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";
1243 }
1244 if (need_tangents) {
1245 text << "\t // Translate tangent-space normal in map to view-space.\n";
1246
1247 // Use Reoriented Normal Mapping to blend additional normal maps.
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) {
1252 if (is_first) {
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";
1257 } else {
1258 text << "\t float3 tsnormal = normalize((tex" << i << ".xyz * 2) - 1);\n";
1259 }
1260 is_first = false;
1261 continue;
1262 }
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";
1269 }
1270 text << "\t tsnormal = normalize(tsnormal * dot(tsnormal, tmp" << i << ") - tmp" << i << " * tsnormal.z);\n";
1271 }
1272 }
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";
1277 }
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";
1281 }
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";
1289 }
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";
1295 } else {
1296 text << "\t float shininess = 50; // no shininess specified, using default\n";
1297 }
1298 }
1299 if (key._have_separate_ambient) {
1300 text << "\t tot_ambient += attr_ambient;\n";
1301 } else {
1302 text << "\t tot_diffuse += attr_ambient;\n";
1303 }
1304 }
1305 for (size_t i = 0; i < key._lights.size(); ++i) {
1306 const ShaderKey::LightInfo &light = key._lights[i];
1307
1308 if (light._flags & ShaderKey::LF_has_shadows) {
1309 if (lightcoord_fregs[i] == nullptr) {
1310 // We have to do this one in the fragment shader if we ran out of
1311 // varyings.
1312 text << "\t float4 l_lightcoord" << i << " = mul(mat_shadow_" << i << ", float4(l_eye_position.xyz, 1.0f));\n";
1313 }
1314 }
1315
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";
1321 } else {
1322 text << "\t lspec = lcolor;\n";
1323 }
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";
1329 } else {
1330 text << "\t lshad = tex2Dproj(shadow_" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n";
1331 }
1332 text << "\t lcolor *= lshad;\n";
1333 text << "\t lspec *= lshad;\n";
1334 }
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";
1339 } else {
1340 text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1341 }
1342 text << "\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1343 text << "\t tot_specular += lspec;\n";
1344 }
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";
1350 } else {
1351 text << "\t lspec = lcolor;\n";
1352 }
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";
1360 }
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";
1369 }
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";
1374 } else {
1375 text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1376 }
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";
1380 }
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";
1386 } else {
1387 text << "\t lspec = lcolor;\n";
1388 }
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";
1403 } else {
1404 text << "\t lshad = tex2Dproj(shadow_" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n";
1405 }
1406 text << "\t lcolor *= lshad;\n";
1407 text << "\t lspec *= lshad;\n";
1408 }
1409
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";
1414 } else {
1415 text << "\t lhalf = normalize(lvec - float3(0,1,0));\n";
1416 }
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";
1420 }
1421 }
1422 }
1423 if (key._lighting) {
1424 if (key._light_ramp != nullptr) {
1425 switch (key._light_ramp->get_mode()) {
1426 case LightRampAttrib::LRT_single_threshold:
1427 {
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";
1434 break;
1435 }
1436 case LightRampAttrib::LRT_double_threshold:
1437 {
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";
1448 break;
1449 }
1450 default:
1451 break;
1452 }
1453 }
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";
1459 } else {
1460 text << "\t result = float4(0,0,0,0);\n";
1461 }
1462 if (key._texture_flags & ShaderKey::TF_map_emission) {
1463 text << "\t result.rgb *= tex" << map_index_emission << ".rgb;\n";
1464 }
1465 if (key._texture_flags & ShaderKey::TF_map_glow) {
1466 text << "\t result *= saturate(2 * (tex" << map_index_glow << ".a - 0.5));\n";
1467 }
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";
1475 } else {
1476 text << "\t result += tot_ambient;\n";
1477 }
1478 }
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";
1485 } else {
1486 text << "\t result += tot_diffuse;\n";
1487 }
1488 if (key._light_ramp == nullptr ||
1489 key._light_ramp->get_mode() == LightRampAttrib::LRT_default) {
1490 text << "\t result = saturate(result);\n";
1491 }
1492 text << "\t // End view-space light calculations\n";
1493
1494 // Combine in alpha, which bypasses lighting calculations. Use of lerp
1495 // here is a workaround for a radeon driver bug.
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";
1503 } else {
1504 text << "\t result.a = 1;\n";
1505 }
1506 }
1507 } else {
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";
1512 } else {
1513 text << "\t result = float4(1, 1, 1, 1);\n";
1514 }
1515 }
1516
1517 // Apply the color scale.
1518 text << "\t result *= attr_colorscale;\n";
1519
1520 // Store these if any stages will use it.
1521 if (key._texture_flags & ShaderKey::TF_uses_primary_color) {
1522 text << "\t float4 primary_color = result;\n";
1523 }
1524 if (key._texture_flags & ShaderKey::TF_uses_last_saved_result) {
1525 text << "\t float4 last_saved_result = result;\n";
1526 }
1527
1528 // Now loop through the textures to compose our magic blending formulas.
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;
1532
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";
1542 }
1543 break;
1544 case TextureStage::M_modulate_glow:
1545 case TextureStage::M_modulate_gloss:
1546 // in the case of glow or spec we currently see the specularity evenly
1547 // across the surface even if transparency or masking is present not
1548 // sure if this is desired behavior or not. *MOST* would construct a
1549 // spec map based off of what isisn't seen based on the masktransparency
1550 // this may have to be left alone for now agartner
1551 text << "\t result.rgb *= tex" << i << ";\n";
1552 break;
1553 case TextureStage::M_decal:
1554 text << "\t result.rgb = lerp(result, tex" << i << ", tex" << i << ".a).rgb;\n";
1555 break;
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";
1560 }
1561 break;
1562 case TextureStage::M_replace:
1563 text << "\t result = tex" << i << ";\n";
1564 break;
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";
1569 }
1570 break;
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);
1577 text << ";\n";
1578 } else {
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);
1583 text << ";\n";
1584 }
1585 if (tex._flags & ShaderKey::TF_rgb_scale_2) {
1586 text << "\t result.rgb *= 2;\n";
1587 }
1588 if (tex._flags & ShaderKey::TF_rgb_scale_4) {
1589 text << "\t result.rgb *= 4;\n";
1590 }
1591 if (tex._flags & ShaderKey::TF_alpha_scale_2) {
1592 text << "\t result.a *= 2;\n";
1593 }
1594 if (tex._flags & ShaderKey::TF_alpha_scale_4) {
1595 text << "\t result.a *= 4;\n";
1596 }
1597 break;
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";
1602 }
1603 break;
1604 default:
1605 break;
1606 }
1607 if (tex._flags & ShaderKey::TF_saved_result) {
1608 text << "\t last_saved_result = result;\n";
1609 }
1610 }
1611
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";
1618 break;
1619 case RenderAttrib::M_less:
1620 text << "\t if (result.a >= " << ref << ") discard;\n";
1621 break;
1622 case RenderAttrib::M_equal:
1623 text << "\t if (result.a != " << ref << ") discard;\n";
1624 break;
1625 case RenderAttrib::M_less_equal:
1626 text << "\t if (result.a > " << ref << ") discard;\n";
1627 break;
1628 case RenderAttrib::M_greater:
1629 text << "\t if (result.a <= " << ref << ") discard;\n";
1630 break;
1631 case RenderAttrib::M_not_equal:
1632 text << "\t if (result.a == " << ref << ") discard;\n";
1633 break;
1634 case RenderAttrib::M_greater_equal:
1635 text << "\t if (result.a < " << ref << ") discard;\n";
1636 break;
1637 case RenderAttrib::M_none:
1638 case RenderAttrib::M_always:
1639 break;
1640 }
1641 }
1642
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";
1646 } else {
1647 text << "\t result.a = 0.5;\n";
1648 }
1649 }
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";
1653 } else {
1654 text << "\t o_aux.a = 0.5;\n";
1655 }
1656 }
1657
1658 if (have_specular) {
1659 if (key._material_flags & Material::F_specular) {
1660 text << "\t tot_specular *= attr_material[3];\n";
1661 }
1662 if (key._texture_flags & ShaderKey::TF_map_gloss) {
1663 text << "\t tot_specular *= tex" << map_index_gloss << ".a;\n";
1664 }
1665 text << "\t result.rgb = result.rgb + tot_specular.rgb;\n";
1666 }
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";
1671 break;
1672 case LightRampAttrib::LRT_hdr1:
1673 text << "\t result.rgb = (result*result + result) / (result*result + result + 1);\n";
1674 break;
1675 case LightRampAttrib::LRT_hdr2:
1676 text << "\t result.rgb = result / (result + 1);\n";
1677 break;
1678 default: break;
1679 }
1680 }
1681
1682 // Apply fog.
1683 if (key._fog_mode != 0) {
1684 Fog::Mode fog_mode = (Fog::Mode)(key._fog_mode - 1);
1685 switch (fog_mode) {
1686 case Fog::M_linear:
1687 text << "\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate((attr_fog.z - l_hpos.z) * attr_fog.w));\n";
1688 break;
1689 case Fog::M_exponential: // 1.442695f = 1 / log(2)
1690 text << "\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate(exp2(attr_fog.x * l_hpos.z * -1.442695f)));\n";
1691 break;
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";
1694 break;
1695 }
1696 }
1697
1698 // The multiply is a workaround for a radeon driver bug. It's annoying as
1699 // heck, since it produces an extra instruction.
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";
1703 }
1704 if (key._disable_alpha_write) {
1705 text << "\t // Shader disables alpha write.\n";
1706 }
1707 text << "}\n";
1708
1709 if (pgraphnodes_cat.is_spam()) {
1710 pgraphnodes_cat.spam() << "Generated shader:\n"
1711 << text.str() << "\n";
1712 }
1713
1714 // Insert the shader into the shader attrib.
1715 PT(Shader) shader = Shader::make(text.str(), Shader::SL_Cg);
1716 nassertr(shader != nullptr, nullptr);
1717
1718 CPT(RenderAttrib) shattr = ShaderAttrib::make(shader);
1719 if (key._alpha_test_mode != RenderAttrib::M_none) {
1720 shattr = DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_subsume_alpha_test, true);
1721 }
1722 if (key._disable_alpha_write) {
1723 shattr = DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_disable_alpha_write, true);
1724 }
1725
1726 reset_register_allocator();
1727
1728 CPT(ShaderAttrib) attr = DCAST(ShaderAttrib, shattr);
1729 _generated_shaders[key] = attr;
1730 return attr;
1731}
1732
1733/**
1734 * This 'synthesizes' a combine mode into a string.
1735 */
1736string ShaderGenerator::
1737combine_mode_as_string(const ShaderKey::TextureInfo &info, TextureStage::CombineMode c_mode, bool alpha, short texindex) {
1738 std::ostringstream text;
1739 switch (c_mode) {
1740 case TextureStage::CM_modulate:
1741 text << combine_source_as_string(info, 0, alpha, texindex);
1742 text << " * ";
1743 text << combine_source_as_string(info, 1, alpha, texindex);
1744 break;
1745 case TextureStage::CM_add:
1746 text << combine_source_as_string(info, 0, alpha, texindex);
1747 text << " + ";
1748 text << combine_source_as_string(info, 1, alpha, texindex);
1749 break;
1750 case TextureStage::CM_add_signed:
1751 text << combine_source_as_string(info, 0, alpha, texindex);
1752 text << " + ";
1753 text << combine_source_as_string(info, 1, alpha, texindex);
1754 if (alpha) {
1755 text << " - 0.5";
1756 } else {
1757 text << " - float3(0.5, 0.5, 0.5)";
1758 }
1759 break;
1760 case TextureStage::CM_interpolate:
1761 text << "lerp(";
1762 text << combine_source_as_string(info, 1, alpha, texindex);
1763 text << ", ";
1764 text << combine_source_as_string(info, 0, alpha, texindex);
1765 text << ", ";
1766 text << combine_source_as_string(info, 2, alpha, texindex);
1767 text << ")";
1768 break;
1769 case TextureStage::CM_subtract:
1770 text << combine_source_as_string(info, 0, alpha, texindex);
1771 text << " - ";
1772 text << combine_source_as_string(info, 1, alpha, texindex);
1773 break;
1774 case TextureStage::CM_dot3_rgb:
1775 case TextureStage::CM_dot3_rgba:
1776 text << "4 * dot(";
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))";
1781 break;
1782 case TextureStage::CM_replace:
1783 default: // Not sure if this is correct as default value.
1784 text << combine_source_as_string(info, 0, alpha, texindex);
1785 break;
1786 }
1787 return text.str();
1788}
1789
1790/**
1791 * This 'synthesizes' a combine source into a string.
1792 */
1793string ShaderGenerator::
1794combine_source_as_string(const ShaderKey::TextureInfo &info, short num, bool alpha, short texindex) {
1795 TextureStage::CombineSource c_src;
1796 TextureStage::CombineOperand c_op;
1797 if (!alpha) {
1798 c_src = UNPACK_COMBINE_SRC(info._combine_rgb, num);
1799 c_op = UNPACK_COMBINE_OP(info._combine_rgb, num);
1800 } else {
1801 c_src = UNPACK_COMBINE_SRC(info._combine_alpha, num);
1802 c_op = UNPACK_COMBINE_OP(info._combine_alpha, num);
1803 }
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 - ";
1808 }
1809 switch (c_src) {
1810 case TextureStage::CS_undefined:
1811 case TextureStage::CS_texture:
1812 csource << "tex" << texindex;
1813 break;
1814 case TextureStage::CS_constant:
1815 csource << "texcolor_" << texindex;
1816 break;
1817 case TextureStage::CS_primary_color:
1818 csource << "primary_color";
1819 break;
1820 case TextureStage::CS_previous:
1821 csource << "result";
1822 break;
1823 case TextureStage::CS_constant_color_scale:
1824 csource << "attr_colorscale";
1825 break;
1826 case TextureStage::CS_last_saved_result:
1827 csource << "last_saved_result";
1828 break;
1829 }
1830 if (c_op == TextureStage::CO_one_minus_src_color ||
1831 c_op == TextureStage::CO_one_minus_src_alpha) {
1832 csource << ")";
1833 }
1834 if (c_op == TextureStage::CO_src_color || c_op == TextureStage::CO_one_minus_src_color) {
1835 csource << ".rgb";
1836 } else {
1837 csource << ".a";
1838 if (!alpha) {
1839 // Dunno if it's legal in the FPP at all, but let's just allow it.
1840 return "float3(" + csource.str() + ")";
1841 }
1842 }
1843 return csource.str();
1844}
1845
1846/**
1847 * Returns 1D, 2D, 3D or CUBE, depending on the given texture type.
1848 */
1849const char *ShaderGenerator::
1850texture_type_as_string(Texture::TextureType ttype) {
1851 switch (ttype) {
1852 case Texture::TT_1d_texture:
1853 return "1D";
1854 break;
1855 case Texture::TT_2d_texture:
1856 return "2D";
1857 break;
1858 case Texture::TT_3d_texture:
1859 return "3D";
1860 break;
1861 case Texture::TT_cube_map:
1862 return "CUBE";
1863 break;
1864 case Texture::TT_2d_texture_array:
1865 return "2DARRAY";
1866 break;
1867 default:
1868 pgraphnodes_cat.error() << "Unsupported texture type!\n";
1869 return "2D";
1870 }
1871}
1872
1873/**
1874 * Initializes the ShaderKey to the empty state.
1875 */
1876ShaderGenerator::ShaderKey::
1877ShaderKey() :
1878 _color_type(ColorAttrib::T_vertex),
1879 _material_flags(0),
1880 _texture_flags(0),
1881 _lighting(false),
1882 _have_separate_ambient(false),
1883 _fog_mode(0),
1884 _outputs(0),
1885 _calc_primary_alpha(false),
1886 _disable_alpha_write(false),
1887 _alpha_test_mode(RenderAttrib::M_none),
1888 _alpha_test_ref(0.0),
1889 _num_clip_planes(0),
1890 _light_ramp(nullptr) {
1891}
1892
1893/**
1894 * Returns true if this ShaderKey sorts less than the other one. This is an
1895 * arbitrary, but consistent ordering.
1896 */
1897bool ShaderGenerator::ShaderKey::
1898operator < (const ShaderKey &other) const {
1899 if (_anim_spec != other._anim_spec) {
1900 return _anim_spec < other._anim_spec;
1901 }
1902 if (_color_type != other._color_type) {
1903 return _color_type < other._color_type;
1904 }
1905 if (_material_flags != other._material_flags) {
1906 return _material_flags < other._material_flags;
1907 }
1908 if (_texture_flags != other._texture_flags) {
1909 return _texture_flags < other._texture_flags;
1910 }
1911 if (_textures.size() != other._textures.size()) {
1912 return _textures.size() < other._textures.size();
1913 }
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;
1919 }
1920 if (tex._type != other_tex._type) {
1921 return tex._type < other_tex._type;
1922 }
1923 if (tex._mode != other_tex._mode) {
1924 return tex._mode < other_tex._mode;
1925 }
1926 if (tex._gen_mode != other_tex._gen_mode) {
1927 return tex._gen_mode < other_tex._gen_mode;
1928 }
1929 if (tex._flags != other_tex._flags) {
1930 return tex._flags < other_tex._flags;
1931 }
1932 if (tex._combine_rgb != other_tex._combine_rgb) {
1933 return tex._combine_rgb < other_tex._combine_rgb;
1934 }
1935 if (tex._combine_alpha != other_tex._combine_alpha) {
1936 return tex._combine_alpha < other_tex._combine_alpha;
1937 }
1938 }
1939 if (_lights.size() != other._lights.size()) {
1940 return _lights.size() < other._lights.size();
1941 }
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;
1947 }
1948 if (light._flags != other_light._flags) {
1949 return light._flags < other_light._flags;
1950 }
1951 }
1952 if (_lighting != other._lighting) {
1953 return _lighting < other._lighting;
1954 }
1955 if (_have_separate_ambient != other._have_separate_ambient) {
1956 return _have_separate_ambient < other._have_separate_ambient;
1957 }
1958 if (_fog_mode != other._fog_mode) {
1959 return _fog_mode < other._fog_mode;
1960 }
1961 if (_outputs != other._outputs) {
1962 return _outputs < other._outputs;
1963 }
1964 if (_calc_primary_alpha != other._calc_primary_alpha) {
1965 return _calc_primary_alpha < other._calc_primary_alpha;
1966 }
1967 if (_disable_alpha_write != other._disable_alpha_write) {
1968 return _disable_alpha_write < other._disable_alpha_write;
1969 }
1970 if (_alpha_test_mode != other._alpha_test_mode) {
1971 return _alpha_test_mode < other._alpha_test_mode;
1972 }
1973 if (_alpha_test_ref != other._alpha_test_ref) {
1974 return _alpha_test_ref < other._alpha_test_ref;
1975 }
1976 if (_num_clip_planes != other._num_clip_planes) {
1977 return _num_clip_planes < other._num_clip_planes;
1978 }
1979 return _light_ramp < other._light_ramp;
1980}
1981
1982/**
1983 * Returns true if this ShaderKey is equal to the other one.
1984 */
1985bool ShaderGenerator::ShaderKey::
1986operator == (const ShaderKey &other) const {
1987 if (_anim_spec != other._anim_spec) {
1988 return false;
1989 }
1990 if (_color_type != other._color_type) {
1991 return false;
1992 }
1993 if (_material_flags != other._material_flags) {
1994 return false;
1995 }
1996 if (_texture_flags != other._texture_flags) {
1997 return false;
1998 }
1999 if (_textures.size() != other._textures.size()) {
2000 return false;
2001 }
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) {
2012 return false;
2013 }
2014 }
2015 if (_lights.size() != other._lights.size()) {
2016 return false;
2017 }
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) {
2023 return false;
2024 }
2025 }
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;
2036}
2037
2038#else
2039
2040// Stubs for when building without Cg support.
2041ShaderGenerator::
2042ShaderGenerator(const GraphicsStateGuardianBase *gsg) {
2043}
2044
2045ShaderGenerator::
2046~ShaderGenerator() {
2047}
2048
2049void ShaderGenerator::
2050rehash_generated_shaders() {
2051}
2052
2053void ShaderGenerator::
2054clear_generated_shaders() {
2055}
2056
2057CPT(ShaderAttrib) ShaderGenerator::
2058synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
2059 return nullptr;
2060}
2061
2062#endif // HAVE_CG
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.
Definition: colorAttrib.h:27
get_color_type
Returns the type of color specified by this ColorAttrib.
Definition: colorAttrib.h:46
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.
Definition: fogAttrib.h:25
get_fog
If the FogAttrib is not an 'off' FogAttrib, returns the fog that is associated.
Definition: fogAttrib.h:38
bool is_off() const
Returns true if the FogAttrib is an 'off' FogAttrib, indicating that it should disable fog.
Definition: fogAttrib.I:26
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.
Definition: internalName.h:38
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
Definition: lightAttrib.h:30
get_num_on_lights
Returns the number of lights that are turned on by the attribute.
Definition: lightAttrib.h:74
get_on_light
Returns the nth light turned on by the attribute, sorted in render order.
Definition: lightAttrib.h:74
A derivative of Light and of Camera.
Definition: lightLensNode.h:33
is_shadow_caster
Returns whether this light is configured to cast shadows or not.
Definition: lightLensNode.h:52
bool has_specular_color() const
Returns true if this light defines a specular color, false if the specular color is derived automatic...
Definition: lightLensNode.I:19
void mark_used_by_auto_shader() const
Marks this light as having been used by the auto shader.
Definition: lightLensNode.I:78
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.
Definition: material.h:43
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
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...
Definition: pStatTimer.h:30
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
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...
Definition: pandaNode.cxx:2104
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...
Definition: renderAttrib.h:51
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
bool auto_shader() const
If true, then this ShaderAttrib does not contain an explicit shader - instead, it requests the automa...
Definition: shaderAttrib.I:71
Definition: shader.h:49
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.
Definition: texGenAttrib.h:32
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...
Definition: textureAttrib.h:31
get_num_on_stages
Returns the number of stages that are turned on by the attribute.
Definition: textureAttrib.h:55
get_on_texture
Returns the texture associated with the indicated stage, or NULL if no texture is associated.
Definition: textureAttrib.h:69
get_on_stage
Returns the nth stage turned on by the attribute, sorted in render order.
Definition: textureAttrib.h:55
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:35
bool uses_primary_color() const
Returns true if the TextureStage makes use of the CS_primary_color combine source.
Definition: textureStage.I:618
CombineMode get_combine_alpha_mode() const
Get combine_alpha_mode.
Definition: textureStage.I:534
get_saved_result
Returns the current setting of the saved_result flag.
Definition: textureStage.h:203
CombineOperand get_combine_rgb_operand2() const
Get operand2 of combine_rgb_mode.
Definition: textureStage.I:453
CombineSource get_combine_alpha_source1() const
Get source1 of combine_alpha_mode.
Definition: textureStage.I:567
CombineMode get_combine_rgb_mode() const
Get the combine_rgb_mode.
Definition: textureStage.I:396
CombineSource get_combine_rgb_source1() const
Get source1 of combine_rgb_mode.
Definition: textureStage.I:429
CombineOperand get_combine_alpha_operand0() const
Get operand0 of combine_alpha_mode.
Definition: textureStage.I:559
CombineOperand get_combine_rgb_operand1() const
Get operand1 of combine_rgb_mode.
Definition: textureStage.I:437
CombineSource get_combine_alpha_source0() const
Get source0 of combine_alpha_mode.
Definition: textureStage.I:551
get_rgb_scale
See set_rgb_scale().
Definition: textureStage.h:201
get_alpha_scale
See set_alpha_scale().
Definition: textureStage.h:202
CombineOperand get_combine_alpha_operand1() const
Get operand1 of combine_alpha_mode.
Definition: textureStage.I:575
CombineSource get_combine_rgb_source0() const
Get source0 of combine_rgb_mode.
Definition: textureStage.I:413
CombineSource get_combine_rgb_source2() const
Get source2 of combine_rgb_mode.
Definition: textureStage.I:445
bool uses_color() const
Returns true if the TextureStage makes use of whatever color is specified in set_color(),...
Definition: textureStage.I:609
CombineOperand get_combine_rgb_operand0() const
Get operand0 of combine_rgb_mode.
Definition: textureStage.I:421
CombineSource get_combine_alpha_source2() const
Get source2 of combine_alpha_mode.
Definition: textureStage.I:583
get_texcoord_name
See set_texcoord_name.
Definition: textureStage.h:194
bool uses_last_saved_result() const
Returns true if the TextureStage makes use of the CS_primary_color combine source.
Definition: textureStage.I:627
CombineOperand get_combine_alpha_operand2() const
Get operand2 of combine_alpha_mode.
Definition: textureStage.I:591
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:71
get_format
Returns the format of the texture, which represents both the semantic meaning of the texels and,...
Definition: texture.h:370
static bool has_alpha(Format format)
Returns true if the indicated format includes alpha, false otherwise.
Definition: texture.cxx:2633
Indicates a coordinate-system transform on vertices.
This controls the enabling of transparency.
get_mode
Returns the transparency mode.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
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.