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 
50 using std::string;
51 
52 TypeHandle 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 
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;
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 
72 static PStatCollector lookup_collector("*:Munge:ShaderGen:Lookup");
73 static 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  */
80 ShaderGenerator::
81 ShaderGenerator(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  */
99 ShaderGenerator::
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  */
107 void ShaderGenerator::
108 reset_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  */
118 const char *ShaderGenerator::
119 alloc_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  */
175 const char *ShaderGenerator::
176 alloc_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  */
206 void ShaderGenerator::
207 analyze_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  default:
471  break;
472  }
473  // We can't just drop a disabled slot from the list, since then the
474  // indices for the texture stages will no longer match up. So we keep it,
475  // but set it to a noop state to indicate that it should be skipped.
476  if (skip) {
477  info._type = Texture::TT_1d_texture;
478  info._mode = TextureStage::M_modulate;
479  info._flags = 0;
480  key._textures.push_back(info);
481  continue;
482  }
483 
484  // Check if this state has a texture matrix to transform the texture
485  // coordinates.
486  if (tex_matrix->has_stage(stage)) {
487  CPT(TransformState) transform = tex_matrix->get_transform(stage);
488  if (!transform->is_identity()) {
489  // Optimize for common case: if we only have a scale component, we
490  // can get away with fewer shader inputs and operations.
491  if (transform->has_components() && !transform->has_nonzero_shear() &&
492  transform->get_pos() == LPoint3::zero() &&
493  transform->get_hpr() == LVecBase3::zero()) {
494  info._flags |= ShaderKey::TF_has_texscale;
495  } else {
496  info._flags |= ShaderKey::TF_has_texmat;
497  }
498  }
499  }
500 
501  if (tex_gen->has_stage(stage)) {
502  info._texcoord_name = nullptr;
503  info._gen_mode = tex_gen->get_mode(stage);
504  } else {
505  info._texcoord_name = stage->get_texcoord_name();
506  info._gen_mode = TexGenAttrib::M_off;
507  }
508 
509  // Does this stage require saving its result?
510  if (stage->get_saved_result()) {
511  info._flags |= ShaderKey::TF_saved_result;
512  }
513 
514  // Does this stage need a texcolor_# input?
515  if (stage->uses_color()) {
516  info._flags |= ShaderKey::TF_uses_color;
517  }
518 
519  key._textures.push_back(info);
520  key._texture_flags |= info._flags;
521  }
522 
523  // Does nothing use the saved result? If so, don't bother saving it.
524  if ((key._texture_flags & ShaderKey::TF_uses_last_saved_result) == 0 &&
525  (key._texture_flags & ShaderKey::TF_saved_result) != 0) {
526 
528  for (it = key._textures.begin(); it != key._textures.end(); ++it) {
529  (*it)._flags &= ~ShaderKey::TF_saved_result;
530  }
531  key._texture_flags &= ~ShaderKey::TF_saved_result;
532  }
533 
534  // Decide whether to separate ambient and diffuse calculations.
535  if (have_ambient) {
536  if (key._material_flags & Material::F_ambient) {
537  key._have_separate_ambient = true;
538  } else {
539  if (key._material_flags & Material::F_diffuse) {
540  key._have_separate_ambient = true;
541  } else {
542  key._have_separate_ambient = false;
543  }
544  }
545  }
546 
547  if (shader_attrib->auto_ramp_on()) {
548  const LightRampAttrib *light_ramp;
549  if (rs->get_attrib(light_ramp)) {
550  key._light_ramp = light_ramp;
551  if (key._lighting) {
552  key._have_separate_ambient = true;
553  }
554  }
555  }
556 
557  // Check for clip planes.
558  const ClipPlaneAttrib *clip_plane;
559  rs->get_attrib_def(clip_plane);
560  key._num_clip_planes = clip_plane->get_num_on_planes();
561 
562  // Check for fog.
563  const FogAttrib *fog;
564  if (rs->get_attrib(fog) && !fog->is_off()) {
565  key._fog_mode = (int)fog->get_fog()->get_mode() + 1;
566  }
567 }
568 
569 /**
570  * Rehashes all the states with generated shaders, removing the ones that are
571  * no longer fresh.
572  *
573  * Call this if certain state has changed in such a way as to require a rerun
574  * of the shader generator. This should be rare because in most cases, the
575  * shader generator will automatically regenerate shaders as necessary.
576  *
577  * @since 1.10.0
578  */
579 void ShaderGenerator::
580 rehash_generated_shaders() {
581  LightReMutexHolder holder(*RenderState::_states_lock);
582 
583  // With uniquify-states turned on, we can actually go through all the states
584  // and check whether their generated shader is still OK.
585  size_t size = RenderState::_states->get_num_entries();
586  for (size_t si = 0; si < size; ++si) {
587  const RenderState *state = RenderState::_states->get_key(si);
588 
589  if (state->_generated_shader != nullptr) {
590  ShaderKey key;
591  analyze_renderstate(key, state);
592 
593  GeneratedShaders::const_iterator si;
594  si = _generated_shaders.find(key);
595  if (si != _generated_shaders.end()) {
596  if (si->second != state->_generated_shader) {
597  state->_generated_shader = si->second;
598  state->_munged_states.clear();
599  }
600  } else {
601  // We have not yet generated a shader for this modified state.
602  state->_generated_shader.clear();
603  state->_munged_states.clear();
604  }
605  }
606  }
607 
608  // If we don't have uniquify-states, however, the above list won't contain
609  // all the state. We can change a global seq value to require Panda to
610  // rehash the states the next time it tries to render an object with it.
611  if (!uniquify_states) {
612  GraphicsStateGuardianBase::mark_rehash_generated_shaders();
613  }
614 }
615 
616 /**
617  * Removes all previously generated shaders, requiring all shaders to be
618  * regenerated. Does not clear cache of compiled shaders.
619  *
620  * @since 1.10.0
621  */
622 void ShaderGenerator::
623 clear_generated_shaders() {
624  LightReMutexHolder holder(*RenderState::_states_lock);
625 
626  size_t size = RenderState::_states->get_num_entries();
627  for (size_t si = 0; si < size; ++si) {
628  const RenderState *state = RenderState::_states->get_key(si);
629  state->_generated_shader.clear();
630  }
631 
632  _generated_shaders.clear();
633 
634  // If we don't have uniquify-states, we can't clear all the ShaderAttribs
635  // that are cached on the states, but we can simulate the effect of that.
636  if (!uniquify_states) {
637  GraphicsStateGuardianBase::mark_rehash_generated_shaders();
638  }
639 }
640 
641 /**
642  * This is the routine that implements the next-gen fixed function pipeline by
643  * synthesizing a shader. It also takes care of setting up any buffers needed
644  * to produce the requested effects.
645  *
646  * Currently supports:
647  * - flat colors
648  * - vertex colors
649  * - lighting
650  * - normal maps, even multiple
651  * - gloss maps, but not multiple
652  * - glow maps, but not multiple
653  * - materials, but not updates to materials
654  * - 2D textures
655  * - all texture stage modes, including combine modes
656  * - color scale attrib
657  * - light ramps (for cartoon shading)
658  * - shadow mapping
659  * - most texgen modes
660  * - texmatrix
661  * - 1D/2D/3D textures, cube textures, 2D tex arrays
662  * - linear/exp/exp2 fog
663  * - animation
664  *
665  * Potential optimizations
666  * - omit attenuation calculations if attenuation off
667  *
668  */
669 CPT(ShaderAttrib) ShaderGenerator::
670 synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
671  ShaderKey key;
672 
673  // First look up the state key in the table of already generated shaders.
674  {
675  PStatTimer timer(lookup_collector);
676  key._anim_spec = anim;
677  analyze_renderstate(key, rs);
678 
679  GeneratedShaders::const_iterator si;
680  si = _generated_shaders.find(key);
681  if (si != _generated_shaders.end()) {
682  // We've already generated a shader for this state.
683  return si->second;
684  }
685  }
686 
687  PStatTimer timer(synthesize_collector);
688 
689  reset_register_allocator();
690 
691  if (pgraphnodes_cat.is_debug()) {
692  pgraphnodes_cat.debug()
693  << "Generating shader for render state " << rs << ":\n";
694  rs->write(pgraphnodes_cat.debug(false), 2);
695  }
696 
697  // These variables will hold the results of register allocation.
698 
699  const char *tangent_freg = nullptr;
700  const char *binormal_freg = nullptr;
701  string tangent_input;
702  string binormal_input;
704  pvector<const char *> lightcoord_fregs;
705  const char *world_position_freg = nullptr;
706  const char *world_normal_freg = nullptr;
707  const char *eye_position_freg = nullptr;
708  const char *eye_normal_freg = nullptr;
709  const char *hpos_freg = nullptr;
710 
711  const char *position_vreg;
712  const char *transform_weight_vreg = nullptr;
713  const char *normal_vreg;
714  const char *color_vreg = nullptr;
715  const char *transform_index_vreg = nullptr;
716 
717  if (_use_generic_attr) {
718  position_vreg = "ATTR0";
719  transform_weight_vreg = "ATTR1";
720  normal_vreg = "ATTR2";
721  transform_index_vreg = "ATTR7";
722  } else {
723  position_vreg = "POSITION";
724  normal_vreg = "NORMAL";
725  }
726 
727  if (key._color_type == ColorAttrib::T_vertex) {
728  // Reserve COLOR0
729  color_vreg = _use_generic_attr ? "ATTR3" : "COLOR0";
730  _vcregs_used = 1;
731  _fcregs_used = 1;
732  }
733 
734  // Generate the shader's text.
735 
736  std::ostringstream text;
737 
738  text << "//Cg\n";
739 
740  text << "/* Generated shader for render state:\n";
741  rs->write(text, 2);
742  text << "*/\n";
743 
744  int map_index_glow = -1;
745  int map_index_gloss = -1;
746 
747  // Figure out whether we need to calculate any of these variables.
748  bool need_world_position = (key._num_clip_planes > 0);
749  bool need_world_normal = false;
750  bool need_eye_position = key._lighting;
751  bool need_eye_normal = !key._lights.empty() || ((key._outputs & AuxBitplaneAttrib::ABO_aux_normal) != 0);
752  bool need_tangents = ((key._texture_flags & ShaderKey::TF_map_normal) != 0);
753 
754  // If we have binormal/tangent and eye position, we can pack eye normal in
755  // the w channels of the others.
756  bool pack_eye_normal = need_eye_normal && need_tangents && need_eye_position;
757 
758  bool have_specular = false;
759  if (key._lighting) {
760  if (key._material_flags & Material::F_specular) {
761  have_specular = true;
762  } else if ((key._texture_flags & ShaderKey::TF_map_gloss) != 0) {
763  have_specular = true;
764  }
765  }
766 
767  bool need_color = false;
768  if (key._color_type != ColorAttrib::T_off) {
769  if (key._lighting) {
770  if (((key._material_flags & Material::F_ambient) == 0 && key._have_separate_ambient) ||
771  (key._material_flags & Material::F_diffuse) == 0 ||
772  key._calc_primary_alpha) {
773  need_color = true;
774  }
775  } else {
776  need_color = true;
777  }
778  }
779 
780  text << "void vshader(\n";
781  for (size_t i = 0; i < key._textures.size(); ++i) {
782  const ShaderKey::TextureInfo &tex = key._textures[i];
783 
784  switch (tex._gen_mode) {
785  case TexGenAttrib::M_world_position:
786  need_world_position = true;
787  break;
788  case TexGenAttrib::M_world_normal:
789  need_world_normal = true;
790  break;
791  case TexGenAttrib::M_eye_position:
792  need_eye_position = true;
793  break;
794  case TexGenAttrib::M_eye_normal:
795  need_eye_normal = true;
796  break;
797  default:
798  break;
799  }
800 
801  if (tex._texcoord_name != nullptr) {
802  if (texcoord_fregs.count(tex._texcoord_name) == 0) {
803  const char *freg = alloc_freg();
804  texcoord_fregs[tex._texcoord_name] = freg;
805 
806  string tcname = tex._texcoord_name->join("_");
807  text << "\t in float4 vtx_" << tcname << " : " << alloc_vreg() << ",\n";
808  text << "\t out float4 l_" << tcname << " : " << freg << ",\n";
809  }
810  }
811 
812  if (tangent_input.empty() &&
813  (tex._flags & (ShaderKey::TF_map_normal | ShaderKey::TF_map_height)) != 0) {
814  PT(InternalName) tangent_name = InternalName::get_tangent();
815  PT(InternalName) binormal_name = InternalName::get_binormal();
816 
817  if (tex._texcoord_name != nullptr &&
818  tex._texcoord_name != InternalName::get_texcoord()) {
819  tangent_name = tangent_name->append(tex._texcoord_name->get_basename());
820  binormal_name = binormal_name->append(tex._texcoord_name->get_basename());
821  }
822 
823  tangent_input = tangent_name->join("_");
824  binormal_input = binormal_name->join("_");
825 
826  text << "\t in float4 vtx_" << tangent_input << " : " << alloc_vreg() << ",\n";
827  text << "\t in float4 vtx_" << binormal_input << " : " << alloc_vreg() << ",\n";
828  }
829 
830  if (tex._flags & ShaderKey::TF_map_glow) {
831  map_index_glow = i;
832  }
833  if (tex._flags & ShaderKey::TF_map_gloss) {
834  map_index_gloss = i;
835  }
836  }
837  if (need_tangents) {
838  tangent_freg = alloc_freg();
839  binormal_freg = alloc_freg();
840  text << "\t out float4 l_tangent : " << tangent_freg << ",\n";
841  text << "\t out float4 l_binormal : " << binormal_freg << ",\n";
842  }
843  if (need_color && key._color_type == ColorAttrib::T_vertex) {
844  text << "\t in float4 vtx_color : " << color_vreg << ",\n";
845  text << "\t out float4 l_color : COLOR0,\n";
846  }
847  if (need_world_position || need_world_normal) {
848  text << "\t uniform float4x4 trans_model_to_world,\n";
849  }
850  if (need_world_position) {
851  world_position_freg = alloc_freg();
852  text << "\t out float4 l_world_position : " << world_position_freg << ",\n";
853  }
854  if (need_world_normal) {
855  world_normal_freg = alloc_freg();
856  text << "\t out float4 l_world_normal : " << world_normal_freg << ",\n";
857  }
858  if (need_eye_position) {
859  text << "\t uniform float4x4 trans_model_to_view,\n";
860  eye_position_freg = alloc_freg();
861  text << "\t out float4 l_eye_position : " << eye_position_freg << ",\n";
862  } else if (need_tangents) {
863  text << "\t uniform float4x4 trans_model_to_view,\n";
864  }
865  if (need_eye_normal) {
866  text << "\t uniform float4x4 tpose_view_to_model,\n";
867  if (!pack_eye_normal) {
868  eye_normal_freg = alloc_freg();
869  text << "\t out float3 l_eye_normal : " << eye_normal_freg << ",\n";
870  }
871  }
872  if ((key._texture_flags & ShaderKey::TF_map_height) != 0 || need_world_normal || need_eye_normal) {
873  text << "\t in float3 vtx_normal : " << normal_vreg << ",\n";
874  }
875  if (key._texture_flags & ShaderKey::TF_map_height) {
876  text << "\t uniform float4 mspos_view,\n";
877  text << "\t out float3 l_eyevec,\n";
878  }
879  if (key._fog_mode != 0) {
880  hpos_freg = alloc_freg();
881  text << "\t out float4 l_hpos : " << hpos_freg << ",\n";
882  }
883  for (size_t i = 0; i < key._lights.size(); ++i) {
884  const ShaderKey::LightInfo &light = key._lights[i];
885  if (light._flags & ShaderKey::LF_has_shadows) {
886  if (_ftregs_used >= 8) {
887  // We ran out of TEXCOORD registers. That means we have to do this
888  // calculation in the fragment shader, which is slower.
889  lightcoord_fregs.push_back(nullptr);
890  } else {
891  lightcoord_fregs.push_back(alloc_freg());
892  text << "\t uniform float4x4 mat_shadow_" << i << ",\n";
893  text << "\t out float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n";
894  }
895  } else {
896  lightcoord_fregs.push_back(nullptr);
897  }
898  }
899  if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware &&
900  key._anim_spec.get_num_transforms() > 0) {
901  int num_transforms;
902  if (key._anim_spec.get_indexed_transforms()) {
903  num_transforms = 120;
904  } else {
905  num_transforms = key._anim_spec.get_num_transforms();
906  }
907  if (transform_weight_vreg == nullptr) {
908  transform_weight_vreg = alloc_vreg();
909  }
910  if (transform_index_vreg == nullptr) {
911  transform_index_vreg = alloc_vreg();
912  }
913  text << "\t uniform float4x4 tbl_transforms[" << num_transforms << "],\n";
914  text << "\t in float4 vtx_transform_weight : " << transform_weight_vreg << ",\n";
915  if (key._anim_spec.get_indexed_transforms()) {
916  text << "\t in uint4 vtx_transform_index : " << transform_index_vreg << ",\n";
917  }
918  }
919  text << "\t in float4 vtx_position : " << position_vreg << ",\n";
920  text << "\t out float4 l_position : POSITION,\n";
921  text << "\t uniform float4x4 mat_modelproj\n";
922  text << ") {\n";
923 
924  if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware &&
925  key._anim_spec.get_num_transforms() > 0) {
926 
927  if (!key._anim_spec.get_indexed_transforms()) {
928  text << "\t const uint4 vtx_transform_index = uint4(0, 1, 2, 3);\n";
929  }
930 
931  text << "\t float4x4 matrix = tbl_transforms[vtx_transform_index.x] * vtx_transform_weight.x";
932  if (key._anim_spec.get_num_transforms() > 1) {
933  text << "\n\t + tbl_transforms[vtx_transform_index.y] * vtx_transform_weight.y";
934  }
935  if (key._anim_spec.get_num_transforms() > 2) {
936  text << "\n\t + tbl_transforms[vtx_transform_index.z] * vtx_transform_weight.z";
937  }
938  if (key._anim_spec.get_num_transforms() > 3) {
939  text << "\n\t + tbl_transforms[vtx_transform_index.w] * vtx_transform_weight.w";
940  }
941  text << ";\n";
942 
943  text << "\t vtx_position = mul(matrix, vtx_position);\n";
944  if (need_world_normal || need_eye_normal) {
945  text << "\t vtx_normal = mul((float3x3)matrix, vtx_normal);\n";
946  }
947  }
948 
949  text << "\t l_position = mul(mat_modelproj, vtx_position);\n";
950  if (key._fog_mode != 0) {
951  text << "\t l_hpos = l_position;\n";
952  }
953  if (need_world_position) {
954  text << "\t l_world_position = mul(trans_model_to_world, vtx_position);\n";
955  }
956  if (need_world_normal) {
957  text << "\t l_world_normal = mul(trans_model_to_world, float4(vtx_normal, 0));\n";
958  }
959  if (need_eye_position) {
960  text << "\t l_eye_position = mul(trans_model_to_view, vtx_position);\n";
961  }
963  for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
964  // Pass through all texcoord inputs as-is.
965  string tcname = it->first->join("_");
966  text << "\t l_" << tcname << " = vtx_" << tcname << ";\n";
967  }
968  if (need_color && key._color_type == ColorAttrib::T_vertex) {
969  text << "\t l_color = vtx_color;\n";
970  }
971  if (need_tangents) {
972  text << "\t l_tangent.xyz = normalize(mul((float3x3)trans_model_to_view, vtx_" << tangent_input << ".xyz));\n";
973  text << "\t l_tangent.w = 0;\n";
974  text << "\t l_binormal.xyz = normalize(mul((float3x3)trans_model_to_view, -vtx_" << binormal_input << ".xyz));\n";
975  text << "\t l_binormal.w = 0;\n";
976  }
977  for (size_t i = 0; i < key._lights.size(); ++i) {
978  if (key._lights[i]._flags & ShaderKey::LF_has_shadows) {
979  if (lightcoord_fregs[i] != nullptr) {
980  text << "\t l_lightcoord" << i << " = mul(mat_shadow_" << i << ", l_eye_position);\n";
981  }
982  }
983  }
984  if (key._texture_flags & ShaderKey::TF_map_height) {
985  text << "\t float3 eyedir = mspos_view.xyz - vtx_position.xyz;\n";
986  text << "\t l_eyevec.x = dot(vtx_" << tangent_input << ".xyz, eyedir);\n";
987  text << "\t l_eyevec.y = dot(vtx_" << binormal_input << ".xyz, eyedir);\n";
988  text << "\t l_eyevec.z = dot(vtx_normal, eyedir);\n";
989  text << "\t l_eyevec = normalize(l_eyevec);\n";
990  }
991  if (need_eye_normal) {
992  if (pack_eye_normal) {
993  // We can pack the normal into the w channels of these unused varyings.
994  text << "\t float3 eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n";
995  text << "\t l_tangent.w = eye_normal.x;\n";
996  text << "\t l_binormal.w = eye_normal.y;\n";
997  text << "\t l_eye_position.w = eye_normal.z;\n";
998  } else {
999  text << "\t l_eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n";
1000  }
1001  }
1002  text << "}\n\n";
1003 
1004  // Fragment shader
1005 
1006  text << "void fshader(\n";
1007  if (key._fog_mode != 0) {
1008  text << "\t in float4 l_hpos : " << hpos_freg << ",\n";
1009  text << "\t in uniform float4 attr_fog,\n";
1010  text << "\t in uniform float4 attr_fogcolor,\n";
1011  }
1012  if (need_world_position) {
1013  text << "\t in float4 l_world_position : " << world_position_freg << ",\n";
1014  }
1015  if (need_world_normal) {
1016  text << "\t in float4 l_world_normal : " << world_normal_freg << ",\n";
1017  }
1018  if (need_eye_position) {
1019  text << "\t in float4 l_eye_position : " << eye_position_freg << ",\n";
1020  }
1021  if (need_eye_normal && !pack_eye_normal) {
1022  text << "\t in float3 l_eye_normal : " << eye_normal_freg << ",\n";
1023  }
1024  for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
1025  text << "\t in float4 l_" << it->first->join("_") << " : " << it->second << ",\n";
1026  }
1027  for (size_t i = 0; i < key._textures.size(); ++i) {
1028  const ShaderKey::TextureInfo &tex = key._textures[i];
1029  if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1030  // Skip this stage.
1031  continue;
1032  }
1033 
1034  text << "\t uniform sampler" << texture_type_as_string(tex._type) << " tex_" << i << ",\n";
1035 
1036  if (tex._flags & ShaderKey::TF_has_texscale) {
1037  text << "\t uniform float3 texscale_" << i << ",\n";
1038  } else if (tex._flags & ShaderKey::TF_has_texmat) {
1039  text << "\t uniform float4x4 texmat_" << i << ",\n";
1040  }
1041 
1042  if (tex._flags & ShaderKey::TF_uses_color) {
1043  text << "\t uniform float4 texcolor_" << i << ",\n";
1044  }
1045  }
1046  if (need_tangents) {
1047  text << "\t in float4 l_tangent : " << tangent_freg << ",\n";
1048  text << "\t in float4 l_binormal : " << binormal_freg << ",\n";
1049  }
1050  for (size_t i = 0; i < key._lights.size(); ++i) {
1051  text << "\t uniform float4x4 attr_light" << i << ",\n";
1052 
1053  const ShaderKey::LightInfo &light = key._lights[i];
1054  if (light._flags & ShaderKey::LF_has_shadows) {
1055  if (light._type.is_derived_from(PointLight::get_class_type())) {
1056  text << "\t uniform samplerCUBE shadow_" << i << ",\n";
1057  } else if (_use_shadow_filter) {
1058  text << "\t uniform sampler2DShadow shadow_" << i << ",\n";
1059  } else {
1060  text << "\t uniform sampler2D shadow_" << i << ",\n";
1061  }
1062  if (lightcoord_fregs[i] != nullptr) {
1063  text << "\t in float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n";
1064  } else {
1065  text << "\t uniform float4x4 mat_shadow_" << i << ",\n";
1066  }
1067  }
1068  if (light._flags & ShaderKey::LF_has_specular_color) {
1069  text << "\t uniform float4 attr_lspec" << i << ",\n";
1070  }
1071  }
1072 
1073  // Does the shader need material properties as input?
1074  if (key._material_flags & (Material::F_ambient | Material::F_diffuse | Material::F_emission | Material::F_specular)) {
1075  text << "\t uniform float4x4 attr_material,\n";
1076  }
1077  if (key._texture_flags & ShaderKey::TF_map_height) {
1078  text << "\t float3 l_eyevec,\n";
1079  }
1080  if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
1081  text << "\t out float4 o_aux : COLOR1,\n";
1082  }
1083  text << "\t out float4 o_color : COLOR0,\n";
1084 
1085  if (need_color) {
1086  if (key._color_type == ColorAttrib::T_vertex) {
1087  text << "\t in float4 l_color : COLOR0,\n";
1088  } else if (key._color_type == ColorAttrib::T_flat) {
1089  text << "\t uniform float4 attr_color,\n";
1090  }
1091  }
1092 
1093  for (int i = 0; i < key._num_clip_planes; ++i) {
1094  text << "\t uniform float4 clipplane_" << i << ",\n";
1095  }
1096 
1097  text << "\t uniform float4 attr_ambient,\n";
1098  text << "\t uniform float4 attr_colorscale\n";
1099  text << ") {\n";
1100 
1101  // Clipping first!
1102  for (int i = 0; i < key._num_clip_planes; ++i) {
1103  text << "\t if (l_world_position.x * clipplane_" << i << ".x + l_world_position.y ";
1104  text << "* clipplane_" << i << ".y + l_world_position.z * clipplane_" << i << ".z + clipplane_" << i << ".w <= 0) {\n";
1105  text << "\t discard;\n";
1106  text << "\t }\n";
1107  }
1108 
1109  // Reconstruct a packed normal vector.
1110  if (need_eye_normal && pack_eye_normal) {
1111  text << "\t float3 l_eye_normal = float3(l_tangent.w, l_binormal.w, l_eye_position.w);\n";
1112  }
1113 
1114  text << "\t float4 result;\n";
1115  if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
1116  text << "\t o_aux = float4(0, 0, 0, 0);\n";
1117  }
1118  // Now generate any texture coordinates according to TexGenAttrib. If it
1119  // has a TexMatrixAttrib, also transform them.
1120  for (size_t i = 0; i < key._textures.size(); ++i) {
1121  const ShaderKey::TextureInfo &tex = key._textures[i];
1122  if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1123  // Skip this stage.
1124  continue;
1125  }
1126  switch (tex._gen_mode) {
1127  case TexGenAttrib::M_off:
1128  // Cg seems to be able to optimize this temporary away when appropriate.
1129  text << "\t float4 texcoord" << i << " = l_" << tex._texcoord_name->join("_") << ";\n";
1130  break;
1131  case TexGenAttrib::M_world_position:
1132  text << "\t float4 texcoord" << i << " = l_world_position;\n";
1133  break;
1134  case TexGenAttrib::M_world_normal:
1135  text << "\t float4 texcoord" << i << " = l_world_normal;\n";
1136  break;
1137  case TexGenAttrib::M_eye_position:
1138  text << "\t float4 texcoord" << i << " = float4(l_eye_position.xyz, 1.0f);\n";
1139  break;
1140  case TexGenAttrib::M_eye_normal:
1141  text << "\t float4 texcoord" << i << " = float4(l_eye_normal, 1.0f);\n";
1142  break;
1143  default:
1144  text << "\t float4 texcoord" << i << " = float4(0, 0, 0, 0);\n";
1145  pgraphnodes_cat.error()
1146  << "Unsupported TexGenAttrib mode: " << tex._gen_mode << "\n";
1147  }
1148  if (tex._flags & ShaderKey::TF_has_texscale) {
1149  text << "\t texcoord" << i << ".xyz *= texscale_" << i << ";\n";
1150  } else if (tex._flags & ShaderKey::TF_has_texmat) {
1151  text << "\t texcoord" << i << " = mul(texmat_" << i << ", texcoord" << i << ");\n";
1152  text << "\t texcoord" << i << ".xyz /= texcoord" << i << ".w;\n";
1153  }
1154  }
1155  text << "\t // Fetch all textures.\n";
1156  for (size_t i = 0; i < key._textures.size(); ++i) {
1157  const ShaderKey::TextureInfo &tex = key._textures[i];
1158  if ((tex._flags & ShaderKey::TF_map_height) == 0) {
1159  continue;
1160  }
1161 
1162  text << "\t float4 tex" << i << " = tex" << texture_type_as_string(tex._type);
1163  text << "(tex_" << i << ", texcoord" << i << ".";
1164  switch (tex._type) {
1165  case Texture::TT_cube_map:
1166  case Texture::TT_3d_texture:
1167  case Texture::TT_2d_texture_array:
1168  text << "xyz";
1169  break;
1170  case Texture::TT_2d_texture:
1171  text << "xy";
1172  break;
1173  case Texture::TT_1d_texture:
1174  text << "x";
1175  break;
1176  default:
1177  break;
1178  }
1179  text << ");\n\t float3 parallax_offset = l_eyevec.xyz * (tex" << i;
1180  if (tex._mode == TextureStage::M_normal_height ||
1181  (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1182  text << ".aaa";
1183  } else {
1184  text << ".rgb";
1185  }
1186  text << " * 2.0 - 1.0) * " << parallax_mapping_scale << ";\n";
1187  // Additional samples
1188  for (int j = 0; j < parallax_mapping_samples - 1; ++j) {
1189  text << "\t parallax_offset = l_eyevec.xyz * (parallax_offset + (tex" << i;
1190  if (tex._mode == TextureStage::M_normal_height ||
1191  (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1192  text << ".aaa";
1193  } else {
1194  text << ".rgb";
1195  }
1196  text << " * 2.0 - 1.0)) * " << 0.5 * parallax_mapping_scale << ";\n";
1197  }
1198  }
1199  for (size_t i = 0; i < key._textures.size(); ++i) {
1200  ShaderKey::TextureInfo &tex = key._textures[i];
1201  if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1202  // Skip this stage.
1203  continue;
1204  }
1205  if ((tex._flags & ShaderKey::TF_map_height) == 0) {
1206  // Parallax mapping pushes the texture coordinates of the other textures
1207  // away from the camera.
1208  if (key._texture_flags & ShaderKey::TF_map_height) {
1209  text << "\t texcoord" << i << ".xyz -= parallax_offset;\n";
1210  }
1211  text << "\t float4 tex" << i << " = tex" << texture_type_as_string(tex._type);
1212  text << "(tex_" << i << ", texcoord" << i << ".";
1213  switch (tex._type) {
1214  case Texture::TT_cube_map:
1215  case Texture::TT_3d_texture:
1216  case Texture::TT_2d_texture_array:
1217  text << "xyz";
1218  break;
1219  case Texture::TT_2d_texture:
1220  text << "xy";
1221  break;
1222  case Texture::TT_1d_texture:
1223  text << "x";
1224  break;
1225  default:
1226  break;
1227  }
1228  text << ");\n";
1229  }
1230  }
1231  if (need_eye_normal) {
1232  text << "\t // Correct the surface normal for interpolation effects\n";
1233  text << "\t l_eye_normal = normalize(l_eye_normal);\n";
1234  }
1235  if (need_tangents) {
1236  text << "\t // Translate tangent-space normal in map to view-space.\n";
1237 
1238  // Use Reoriented Normal Mapping to blend additional normal maps.
1239  bool is_first = true;
1240  for (size_t i = 0; i < key._textures.size(); ++i) {
1241  const ShaderKey::TextureInfo &tex = key._textures[i];
1242  if (tex._flags & ShaderKey::TF_map_normal) {
1243  if (is_first) {
1244  if (tex._flags & ShaderKey::TF_has_texscale) {
1245  text << "\t float3 tsnormal = normalize(((tex" << i << ".xyz * 2) - 1) * texscale_" << i << ");\n";
1246  } else if (tex._flags & ShaderKey::TF_has_texmat) {
1247  text << "\t float3 tsnormal = normalize(mul(texmat_" << i << ", float4((tex" << i << ".xyz * 2) - 1, 0)).xyz);\n";
1248  } else {
1249  text << "\t float3 tsnormal = normalize((tex" << i << ".xyz * 2) - 1);\n";
1250  }
1251  is_first = false;
1252  continue;
1253  }
1254  text << "\t tsnormal.z += 1;\n";
1255  text << "\t float3 tmp" << i << " = tex" << i << ".xyz * float3(-2, -2, 2) + float3(1, 1, -1);\n";
1256  if (tex._flags & ShaderKey::TF_has_texscale) {
1257  text << "\t tmp" << i << " *= texscale_" << i << ";\n";
1258  } else if (tex._flags & ShaderKey::TF_has_texmat) {
1259  text << "\t tmp" << i << " = mul(texmat_" << i << ", float4(tmp" << i << ", 0)).xyz;\n";
1260  }
1261  text << "\t tsnormal = normalize(tsnormal * dot(tsnormal, tmp" << i << ") - tmp" << i << " * tsnormal.z);\n";
1262  }
1263  }
1264  text << "\t l_eye_normal *= tsnormal.z;\n";
1265  text << "\t l_eye_normal += normalize(l_tangent.xyz) * tsnormal.x;\n";
1266  text << "\t l_eye_normal += normalize(l_binormal.xyz) * tsnormal.y;\n";
1267  text << "\t l_eye_normal = normalize(l_eye_normal);\n";
1268  }
1269  if (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) {
1270  text << "\t // Output the camera-space surface normal\n";
1271  text << "\t o_aux.rgb = (l_eye_normal*0.5) + float3(0.5,0.5,0.5);\n";
1272  }
1273  if (key._lighting) {
1274  text << "\t // Begin view-space light calculations\n";
1275  text << "\t float ldist,lattenv,langle,lshad;\n";
1276  text << "\t float4 lcolor,lspec,lpoint,latten,ldir,leye;\n";
1277  text << "\t float3 lvec,lhalf;\n";
1278  if (key._have_separate_ambient) {
1279  text << "\t float4 tot_ambient = float4(0,0,0,0);\n";
1280  }
1281  text << "\t float4 tot_diffuse = float4(0,0,0,0);\n";
1282  if (have_specular) {
1283  text << "\t float4 tot_specular = float4(0,0,0,0);\n";
1284  if (key._material_flags & Material::F_specular) {
1285  text << "\t float shininess = attr_material[3].w;\n";
1286  } else {
1287  text << "\t float shininess = 50; // no shininess specified, using default\n";
1288  }
1289  }
1290  if (key._have_separate_ambient) {
1291  text << "\t tot_ambient += attr_ambient;\n";
1292  } else {
1293  text << "\t tot_diffuse += attr_ambient;\n";
1294  }
1295  }
1296  for (size_t i = 0; i < key._lights.size(); ++i) {
1297  const ShaderKey::LightInfo &light = key._lights[i];
1298 
1299  if (light._flags & ShaderKey::LF_has_shadows) {
1300  if (lightcoord_fregs[i] == nullptr) {
1301  // We have to do this one in the fragment shader if we ran out of
1302  // varyings.
1303  text << "\t float4 l_lightcoord" << i << " = mul(mat_shadow_" << i << ", float4(l_eye_position.xyz, 1.0f));\n";
1304  }
1305  }
1306 
1307  if (light._type.is_derived_from(DirectionalLight::get_class_type())) {
1308  text << "\t // Directional Light " << i << "\n";
1309  text << "\t lcolor = attr_light" << i << "[0];\n";
1310  if (light._flags & ShaderKey::LF_has_specular_color) {
1311  text << "\t lspec = attr_lspec" << i << ";\n";
1312  } else {
1313  text << "\t lspec = lcolor;\n";
1314  }
1315  text << "\t lvec = attr_light" << i << "[3].xyz;\n";
1316  text << "\t lcolor *= saturate(dot(l_eye_normal, lvec.xyz));\n";
1317  if (light._flags & ShaderKey::LF_has_shadows) {
1318  if (_use_shadow_filter) {
1319  text << "\t lshad = shadow2DProj(shadow_" << i << ", l_lightcoord" << i << ").r;\n";
1320  } else {
1321  text << "\t lshad = tex2Dproj(shadow_" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n";
1322  }
1323  text << "\t lcolor *= lshad;\n";
1324  text << "\t lspec *= lshad;\n";
1325  }
1326  text << "\t tot_diffuse += lcolor;\n";
1327  if (have_specular) {
1328  if (key._material_flags & Material::F_local) {
1329  text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1330  } else {
1331  text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1332  }
1333  text << "\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1334  text << "\t tot_specular += lspec;\n";
1335  }
1336  } else if (light._type.is_derived_from(PointLight::get_class_type())) {
1337  text << "\t // Point Light " << i << "\n";
1338  text << "\t lcolor = attr_light" << i << "[0];\n";
1339  if (light._flags & ShaderKey::LF_has_specular_color) {
1340  text << "\t lspec = attr_lspec" << i << ";\n";
1341  } else {
1342  text << "\t lspec = lcolor;\n";
1343  }
1344  text << "\t latten = attr_light" << i << "[1];\n";
1345  text << "\t lpoint = attr_light" << i << "[3];\n";
1346  text << "\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
1347  text << "\t ldist = length(lvec);\n";
1348  text << "\t lvec /= ldist;\n";
1349  if (light._type.is_derived_from(SphereLight::get_class_type())) {
1350  text << "\t ldist = max(ldist, attr_light" << i << "[2].w);\n";
1351  }
1352  text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1353  text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal, lvec));\n";
1354  if (light._flags & ShaderKey::LF_has_shadows) {
1355  text << "\t ldist = max(abs(l_lightcoord" << i << ".x), max(abs(l_lightcoord" << i << ".y), abs(l_lightcoord" << i << ".z)));\n";
1356  text << "\t ldist = ((latten.w+lpoint.w)/(latten.w-lpoint.w))+((-2*latten.w*lpoint.w)/(ldist * (latten.w-lpoint.w)));\n";
1357  text << "\t lshad = texCUBE(shadow_" << i << ", l_lightcoord" << i << ".xyz).r >= ldist * 0.5 + 0.5;\n";
1358  text << "\t lcolor *= lshad;\n";
1359  text << "\t lspec *= lshad;\n";
1360  }
1361  text << "\t tot_diffuse += lcolor;\n";
1362  if (have_specular) {
1363  if (key._material_flags & Material::F_local) {
1364  text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1365  } else {
1366  text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1367  }
1368  text << "\t lspec *= lattenv;\n";
1369  text << "\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1370  text << "\t tot_specular += lspec;\n";
1371  }
1372  } else if (light._type.is_derived_from(Spotlight::get_class_type())) {
1373  text << "\t // Spot Light " << i << "\n";
1374  text << "\t lcolor = attr_light" << i << "[0];\n";
1375  if (light._flags & ShaderKey::LF_has_specular_color) {
1376  text << "\t lspec = attr_lspec" << i << ";\n";
1377  } else {
1378  text << "\t lspec = lcolor;\n";
1379  }
1380  text << "\t latten = attr_light" << i << "[1];\n";
1381  text << "\t ldir = attr_light" << i << "[2];\n";
1382  text << "\t lpoint = attr_light" << i << "[3];\n";
1383  text << "\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
1384  text << "\t ldist = length(lvec);\n";
1385  text << "\t lvec /= ldist;\n";
1386  text << "\t langle = saturate(dot(ldir.xyz, lvec));\n";
1387  text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1388  text << "\t lattenv *= pow(langle, latten.w);\n";
1389  text << "\t if (langle < ldir.w) lattenv = 0;\n";
1390  text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal, lvec));\n";
1391  if (light._flags & ShaderKey::LF_has_shadows) {
1392  if (_use_shadow_filter) {
1393  text << "\t lshad = shadow2DProj(shadow_" << i << ", l_lightcoord" << i << ").r;\n";
1394  } else {
1395  text << "\t lshad = tex2Dproj(shadow_" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n";
1396  }
1397  text << "\t lcolor *= lshad;\n";
1398  text << "\t lspec *= lshad;\n";
1399  }
1400 
1401  text << "\t tot_diffuse += lcolor;\n";
1402  if (have_specular) {
1403  if (key._material_flags & Material::F_local) {
1404  text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1405  } else {
1406  text << "\t lhalf = normalize(lvec - float3(0,1,0));\n";
1407  }
1408  text << "\t lspec *= lattenv;\n";
1409  text << "\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1410  text << "\t tot_specular += lspec;\n";
1411  }
1412  }
1413  }
1414  if (key._lighting) {
1415  if (key._light_ramp != nullptr) {
1416  switch (key._light_ramp->get_mode()) {
1417  case LightRampAttrib::LRT_single_threshold:
1418  {
1419  PN_stdfloat t = key._light_ramp->get_threshold(0);
1420  PN_stdfloat l0 = key._light_ramp->get_level(0);
1421  text << "\t // Single-threshold light ramp\n";
1422  text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1423  text << "\t float lr_scale = (lr_in < " << t << ") ? 0.0 : (" << l0 << "/lr_in);\n";
1424  text << "\t tot_diffuse = tot_diffuse * lr_scale;\n";
1425  break;
1426  }
1427  case LightRampAttrib::LRT_double_threshold:
1428  {
1429  PN_stdfloat t0 = key._light_ramp->get_threshold(0);
1430  PN_stdfloat t1 = key._light_ramp->get_threshold(1);
1431  PN_stdfloat l0 = key._light_ramp->get_level(0);
1432  PN_stdfloat l1 = key._light_ramp->get_level(1);
1433  text << "\t // Double-threshold light ramp\n";
1434  text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1435  text << "\t float lr_out = 0.0;\n";
1436  text << "\t if (lr_in > " << t0 << ") lr_out=" << l0 << ";\n";
1437  text << "\t if (lr_in > " << t1 << ") lr_out=" << l1 << ";\n";
1438  text << "\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n";
1439  break;
1440  }
1441  default:
1442  break;
1443  }
1444  }
1445  text << "\t // Begin view-space light summation\n";
1446  if (key._material_flags & Material::F_emission) {
1447  if (key._texture_flags & ShaderKey::TF_map_glow) {
1448  text << "\t result = attr_material[2] * saturate(2 * (tex" << map_index_glow << ".a - 0.5));\n";
1449  } else {
1450  text << "\t result = attr_material[2];\n";
1451  }
1452  } else {
1453  if (key._texture_flags & ShaderKey::TF_map_glow) {
1454  text << "\t result = saturate(2 * (tex" << map_index_glow << ".a - 0.5));\n";
1455  } else {
1456  text << "\t result = float4(0,0,0,0);\n";
1457  }
1458  }
1459  if (key._have_separate_ambient) {
1460  if (key._material_flags & Material::F_ambient) {
1461  text << "\t result += tot_ambient * attr_material[0];\n";
1462  } else if (key._color_type == ColorAttrib::T_vertex) {
1463  text << "\t result += tot_ambient * l_color;\n";
1464  } else if (key._color_type == ColorAttrib::T_flat) {
1465  text << "\t result += tot_ambient * attr_color;\n";
1466  } else {
1467  text << "\t result += tot_ambient;\n";
1468  }
1469  }
1470  if (key._material_flags & Material::F_diffuse) {
1471  text << "\t result += tot_diffuse * attr_material[1];\n";
1472  } else if (key._color_type == ColorAttrib::T_vertex) {
1473  text << "\t result += tot_diffuse * l_color;\n";
1474  } else if (key._color_type == ColorAttrib::T_flat) {
1475  text << "\t result += tot_diffuse * attr_color;\n";
1476  } else {
1477  text << "\t result += tot_diffuse;\n";
1478  }
1479  if (key._light_ramp == nullptr ||
1480  key._light_ramp->get_mode() == LightRampAttrib::LRT_default) {
1481  text << "\t result = saturate(result);\n";
1482  }
1483  text << "\t // End view-space light calculations\n";
1484 
1485  // Combine in alpha, which bypasses lighting calculations. Use of lerp
1486  // here is a workaround for a radeon driver bug.
1487  if (key._calc_primary_alpha) {
1488  if (key._material_flags & Material::F_diffuse) {
1489  text << "\t result.a = attr_material[1].w;\n";
1490  } else if (key._color_type == ColorAttrib::T_vertex) {
1491  text << "\t result.a = l_color.a;\n";
1492  } else if (key._color_type == ColorAttrib::T_flat) {
1493  text << "\t result.a = attr_color.a;\n";
1494  } else {
1495  text << "\t result.a = 1;\n";
1496  }
1497  }
1498  } else {
1499  if (key._color_type == ColorAttrib::T_vertex) {
1500  text << "\t result = l_color;\n";
1501  } else if (key._color_type == ColorAttrib::T_flat) {
1502  text << "\t result = attr_color;\n";
1503  } else {
1504  text << "\t result = float4(1, 1, 1, 1);\n";
1505  }
1506  }
1507 
1508  // Apply the color scale.
1509  text << "\t result *= attr_colorscale;\n";
1510 
1511  // Store these if any stages will use it.
1512  if (key._texture_flags & ShaderKey::TF_uses_primary_color) {
1513  text << "\t float4 primary_color = result;\n";
1514  }
1515  if (key._texture_flags & ShaderKey::TF_uses_last_saved_result) {
1516  text << "\t float4 last_saved_result = result;\n";
1517  }
1518 
1519  // Now loop through the textures to compose our magic blending formulas.
1520  for (size_t i = 0; i < key._textures.size(); ++i) {
1521  const ShaderKey::TextureInfo &tex = key._textures[i];
1522  TextureStage::CombineMode combine_rgb, combine_alpha;
1523 
1524  switch (tex._mode) {
1525  case TextureStage::M_modulate:
1526  if ((tex._flags & ShaderKey::TF_has_rgb) != 0 &&
1527  (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1528  text << "\t result.rgba *= tex" << i << ".rgba;\n";
1529  } else if (tex._flags & ShaderKey::TF_has_alpha) {
1530  text << "\t result.a *= tex" << i << ".a;\n";
1531  } else if (tex._flags & ShaderKey::TF_has_rgb) {
1532  text << "\t result.rgb *= tex" << i << ".rgb;\n";
1533  }
1534  break;
1535  case TextureStage::M_modulate_glow:
1536  case TextureStage::M_modulate_gloss:
1537  // in the case of glow or spec we currently see the specularity evenly
1538  // across the surface even if transparency or masking is present not
1539  // sure if this is desired behavior or not. *MOST* would construct a
1540  // spec map based off of what isisn't seen based on the masktransparency
1541  // this may have to be left alone for now agartner
1542  text << "\t result.rgb *= tex" << i << ";\n";
1543  break;
1544  case TextureStage::M_decal:
1545  text << "\t result.rgb = lerp(result, tex" << i << ", tex" << i << ".a).rgb;\n";
1546  break;
1547  case TextureStage::M_blend:
1548  text << "\t result.rgb = lerp(result.rgb, texcolor_" << i << ".rgb, tex" << i << ".rgb);\n";
1549  if (key._calc_primary_alpha) {
1550  text << "\t result.a *= tex" << i << ".a;\n";
1551  }
1552  break;
1553  case TextureStage::M_replace:
1554  text << "\t result = tex" << i << ";\n";
1555  break;
1556  case TextureStage::M_add:
1557  text << "\t result.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_combine:
1563  combine_rgb = (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_RGB_MODE_MASK) >> ShaderKey::TF_COMBINE_RGB_MODE_SHIFT);
1564  combine_alpha = (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_ALPHA_MODE_MASK) >> ShaderKey::TF_COMBINE_ALPHA_MODE_SHIFT);
1565  if (combine_rgb == TextureStage::CM_dot3_rgba) {
1566  text << "\t result = ";
1567  text << combine_mode_as_string(tex, combine_rgb, false, i);
1568  text << ";\n";
1569  } else {
1570  text << "\t result.rgb = ";
1571  text << combine_mode_as_string(tex, combine_rgb, false, i);
1572  text << ";\n\t result.a = ";
1573  text << combine_mode_as_string(tex, combine_alpha, true, i);
1574  text << ";\n";
1575  }
1576  if (tex._flags & ShaderKey::TF_rgb_scale_2) {
1577  text << "\t result.rgb *= 2;\n";
1578  }
1579  if (tex._flags & ShaderKey::TF_rgb_scale_4) {
1580  text << "\t result.rgb *= 4;\n";
1581  }
1582  if (tex._flags & ShaderKey::TF_alpha_scale_2) {
1583  text << "\t result.a *= 2;\n";
1584  }
1585  if (tex._flags & ShaderKey::TF_alpha_scale_4) {
1586  text << "\t result.a *= 4;\n";
1587  }
1588  break;
1589  case TextureStage::M_blend_color_scale:
1590  text << "\t result.rgb = lerp(result.rgb, texcolor_" << i << ".rgb * attr_colorscale.rgb, tex" << i << ".rgb);\n";
1591  if (key._calc_primary_alpha) {
1592  text << "\t result.a *= texcolor_" << i << ".a * attr_colorscale.a;\n";
1593  }
1594  break;
1595  default:
1596  break;
1597  }
1598  if (tex._flags & ShaderKey::TF_saved_result) {
1599  text << "\t last_saved_result = result;\n";
1600  }
1601  }
1602 
1603  if (key._alpha_test_mode != RenderAttrib::M_none) {
1604  text << "\t // Shader includes alpha test:\n";
1605  double ref = key._alpha_test_ref;
1606  switch (key._alpha_test_mode) {
1607  case RenderAttrib::M_never:
1608  text << "\t discard;\n";
1609  break;
1610  case RenderAttrib::M_less:
1611  text << "\t if (result.a >= " << ref << ") discard;\n";
1612  break;
1613  case RenderAttrib::M_equal:
1614  text << "\t if (result.a != " << ref << ") discard;\n";
1615  break;
1616  case RenderAttrib::M_less_equal:
1617  text << "\t if (result.a > " << ref << ") discard;\n";
1618  break;
1619  case RenderAttrib::M_greater:
1620  text << "\t if (result.a <= " << ref << ") discard;\n";
1621  break;
1622  case RenderAttrib::M_not_equal:
1623  text << "\t if (result.a == " << ref << ") discard;\n";
1624  break;
1625  case RenderAttrib::M_greater_equal:
1626  text << "\t if (result.a < " << ref << ") discard;\n";
1627  break;
1628  case RenderAttrib::M_none:
1629  case RenderAttrib::M_always:
1630  break;
1631  }
1632  }
1633 
1634  if (key._outputs & AuxBitplaneAttrib::ABO_glow) {
1635  if (key._texture_flags & ShaderKey::TF_map_glow) {
1636  text << "\t result.a = tex" << map_index_glow << ".a;\n";
1637  } else {
1638  text << "\t result.a = 0.5;\n";
1639  }
1640  }
1641  if (key._outputs & AuxBitplaneAttrib::ABO_aux_glow) {
1642  if (key._texture_flags & ShaderKey::TF_map_glow) {
1643  text << "\t o_aux.a = tex" << map_index_glow << ".a;\n";
1644  } else {
1645  text << "\t o_aux.a = 0.5;\n";
1646  }
1647  }
1648 
1649  if (have_specular) {
1650  if (key._material_flags & Material::F_specular) {
1651  text << "\t tot_specular *= attr_material[3];\n";
1652  }
1653  if (key._texture_flags & ShaderKey::TF_map_gloss) {
1654  text << "\t tot_specular *= tex" << map_index_gloss << ".a;\n";
1655  }
1656  text << "\t result.rgb = result.rgb + tot_specular.rgb;\n";
1657  }
1658  if (key._light_ramp != nullptr) {
1659  switch (key._light_ramp->get_mode()) {
1660  case LightRampAttrib::LRT_hdr0:
1661  text << "\t result.rgb = (result*result*result + result*result + result) / (result*result*result + result*result + result + 1);\n";
1662  break;
1663  case LightRampAttrib::LRT_hdr1:
1664  text << "\t result.rgb = (result*result + result) / (result*result + result + 1);\n";
1665  break;
1666  case LightRampAttrib::LRT_hdr2:
1667  text << "\t result.rgb = result / (result + 1);\n";
1668  break;
1669  default: break;
1670  }
1671  }
1672 
1673  // Apply fog.
1674  if (key._fog_mode != 0) {
1675  Fog::Mode fog_mode = (Fog::Mode)(key._fog_mode - 1);
1676  switch (fog_mode) {
1677  case Fog::M_linear:
1678  text << "\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate((attr_fog.z - l_hpos.z) * attr_fog.w));\n";
1679  break;
1680  case Fog::M_exponential: // 1.442695f = 1 / log(2)
1681  text << "\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate(exp2(attr_fog.x * l_hpos.z * -1.442695f)));\n";
1682  break;
1683  case Fog::M_exponential_squared:
1684  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";
1685  break;
1686  }
1687  }
1688 
1689  // The multiply is a workaround for a radeon driver bug. It's annoying as
1690  // heck, since it produces an extra instruction.
1691  text << "\t o_color = result * 1.000001;\n";
1692  if (key._alpha_test_mode != RenderAttrib::M_none) {
1693  text << "\t // Shader subsumes normal alpha test.\n";
1694  }
1695  if (key._disable_alpha_write) {
1696  text << "\t // Shader disables alpha write.\n";
1697  }
1698  text << "}\n";
1699 
1700  if (pgraphnodes_cat.is_spam()) {
1701  pgraphnodes_cat.spam() << "Generated shader:\n"
1702  << text.str() << "\n";
1703  }
1704 
1705  // Insert the shader into the shader attrib.
1706  PT(Shader) shader = Shader::make(text.str(), Shader::SL_Cg);
1707  nassertr(shader != nullptr, nullptr);
1708 
1709  CPT(RenderAttrib) shattr = ShaderAttrib::make(shader);
1710  if (key._alpha_test_mode != RenderAttrib::M_none) {
1711  shattr = DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_subsume_alpha_test, true);
1712  }
1713  if (key._disable_alpha_write) {
1714  shattr = DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_disable_alpha_write, true);
1715  }
1716 
1717  reset_register_allocator();
1718 
1719  CPT(ShaderAttrib) attr = DCAST(ShaderAttrib, shattr);
1720  _generated_shaders[key] = attr;
1721  return attr;
1722 }
1723 
1724 /**
1725  * This 'synthesizes' a combine mode into a string.
1726  */
1727 string ShaderGenerator::
1728 combine_mode_as_string(const ShaderKey::TextureInfo &info, TextureStage::CombineMode c_mode, bool alpha, short texindex) {
1729  std::ostringstream text;
1730  switch (c_mode) {
1731  case TextureStage::CM_modulate:
1732  text << combine_source_as_string(info, 0, alpha, texindex);
1733  text << " * ";
1734  text << combine_source_as_string(info, 1, alpha, texindex);
1735  break;
1736  case TextureStage::CM_add:
1737  text << combine_source_as_string(info, 0, alpha, texindex);
1738  text << " + ";
1739  text << combine_source_as_string(info, 1, alpha, texindex);
1740  break;
1741  case TextureStage::CM_add_signed:
1742  text << combine_source_as_string(info, 0, alpha, texindex);
1743  text << " + ";
1744  text << combine_source_as_string(info, 1, alpha, texindex);
1745  if (alpha) {
1746  text << " - 0.5";
1747  } else {
1748  text << " - float3(0.5, 0.5, 0.5)";
1749  }
1750  break;
1751  case TextureStage::CM_interpolate:
1752  text << "lerp(";
1753  text << combine_source_as_string(info, 1, alpha, texindex);
1754  text << ", ";
1755  text << combine_source_as_string(info, 0, alpha, texindex);
1756  text << ", ";
1757  text << combine_source_as_string(info, 2, alpha, texindex);
1758  text << ")";
1759  break;
1760  case TextureStage::CM_subtract:
1761  text << combine_source_as_string(info, 0, alpha, texindex);
1762  text << " - ";
1763  text << combine_source_as_string(info, 1, alpha, texindex);
1764  break;
1765  case TextureStage::CM_dot3_rgb:
1766  case TextureStage::CM_dot3_rgba:
1767  text << "4 * dot(";
1768  text << combine_source_as_string(info, 0, alpha, texindex);
1769  text << " - float3(0.5), ";
1770  text << combine_source_as_string(info, 1, alpha, texindex);
1771  text << " - float3(0.5))";
1772  break;
1773  case TextureStage::CM_replace:
1774  default: // Not sure if this is correct as default value.
1775  text << combine_source_as_string(info, 0, alpha, texindex);
1776  break;
1777  }
1778  return text.str();
1779 }
1780 
1781 /**
1782  * This 'synthesizes' a combine source into a string.
1783  */
1784 string ShaderGenerator::
1785 combine_source_as_string(const ShaderKey::TextureInfo &info, short num, bool alpha, short texindex) {
1786  TextureStage::CombineSource c_src;
1787  TextureStage::CombineOperand c_op;
1788  if (!alpha) {
1789  c_src = UNPACK_COMBINE_SRC(info._combine_rgb, num);
1790  c_op = UNPACK_COMBINE_OP(info._combine_rgb, num);
1791  } else {
1792  c_src = UNPACK_COMBINE_SRC(info._combine_alpha, num);
1793  c_op = UNPACK_COMBINE_OP(info._combine_alpha, num);
1794  }
1795  std::ostringstream csource;
1796  if (c_op == TextureStage::CO_one_minus_src_color ||
1797  c_op == TextureStage::CO_one_minus_src_alpha) {
1798  csource << "saturate(1.0f - ";
1799  }
1800  switch (c_src) {
1801  case TextureStage::CS_undefined:
1802  case TextureStage::CS_texture:
1803  csource << "tex" << texindex;
1804  break;
1805  case TextureStage::CS_constant:
1806  csource << "texcolor_" << texindex;
1807  break;
1808  case TextureStage::CS_primary_color:
1809  csource << "primary_color";
1810  break;
1811  case TextureStage::CS_previous:
1812  csource << "result";
1813  break;
1814  case TextureStage::CS_constant_color_scale:
1815  csource << "attr_colorscale";
1816  break;
1817  case TextureStage::CS_last_saved_result:
1818  csource << "last_saved_result";
1819  break;
1820  }
1821  if (c_op == TextureStage::CO_one_minus_src_color ||
1822  c_op == TextureStage::CO_one_minus_src_alpha) {
1823  csource << ")";
1824  }
1825  if (c_op == TextureStage::CO_src_color || c_op == TextureStage::CO_one_minus_src_color) {
1826  csource << ".rgb";
1827  } else {
1828  csource << ".a";
1829  if (!alpha) {
1830  // Dunno if it's legal in the FPP at all, but let's just allow it.
1831  return "float3(" + csource.str() + ")";
1832  }
1833  }
1834  return csource.str();
1835 }
1836 
1837 /**
1838  * Returns 1D, 2D, 3D or CUBE, depending on the given texture type.
1839  */
1840 const char *ShaderGenerator::
1841 texture_type_as_string(Texture::TextureType ttype) {
1842  switch (ttype) {
1843  case Texture::TT_1d_texture:
1844  return "1D";
1845  break;
1846  case Texture::TT_2d_texture:
1847  return "2D";
1848  break;
1849  case Texture::TT_3d_texture:
1850  return "3D";
1851  break;
1852  case Texture::TT_cube_map:
1853  return "CUBE";
1854  break;
1855  case Texture::TT_2d_texture_array:
1856  return "2DARRAY";
1857  break;
1858  default:
1859  pgraphnodes_cat.error() << "Unsupported texture type!\n";
1860  return "2D";
1861  }
1862 }
1863 
1864 /**
1865  * Initializes the ShaderKey to the empty state.
1866  */
1867 ShaderGenerator::ShaderKey::
1868 ShaderKey() :
1869  _color_type(ColorAttrib::T_vertex),
1870  _material_flags(0),
1871  _texture_flags(0),
1872  _lighting(false),
1873  _have_separate_ambient(false),
1874  _fog_mode(0),
1875  _outputs(0),
1876  _calc_primary_alpha(false),
1877  _disable_alpha_write(false),
1878  _alpha_test_mode(RenderAttrib::M_none),
1879  _alpha_test_ref(0.0),
1880  _num_clip_planes(0),
1881  _light_ramp(nullptr) {
1882 }
1883 
1884 /**
1885  * Returns true if this ShaderKey sorts less than the other one. This is an
1886  * arbitrary, but consistent ordering.
1887  */
1888 bool ShaderGenerator::ShaderKey::
1889 operator < (const ShaderKey &other) const {
1890  if (_anim_spec != other._anim_spec) {
1891  return _anim_spec < other._anim_spec;
1892  }
1893  if (_color_type != other._color_type) {
1894  return _color_type < other._color_type;
1895  }
1896  if (_material_flags != other._material_flags) {
1897  return _material_flags < other._material_flags;
1898  }
1899  if (_texture_flags != other._texture_flags) {
1900  return _texture_flags < other._texture_flags;
1901  }
1902  if (_textures.size() != other._textures.size()) {
1903  return _textures.size() < other._textures.size();
1904  }
1905  for (size_t i = 0; i < _textures.size(); ++i) {
1906  const ShaderKey::TextureInfo &tex = _textures[i];
1907  const ShaderKey::TextureInfo &other_tex = other._textures[i];
1908  if (tex._texcoord_name != other_tex._texcoord_name) {
1909  return tex._texcoord_name < other_tex._texcoord_name;
1910  }
1911  if (tex._type != other_tex._type) {
1912  return tex._type < other_tex._type;
1913  }
1914  if (tex._mode != other_tex._mode) {
1915  return tex._mode < other_tex._mode;
1916  }
1917  if (tex._gen_mode != other_tex._gen_mode) {
1918  return tex._gen_mode < other_tex._gen_mode;
1919  }
1920  if (tex._flags != other_tex._flags) {
1921  return tex._flags < other_tex._flags;
1922  }
1923  if (tex._combine_rgb != other_tex._combine_rgb) {
1924  return tex._combine_rgb < other_tex._combine_rgb;
1925  }
1926  if (tex._combine_alpha != other_tex._combine_alpha) {
1927  return tex._combine_alpha < other_tex._combine_alpha;
1928  }
1929  }
1930  if (_lights.size() != other._lights.size()) {
1931  return _lights.size() < other._lights.size();
1932  }
1933  for (size_t i = 0; i < _lights.size(); ++i) {
1934  const ShaderKey::LightInfo &light = _lights[i];
1935  const ShaderKey::LightInfo &other_light = other._lights[i];
1936  if (light._type != other_light._type) {
1937  return light._type < other_light._type;
1938  }
1939  if (light._flags != other_light._flags) {
1940  return light._flags < other_light._flags;
1941  }
1942  }
1943  if (_lighting != other._lighting) {
1944  return _lighting < other._lighting;
1945  }
1946  if (_have_separate_ambient != other._have_separate_ambient) {
1947  return _have_separate_ambient < other._have_separate_ambient;
1948  }
1949  if (_fog_mode != other._fog_mode) {
1950  return _fog_mode < other._fog_mode;
1951  }
1952  if (_outputs != other._outputs) {
1953  return _outputs < other._outputs;
1954  }
1955  if (_calc_primary_alpha != other._calc_primary_alpha) {
1956  return _calc_primary_alpha < other._calc_primary_alpha;
1957  }
1958  if (_disable_alpha_write != other._disable_alpha_write) {
1959  return _disable_alpha_write < other._disable_alpha_write;
1960  }
1961  if (_alpha_test_mode != other._alpha_test_mode) {
1962  return _alpha_test_mode < other._alpha_test_mode;
1963  }
1964  if (_alpha_test_ref != other._alpha_test_ref) {
1965  return _alpha_test_ref < other._alpha_test_ref;
1966  }
1967  if (_num_clip_planes != other._num_clip_planes) {
1968  return _num_clip_planes < other._num_clip_planes;
1969  }
1970  return _light_ramp < other._light_ramp;
1971 }
1972 
1973 /**
1974  * Returns true if this ShaderKey is equal to the other one.
1975  */
1976 bool ShaderGenerator::ShaderKey::
1977 operator == (const ShaderKey &other) const {
1978  if (_anim_spec != other._anim_spec) {
1979  return false;
1980  }
1981  if (_color_type != other._color_type) {
1982  return false;
1983  }
1984  if (_material_flags != other._material_flags) {
1985  return false;
1986  }
1987  if (_texture_flags != other._texture_flags) {
1988  return false;
1989  }
1990  if (_textures.size() != other._textures.size()) {
1991  return false;
1992  }
1993  for (size_t i = 0; i < _textures.size(); ++i) {
1994  const ShaderKey::TextureInfo &tex = _textures[i];
1995  const ShaderKey::TextureInfo &other_tex = other._textures[i];
1996  if (tex._texcoord_name != other_tex._texcoord_name ||
1997  tex._type != other_tex._type ||
1998  tex._mode != other_tex._mode ||
1999  tex._gen_mode != other_tex._gen_mode ||
2000  tex._flags != other_tex._flags ||
2001  tex._combine_rgb != other_tex._combine_rgb ||
2002  tex._combine_alpha != other_tex._combine_alpha) {
2003  return false;
2004  }
2005  }
2006  if (_lights.size() != other._lights.size()) {
2007  return false;
2008  }
2009  for (size_t i = 0; i < _lights.size(); ++i) {
2010  const ShaderKey::LightInfo &light = _lights[i];
2011  const ShaderKey::LightInfo &other_light = other._lights[i];
2012  if (light._type != other_light._type ||
2013  light._flags != other_light._flags) {
2014  return false;
2015  }
2016  }
2017  return _lighting == other._lighting
2018  && _have_separate_ambient == other._have_separate_ambient
2019  && _fog_mode == other._fog_mode
2020  && _outputs == other._outputs
2021  && _calc_primary_alpha == other._calc_primary_alpha
2022  && _disable_alpha_write == other._disable_alpha_write
2023  && _alpha_test_mode == other._alpha_test_mode
2024  && _alpha_test_ref == other._alpha_test_ref
2025  && _num_clip_planes == other._num_clip_planes
2026  && _light_ramp == other._light_ramp;
2027 }
2028 
2029 #endif // HAVE_CG
lightLensNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
clipPlaneAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
shaderGenerator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
lvector4.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
rescaleNormalAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LightLensNode::mark_used_by_auto_shader
void mark_used_by_auto_shader() const
Marks this light as having been used by the auto shader.
Definition: lightLensNode.I:78
colorBlendAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ClipPlaneAttrib
This functions similarly to a LightAttrib.
Definition: clipPlaneAttrib.h:31
Shader
Definition: shader.h:49
pvector
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
TextureStage::get_alpha_scale
get_alpha_scale
See set_alpha_scale().
Definition: textureStage.h:200
AuxBitplaneAttrib
Modern frame buffers can have 'aux' bitplanes, which are additional bitplanes above and beyond the st...
Definition: auxBitplaneAttrib.h:49
PandaNode::is_ambient_light
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
TextureStage::get_saved_result
get_saved_result
Returns the current setting of the saved_result flag.
Definition: textureStage.h:201
ClipPlaneAttrib::get_num_on_planes
get_num_on_planes
Returns the number of planes that are enabled by the attribute.
Definition: clipPlaneAttrib.h:74
Texture::get_format
get_format
Returns the format of the texture, which represents both the semantic meaning of the texels and,...
Definition: texture.h:362
LightReMutexHolder
Similar to MutexHolder, but for a light reentrant mutex.
Definition: lightReMutexHolder.h:25
pmap
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
TransparencyAttrib
This controls the enabling of transparency.
Definition: transparencyAttrib.h:31
ShaderAttrib::auto_shader
bool auto_shader() const
If true, then this ShaderAttrib does not contain an explicit shader - instead, it requests the automa...
Definition: shaderAttrib.I:71
TextureAttrib::get_on_texture
get_on_texture
Returns the texture associated with the indicated stage, or NULL if no texture is associated.
Definition: textureAttrib.h:69
Material
Defines the way an object appears in the presence of lighting.
Definition: material.h:43
pStatTimer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
colorAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
RenderAttrib
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
SimpleHashMap::get_key
const Key & get_key(size_t n) const
Returns the key in the nth entry of the table.
Definition: simpleHashMap.I:375
TextureStage::get_combine_alpha_operand2
CombineOperand get_combine_alpha_operand2() const
Get operand2 of combine_alpha_mode.
Definition: textureStage.I:591
ShaderAttrib
Definition: shaderAttrib.h:39
TextureStage::uses_color
bool uses_color() const
Returns true if the TextureStage makes use of whatever color is specified in set_color(),...
Definition: textureStage.I:609
InternalName
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
FogAttrib
Applies a Fog to the geometry at and below this node.
Definition: fogAttrib.h:25
FogAttrib::is_off
bool is_off() const
Returns true if the FogAttrib is an 'off' FogAttrib, indicating that it should disable fog.
Definition: fogAttrib.I:26
TextureStage::get_combine_rgb_source2
CombineSource get_combine_rgb_source2() const
Get source2 of combine_rgb_mode.
Definition: textureStage.I:445
Texture
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
TextureStage::uses_primary_color
bool uses_primary_color() const
Returns true if the TextureStage makes use of the CS_primary_color combine source.
Definition: textureStage.I:618
Texture::has_alpha
static bool has_alpha(Format format)
Returns true if the indicated format includes alpha, false otherwise.
Definition: texture.cxx:2573
TextureStage::get_combine_alpha_source1
CombineSource get_combine_alpha_source1() const
Get source1 of combine_alpha_mode.
Definition: textureStage.I:567
TextureStage::get_combine_rgb_operand0
CombineOperand get_combine_rgb_operand0() const
Get operand0 of combine_rgb_mode.
Definition: textureStage.I:421
RenderState
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
config_pgraphnodes.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PStatTimer
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
renderState.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
materialAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
texGenAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LightLensNode::has_specular_color
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
GeomVertexAnimationSpec
This object describes how the vertex animation, if any, represented in a GeomVertexData is encoded.
Definition: geomVertexAnimationSpec.h:38
fogAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
colorScaleAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
sphereLight.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
auxBitplaneAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LightRampAttrib
A Light Ramp is any unary operator that takes a rendered pixel as input, and adjusts the brightness o...
Definition: lightRampAttrib.h:28
PStatCollector
A lightweight class that represents a single element that may be timed and/or counted via stats.
Definition: pStatCollector.h:43
shaderAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
transparencyAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
MaterialAttrib
Indicates which, if any, material should be applied to geometry.
Definition: materialAttrib.h:27
AlphaTestAttrib
Enables or disables writing of pixel to framebuffer based on its alpha value relative to a reference ...
Definition: alphaTestAttrib.h:26
TransparencyAttrib::get_mode
get_mode
Returns the transparency mode.
Definition: transparencyAttrib.h:54
ambientLight.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AlphaTestAttrib::get_reference_alpha
get_reference_alpha
Returns the alpha reference value.
Definition: alphaTestAttrib.h:40
TextureAttrib::get_num_on_stages
get_num_on_stages
Returns the number of stages that are turned on by the attribute.
Definition: textureAttrib.h:55
ColorAttrib::get_color_type
get_color_type
Returns the type of color specified by this ColorAttrib.
Definition: colorAttrib.h:46
ReferenceCount::ref
void ref() const
Explicitly increments the reference count.
Definition: referenceCount.I:151
TextureStage::uses_last_saved_result
bool uses_last_saved_result() const
Returns true if the TextureStage makes use of the CS_primary_color combine source.
Definition: textureStage.I:627
TextureStage::get_combine_rgb_operand2
CombineOperand get_combine_rgb_operand2() const
Get operand2 of combine_rgb_mode.
Definition: textureStage.I:453
MaterialAttrib::get_material
get_material
If the MaterialAttrib is not an 'off' MaterialAttrib, returns the material that is associated.
Definition: materialAttrib.h:40
lightRampAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
TextureStage::get_combine_alpha_operand0
CombineOperand get_combine_alpha_operand0() const
Get operand0 of combine_alpha_mode.
Definition: textureStage.I:559
AuxBitplaneAttrib::get_outputs
get_outputs
Returns the AuxBitplaneAttrib output bits.
Definition: auxBitplaneAttrib.h:67
texMatrixAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
textureAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
texture.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureAttrib::get_on_stage
get_on_stage
Returns the nth stage turned on by the attribute, sorted in render order.
Definition: textureAttrib.h:55
TexMatrixAttrib
Applies a transform matrix to UV's before they are rendered.
Definition: texMatrixAttrib.h:30
LightAttrib::get_on_light
get_on_light
Returns the nth light turned on by the attribute, sorted in render order.
Definition: lightAttrib.h:74
TextureStage::get_texcoord_name
get_texcoord_name
See set_texcoord_name.
Definition: textureStage.h:192
LightLensNode
A derivative of Light and of Camera.
Definition: lightLensNode.h:33
TextureStage::get_combine_alpha_mode
CombineMode get_combine_alpha_mode() const
Get combine_alpha_mode.
Definition: textureStage.I:534
TexGenAttrib
Computes texture coordinates for geometry automatically based on vertex position and/or normal.
Definition: texGenAttrib.h:32
TextureStage::get_combine_alpha_source2
CombineSource get_combine_alpha_source2() const
Get source2 of combine_alpha_mode.
Definition: textureStage.I:583
FogAttrib::get_fog
get_fog
If the FogAttrib is not an 'off' FogAttrib, returns the fog that is associated.
Definition: fogAttrib.h:38
GraphicsStateGuardianBase
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Definition: graphicsStateGuardianBase.h:110
TextureStage::get_combine_alpha_operand1
CombineOperand get_combine_alpha_operand1() const
Get operand1 of combine_alpha_mode.
Definition: textureStage.I:575
TextureStage::get_combine_rgb_operand1
CombineOperand get_combine_rgb_operand1() const
Get operand1 of combine_rgb_mode.
Definition: textureStage.I:437
SimpleHashMap::clear
void clear()
Completely empties the table.
Definition: simpleHashMap.I:331
ColorBlendAttrib::get_mode
get_mode
Returns the blending mode for the RGB channels.
Definition: colorBlendAttrib.h:108
pointLight.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
alphaTestAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AlphaTestAttrib::get_mode
get_mode
Returns the alpha write mode.
Definition: alphaTestAttrib.h:41
lightAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
directionalLight.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ColorBlendAttrib
This specifies how colors are blended into the frame buffer, for special effects.
Definition: colorBlendAttrib.h:27
TextureStage::get_combine_rgb_source1
CombineSource get_combine_rgb_source1() const
Get source1 of combine_rgb_mode.
Definition: textureStage.I:429
LightAttrib::get_num_on_lights
get_num_on_lights
Returns the number of lights that are turned on by the attribute.
Definition: lightAttrib.h:74
LightAttrib
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
Definition: lightAttrib.h:30
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
TextureAttrib
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:31
NodePath::node
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
ColorAttrib
Indicates what color should be applied to renderable geometry.
Definition: colorAttrib.h:27
TextureStage
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:35
LightLensNode::is_shadow_caster
is_shadow_caster
Returns whether this light is configured to cast shadows or not.
Definition: lightLensNode.h:52
TextureStage::get_combine_rgb_mode
CombineMode get_combine_rgb_mode() const
Get the combine_rgb_mode.
Definition: textureStage.I:396
TextureStage::get_combine_rgb_source0
CombineSource get_combine_rgb_source0() const
Get source0 of combine_rgb_mode.
Definition: textureStage.I:413
SimpleHashMap::get_num_entries
size_t get_num_entries() const
Returns the number of active entries in the table.
Definition: simpleHashMap.I:445
TextureStage::get_combine_alpha_source0
CombineSource get_combine_alpha_source0() const
Get source0 of combine_alpha_mode.
Definition: textureStage.I:551
TextureStage::get_rgb_scale
get_rgb_scale
See set_rgb_scale().
Definition: textureStage.h:199
spotlight.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypedObject::is_of_type
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
NodePath::is_empty
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188