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  text << "\t float3 tsnormal = normalize((tex" << i << ".xyz * 2) - 1);\n";
1245  is_first = false;
1246  continue;
1247  }
1248  text << "\t tsnormal.z += 1;\n";
1249  text << "\t float3 tmp" << i << " = tex" << i << ".xyz * float3(-2, -2, 2) + float3(1, 1, -1);\n";
1250  text << "\t tsnormal = normalize(tsnormal * dot(tsnormal, tmp" << i << ") - tmp" << i << " * tsnormal.z);\n";
1251  }
1252  }
1253  text << "\t l_eye_normal *= tsnormal.z;\n";
1254  text << "\t l_eye_normal += normalize(l_tangent.xyz) * tsnormal.x;\n";
1255  text << "\t l_eye_normal += normalize(l_binormal.xyz) * tsnormal.y;\n";
1256  text << "\t l_eye_normal = normalize(l_eye_normal);\n";
1257  }
1258  if (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) {
1259  text << "\t // Output the camera-space surface normal\n";
1260  text << "\t o_aux.rgb = (l_eye_normal*0.5) + float3(0.5,0.5,0.5);\n";
1261  }
1262  if (key._lighting) {
1263  text << "\t // Begin view-space light calculations\n";
1264  text << "\t float ldist,lattenv,langle,lshad;\n";
1265  text << "\t float4 lcolor,lspec,lpoint,latten,ldir,leye;\n";
1266  text << "\t float3 lvec,lhalf;\n";
1267  if (key._have_separate_ambient) {
1268  text << "\t float4 tot_ambient = float4(0,0,0,0);\n";
1269  }
1270  text << "\t float4 tot_diffuse = float4(0,0,0,0);\n";
1271  if (have_specular) {
1272  text << "\t float4 tot_specular = float4(0,0,0,0);\n";
1273  if (key._material_flags & Material::F_specular) {
1274  text << "\t float shininess = attr_material[3].w;\n";
1275  } else {
1276  text << "\t float shininess = 50; // no shininess specified, using default\n";
1277  }
1278  }
1279  if (key._have_separate_ambient) {
1280  text << "\t tot_ambient += attr_ambient;\n";
1281  } else {
1282  text << "\t tot_diffuse += attr_ambient;\n";
1283  }
1284  }
1285  for (size_t i = 0; i < key._lights.size(); ++i) {
1286  const ShaderKey::LightInfo &light = key._lights[i];
1287 
1288  if (light._flags & ShaderKey::LF_has_shadows) {
1289  if (lightcoord_fregs[i] == nullptr) {
1290  // We have to do this one in the fragment shader if we ran out of
1291  // varyings.
1292  text << "\t float4 l_lightcoord" << i << " = mul(mat_shadow_" << i << ", float4(l_eye_position.xyz, 1.0f));\n";
1293  }
1294  }
1295 
1296  if (light._type.is_derived_from(DirectionalLight::get_class_type())) {
1297  text << "\t // Directional Light " << i << "\n";
1298  text << "\t lcolor = attr_light" << i << "[0];\n";
1299  if (light._flags & ShaderKey::LF_has_specular_color) {
1300  text << "\t lspec = attr_lspec" << i << ";\n";
1301  } else {
1302  text << "\t lspec = lcolor;\n";
1303  }
1304  text << "\t lvec = attr_light" << i << "[3].xyz;\n";
1305  text << "\t lcolor *= saturate(dot(l_eye_normal, lvec.xyz));\n";
1306  if (light._flags & ShaderKey::LF_has_shadows) {
1307  if (_use_shadow_filter) {
1308  text << "\t lshad = shadow2DProj(shadow_" << i << ", l_lightcoord" << i << ").r;\n";
1309  } else {
1310  text << "\t lshad = tex2Dproj(shadow_" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n";
1311  }
1312  text << "\t lcolor *= lshad;\n";
1313  text << "\t lspec *= lshad;\n";
1314  }
1315  text << "\t tot_diffuse += lcolor;\n";
1316  if (have_specular) {
1317  if (key._material_flags & Material::F_local) {
1318  text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1319  } else {
1320  text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1321  }
1322  text << "\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1323  text << "\t tot_specular += lspec;\n";
1324  }
1325  } else if (light._type.is_derived_from(PointLight::get_class_type())) {
1326  text << "\t // Point Light " << i << "\n";
1327  text << "\t lcolor = attr_light" << i << "[0];\n";
1328  if (light._flags & ShaderKey::LF_has_specular_color) {
1329  text << "\t lspec = attr_lspec" << i << ";\n";
1330  } else {
1331  text << "\t lspec = lcolor;\n";
1332  }
1333  text << "\t latten = attr_light" << i << "[1];\n";
1334  text << "\t lpoint = attr_light" << i << "[3];\n";
1335  text << "\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
1336  text << "\t ldist = length(lvec);\n";
1337  text << "\t lvec /= ldist;\n";
1338  if (light._type.is_derived_from(SphereLight::get_class_type())) {
1339  text << "\t ldist = max(ldist, attr_light" << i << "[2].w);\n";
1340  }
1341  text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1342  text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal, lvec));\n";
1343  if (light._flags & ShaderKey::LF_has_shadows) {
1344  text << "\t ldist = max(abs(l_lightcoord" << i << ".x), max(abs(l_lightcoord" << i << ".y), abs(l_lightcoord" << i << ".z)));\n";
1345  text << "\t ldist = ((latten.w+lpoint.w)/(latten.w-lpoint.w))+((-2*latten.w*lpoint.w)/(ldist * (latten.w-lpoint.w)));\n";
1346  text << "\t lshad = texCUBE(shadow_" << i << ", l_lightcoord" << i << ".xyz).r >= ldist * 0.5 + 0.5;\n";
1347  text << "\t lcolor *= lshad;\n";
1348  text << "\t lspec *= lshad;\n";
1349  }
1350  text << "\t tot_diffuse += lcolor;\n";
1351  if (have_specular) {
1352  if (key._material_flags & Material::F_local) {
1353  text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1354  } else {
1355  text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1356  }
1357  text << "\t lspec *= lattenv;\n";
1358  text << "\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1359  text << "\t tot_specular += lspec;\n";
1360  }
1361  } else if (light._type.is_derived_from(Spotlight::get_class_type())) {
1362  text << "\t // Spot Light " << i << "\n";
1363  text << "\t lcolor = attr_light" << i << "[0];\n";
1364  if (light._flags & ShaderKey::LF_has_specular_color) {
1365  text << "\t lspec = attr_lspec" << i << ";\n";
1366  } else {
1367  text << "\t lspec = lcolor;\n";
1368  }
1369  text << "\t latten = attr_light" << i << "[1];\n";
1370  text << "\t ldir = attr_light" << i << "[2];\n";
1371  text << "\t lpoint = attr_light" << i << "[3];\n";
1372  text << "\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
1373  text << "\t ldist = length(lvec);\n";
1374  text << "\t lvec /= ldist;\n";
1375  text << "\t langle = saturate(dot(ldir.xyz, lvec));\n";
1376  text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1377  text << "\t lattenv *= pow(langle, latten.w);\n";
1378  text << "\t if (langle < ldir.w) lattenv = 0;\n";
1379  text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal, lvec));\n";
1380  if (light._flags & ShaderKey::LF_has_shadows) {
1381  if (_use_shadow_filter) {
1382  text << "\t lshad = shadow2DProj(shadow_" << i << ", l_lightcoord" << i << ").r;\n";
1383  } else {
1384  text << "\t lshad = tex2Dproj(shadow_" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n";
1385  }
1386  text << "\t lcolor *= lshad;\n";
1387  text << "\t lspec *= lshad;\n";
1388  }
1389 
1390  text << "\t tot_diffuse += lcolor;\n";
1391  if (have_specular) {
1392  if (key._material_flags & Material::F_local) {
1393  text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1394  } else {
1395  text << "\t lhalf = normalize(lvec - float3(0,1,0));\n";
1396  }
1397  text << "\t lspec *= lattenv;\n";
1398  text << "\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1399  text << "\t tot_specular += lspec;\n";
1400  }
1401  }
1402  }
1403  if (key._lighting) {
1404  if (key._light_ramp != nullptr) {
1405  switch (key._light_ramp->get_mode()) {
1406  case LightRampAttrib::LRT_single_threshold:
1407  {
1408  PN_stdfloat t = key._light_ramp->get_threshold(0);
1409  PN_stdfloat l0 = key._light_ramp->get_level(0);
1410  text << "\t // Single-threshold light ramp\n";
1411  text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1412  text << "\t float lr_scale = (lr_in < " << t << ") ? 0.0 : (" << l0 << "/lr_in);\n";
1413  text << "\t tot_diffuse = tot_diffuse * lr_scale;\n";
1414  break;
1415  }
1416  case LightRampAttrib::LRT_double_threshold:
1417  {
1418  PN_stdfloat t0 = key._light_ramp->get_threshold(0);
1419  PN_stdfloat t1 = key._light_ramp->get_threshold(1);
1420  PN_stdfloat l0 = key._light_ramp->get_level(0);
1421  PN_stdfloat l1 = key._light_ramp->get_level(1);
1422  text << "\t // Double-threshold light ramp\n";
1423  text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1424  text << "\t float lr_out = 0.0;\n";
1425  text << "\t if (lr_in > " << t0 << ") lr_out=" << l0 << ";\n";
1426  text << "\t if (lr_in > " << t1 << ") lr_out=" << l1 << ";\n";
1427  text << "\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n";
1428  break;
1429  }
1430  default:
1431  break;
1432  }
1433  }
1434  text << "\t // Begin view-space light summation\n";
1435  if (key._material_flags & Material::F_emission) {
1436  if (key._texture_flags & ShaderKey::TF_map_glow) {
1437  text << "\t result = attr_material[2] * saturate(2 * (tex" << map_index_glow << ".a - 0.5));\n";
1438  } else {
1439  text << "\t result = attr_material[2];\n";
1440  }
1441  } else {
1442  if (key._texture_flags & ShaderKey::TF_map_glow) {
1443  text << "\t result = saturate(2 * (tex" << map_index_glow << ".a - 0.5));\n";
1444  } else {
1445  text << "\t result = float4(0,0,0,0);\n";
1446  }
1447  }
1448  if (key._have_separate_ambient) {
1449  if (key._material_flags & Material::F_ambient) {
1450  text << "\t result += tot_ambient * attr_material[0];\n";
1451  } else if (key._color_type == ColorAttrib::T_vertex) {
1452  text << "\t result += tot_ambient * l_color;\n";
1453  } else if (key._color_type == ColorAttrib::T_flat) {
1454  text << "\t result += tot_ambient * attr_color;\n";
1455  } else {
1456  text << "\t result += tot_ambient;\n";
1457  }
1458  }
1459  if (key._material_flags & Material::F_diffuse) {
1460  text << "\t result += tot_diffuse * attr_material[1];\n";
1461  } else if (key._color_type == ColorAttrib::T_vertex) {
1462  text << "\t result += tot_diffuse * l_color;\n";
1463  } else if (key._color_type == ColorAttrib::T_flat) {
1464  text << "\t result += tot_diffuse * attr_color;\n";
1465  } else {
1466  text << "\t result += tot_diffuse;\n";
1467  }
1468  if (key._light_ramp == nullptr ||
1469  key._light_ramp->get_mode() == LightRampAttrib::LRT_default) {
1470  text << "\t result = saturate(result);\n";
1471  }
1472  text << "\t // End view-space light calculations\n";
1473 
1474  // Combine in alpha, which bypasses lighting calculations. Use of lerp
1475  // here is a workaround for a radeon driver bug.
1476  if (key._calc_primary_alpha) {
1477  if (key._color_type == ColorAttrib::T_vertex) {
1478  text << "\t result.a = l_color.a;\n";
1479  } else if (key._color_type == ColorAttrib::T_flat) {
1480  text << "\t result.a = attr_color.a;\n";
1481  } else {
1482  text << "\t result.a = 1;\n";
1483  }
1484  }
1485  } else {
1486  if (key._color_type == ColorAttrib::T_vertex) {
1487  text << "\t result = l_color;\n";
1488  } else if (key._color_type == ColorAttrib::T_flat) {
1489  text << "\t result = attr_color;\n";
1490  } else {
1491  text << "\t result = float4(1, 1, 1, 1);\n";
1492  }
1493  }
1494 
1495  // Apply the color scale.
1496  text << "\t result *= attr_colorscale;\n";
1497 
1498  // Store these if any stages will use it.
1499  if (key._texture_flags & ShaderKey::TF_uses_primary_color) {
1500  text << "\t float4 primary_color = result;\n";
1501  }
1502  if (key._texture_flags & ShaderKey::TF_uses_last_saved_result) {
1503  text << "\t float4 last_saved_result = result;\n";
1504  }
1505 
1506  // Now loop through the textures to compose our magic blending formulas.
1507  for (size_t i = 0; i < key._textures.size(); ++i) {
1508  const ShaderKey::TextureInfo &tex = key._textures[i];
1509  TextureStage::CombineMode combine_rgb, combine_alpha;
1510 
1511  switch (tex._mode) {
1512  case TextureStage::M_modulate:
1513  if ((tex._flags & ShaderKey::TF_has_rgb) != 0 &&
1514  (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1515  text << "\t result.rgba *= tex" << i << ".rgba;\n";
1516  } else if (tex._flags & ShaderKey::TF_has_alpha) {
1517  text << "\t result.a *= tex" << i << ".a;\n";
1518  } else if (tex._flags & ShaderKey::TF_has_rgb) {
1519  text << "\t result.rgb *= tex" << i << ".rgb;\n";
1520  }
1521  break;
1522  case TextureStage::M_modulate_glow:
1523  case TextureStage::M_modulate_gloss:
1524  // in the case of glow or spec we currently see the specularity evenly
1525  // across the surface even if transparency or masking is present not
1526  // sure if this is desired behavior or not. *MOST* would construct a
1527  // spec map based off of what isisn't seen based on the masktransparency
1528  // this may have to be left alone for now agartner
1529  text << "\t result.rgb *= tex" << i << ";\n";
1530  break;
1531  case TextureStage::M_decal:
1532  text << "\t result.rgb = lerp(result, tex" << i << ", tex" << i << ".a).rgb;\n";
1533  break;
1534  case TextureStage::M_blend:
1535  text << "\t result.rgb = lerp(result.rgb, texcolor_" << i << ".rgb, tex" << i << ".rgb);\n";
1536  if (key._calc_primary_alpha) {
1537  text << "\t result.a *= tex" << i << ".a;\n";
1538  }
1539  break;
1540  case TextureStage::M_replace:
1541  text << "\t result = tex" << i << ";\n";
1542  break;
1543  case TextureStage::M_add:
1544  text << "\t result.rgb += tex" << i << ".rgb;\n";
1545  if (key._calc_primary_alpha) {
1546  text << "\t result.a *= tex" << i << ".a;\n";
1547  }
1548  break;
1549  case TextureStage::M_combine:
1550  combine_rgb = (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_RGB_MODE_MASK) >> ShaderKey::TF_COMBINE_RGB_MODE_SHIFT);
1551  combine_alpha = (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_ALPHA_MODE_MASK) >> ShaderKey::TF_COMBINE_ALPHA_MODE_SHIFT);
1552  if (combine_rgb == TextureStage::CM_dot3_rgba) {
1553  text << "\t result = ";
1554  text << combine_mode_as_string(tex, combine_rgb, false, i);
1555  text << ";\n";
1556  } else {
1557  text << "\t result.rgb = ";
1558  text << combine_mode_as_string(tex, combine_rgb, false, i);
1559  text << ";\n\t result.a = ";
1560  text << combine_mode_as_string(tex, combine_alpha, true, i);
1561  text << ";\n";
1562  }
1563  if (tex._flags & ShaderKey::TF_rgb_scale_2) {
1564  text << "\t result.rgb *= 2;\n";
1565  }
1566  if (tex._flags & ShaderKey::TF_rgb_scale_4) {
1567  text << "\t result.rgb *= 4;\n";
1568  }
1569  if (tex._flags & ShaderKey::TF_alpha_scale_2) {
1570  text << "\t result.a *= 2;\n";
1571  }
1572  if (tex._flags & ShaderKey::TF_alpha_scale_4) {
1573  text << "\t result.a *= 4;\n";
1574  }
1575  break;
1576  case TextureStage::M_blend_color_scale:
1577  text << "\t result.rgb = lerp(result.rgb, texcolor_" << i << ".rgb * attr_colorscale.rgb, tex" << i << ".rgb);\n";
1578  if (key._calc_primary_alpha) {
1579  text << "\t result.a *= texcolor_" << i << ".a * attr_colorscale.a;\n";
1580  }
1581  break;
1582  default:
1583  break;
1584  }
1585  if (tex._flags & ShaderKey::TF_saved_result) {
1586  text << "\t last_saved_result = result;\n";
1587  }
1588  }
1589 
1590  if (key._alpha_test_mode != RenderAttrib::M_none) {
1591  text << "\t // Shader includes alpha test:\n";
1592  double ref = key._alpha_test_ref;
1593  switch (key._alpha_test_mode) {
1594  case RenderAttrib::M_never:
1595  text << "\t discard;\n";
1596  break;
1597  case RenderAttrib::M_less:
1598  text << "\t if (result.a >= " << ref << ") discard;\n";
1599  break;
1600  case RenderAttrib::M_equal:
1601  text << "\t if (result.a != " << ref << ") discard;\n";
1602  break;
1603  case RenderAttrib::M_less_equal:
1604  text << "\t if (result.a > " << ref << ") discard;\n";
1605  break;
1606  case RenderAttrib::M_greater:
1607  text << "\t if (result.a <= " << ref << ") discard;\n";
1608  break;
1609  case RenderAttrib::M_not_equal:
1610  text << "\t if (result.a == " << ref << ") discard;\n";
1611  break;
1612  case RenderAttrib::M_greater_equal:
1613  text << "\t if (result.a < " << ref << ") discard;\n";
1614  break;
1615  case RenderAttrib::M_none:
1616  case RenderAttrib::M_always:
1617  break;
1618  }
1619  }
1620 
1621  if (key._outputs & AuxBitplaneAttrib::ABO_glow) {
1622  if (key._texture_flags & ShaderKey::TF_map_glow) {
1623  text << "\t result.a = tex" << map_index_glow << ".a;\n";
1624  } else {
1625  text << "\t result.a = 0.5;\n";
1626  }
1627  }
1628  if (key._outputs & AuxBitplaneAttrib::ABO_aux_glow) {
1629  if (key._texture_flags & ShaderKey::TF_map_glow) {
1630  text << "\t o_aux.a = tex" << map_index_glow << ".a;\n";
1631  } else {
1632  text << "\t o_aux.a = 0.5;\n";
1633  }
1634  }
1635 
1636  if (have_specular) {
1637  if (key._material_flags & Material::F_specular) {
1638  text << "\t tot_specular *= attr_material[3];\n";
1639  }
1640  if (key._texture_flags & ShaderKey::TF_map_gloss) {
1641  text << "\t tot_specular *= tex" << map_index_gloss << ".a;\n";
1642  }
1643  text << "\t result.rgb = result.rgb + tot_specular.rgb;\n";
1644  }
1645  if (key._light_ramp != nullptr) {
1646  switch (key._light_ramp->get_mode()) {
1647  case LightRampAttrib::LRT_hdr0:
1648  text << "\t result.rgb = (result*result*result + result*result + result) / (result*result*result + result*result + result + 1);\n";
1649  break;
1650  case LightRampAttrib::LRT_hdr1:
1651  text << "\t result.rgb = (result*result + result) / (result*result + result + 1);\n";
1652  break;
1653  case LightRampAttrib::LRT_hdr2:
1654  text << "\t result.rgb = result / (result + 1);\n";
1655  break;
1656  default: break;
1657  }
1658  }
1659 
1660  // Apply fog.
1661  if (key._fog_mode != 0) {
1662  Fog::Mode fog_mode = (Fog::Mode)(key._fog_mode - 1);
1663  switch (fog_mode) {
1664  case Fog::M_linear:
1665  text << "\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate((attr_fog.z - l_hpos.z) * attr_fog.w));\n";
1666  break;
1667  case Fog::M_exponential: // 1.442695f = 1 / log(2)
1668  text << "\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate(exp2(attr_fog.x * l_hpos.z * -1.442695f)));\n";
1669  break;
1670  case Fog::M_exponential_squared:
1671  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";
1672  break;
1673  }
1674  }
1675 
1676  // The multiply is a workaround for a radeon driver bug. It's annoying as
1677  // heck, since it produces an extra instruction.
1678  text << "\t o_color = result * 1.000001;\n";
1679  if (key._alpha_test_mode != RenderAttrib::M_none) {
1680  text << "\t // Shader subsumes normal alpha test.\n";
1681  }
1682  if (key._disable_alpha_write) {
1683  text << "\t // Shader disables alpha write.\n";
1684  }
1685  text << "}\n";
1686 
1687  if (pgraphnodes_cat.is_spam()) {
1688  pgraphnodes_cat.spam() << "Generated shader:\n"
1689  << text.str() << "\n";
1690  }
1691 
1692  // Insert the shader into the shader attrib.
1693  PT(Shader) shader = Shader::make(text.str(), Shader::SL_Cg);
1694  nassertr(shader != nullptr, nullptr);
1695 
1696  CPT(RenderAttrib) shattr = ShaderAttrib::make(shader);
1697  if (key._alpha_test_mode != RenderAttrib::M_none) {
1698  shattr = DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_subsume_alpha_test, true);
1699  }
1700  if (key._disable_alpha_write) {
1701  shattr = DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_disable_alpha_write, true);
1702  }
1703 
1704  reset_register_allocator();
1705 
1706  CPT(ShaderAttrib) attr = DCAST(ShaderAttrib, shattr);
1707  _generated_shaders[key] = attr;
1708  return attr;
1709 }
1710 
1711 /**
1712  * This 'synthesizes' a combine mode into a string.
1713  */
1714 string ShaderGenerator::
1715 combine_mode_as_string(const ShaderKey::TextureInfo &info, TextureStage::CombineMode c_mode, bool alpha, short texindex) {
1716  std::ostringstream text;
1717  switch (c_mode) {
1718  case TextureStage::CM_modulate:
1719  text << combine_source_as_string(info, 0, alpha, texindex);
1720  text << " * ";
1721  text << combine_source_as_string(info, 1, alpha, texindex);
1722  break;
1723  case TextureStage::CM_add:
1724  text << combine_source_as_string(info, 0, alpha, texindex);
1725  text << " + ";
1726  text << combine_source_as_string(info, 1, alpha, texindex);
1727  break;
1728  case TextureStage::CM_add_signed:
1729  text << combine_source_as_string(info, 0, alpha, texindex);
1730  text << " + ";
1731  text << combine_source_as_string(info, 1, alpha, texindex);
1732  if (alpha) {
1733  text << " - 0.5";
1734  } else {
1735  text << " - float3(0.5, 0.5, 0.5)";
1736  }
1737  break;
1738  case TextureStage::CM_interpolate:
1739  text << "lerp(";
1740  text << combine_source_as_string(info, 1, alpha, texindex);
1741  text << ", ";
1742  text << combine_source_as_string(info, 0, alpha, texindex);
1743  text << ", ";
1744  text << combine_source_as_string(info, 2, alpha, texindex);
1745  text << ")";
1746  break;
1747  case TextureStage::CM_subtract:
1748  text << combine_source_as_string(info, 0, alpha, texindex);
1749  text << " - ";
1750  text << combine_source_as_string(info, 1, alpha, texindex);
1751  break;
1752  case TextureStage::CM_dot3_rgb:
1753  case TextureStage::CM_dot3_rgba:
1754  text << "4 * dot(";
1755  text << combine_source_as_string(info, 0, alpha, texindex);
1756  text << " - float3(0.5), ";
1757  text << combine_source_as_string(info, 1, alpha, texindex);
1758  text << " - float3(0.5))";
1759  break;
1760  case TextureStage::CM_replace:
1761  default: // Not sure if this is correct as default value.
1762  text << combine_source_as_string(info, 0, alpha, texindex);
1763  break;
1764  }
1765  return text.str();
1766 }
1767 
1768 /**
1769  * This 'synthesizes' a combine source into a string.
1770  */
1771 string ShaderGenerator::
1772 combine_source_as_string(const ShaderKey::TextureInfo &info, short num, bool alpha, short texindex) {
1773  TextureStage::CombineSource c_src;
1774  TextureStage::CombineOperand c_op;
1775  if (!alpha) {
1776  c_src = UNPACK_COMBINE_SRC(info._combine_rgb, num);
1777  c_op = UNPACK_COMBINE_OP(info._combine_rgb, num);
1778  } else {
1779  c_src = UNPACK_COMBINE_SRC(info._combine_alpha, num);
1780  c_op = UNPACK_COMBINE_OP(info._combine_alpha, num);
1781  }
1782  std::ostringstream csource;
1783  if (c_op == TextureStage::CO_one_minus_src_color ||
1784  c_op == TextureStage::CO_one_minus_src_alpha) {
1785  csource << "saturate(1.0f - ";
1786  }
1787  switch (c_src) {
1788  case TextureStage::CS_undefined:
1789  case TextureStage::CS_texture:
1790  csource << "tex" << texindex;
1791  break;
1792  case TextureStage::CS_constant:
1793  csource << "texcolor_" << texindex;
1794  break;
1795  case TextureStage::CS_primary_color:
1796  csource << "primary_color";
1797  break;
1798  case TextureStage::CS_previous:
1799  csource << "result";
1800  break;
1801  case TextureStage::CS_constant_color_scale:
1802  csource << "attr_colorscale";
1803  break;
1804  case TextureStage::CS_last_saved_result:
1805  csource << "last_saved_result";
1806  break;
1807  }
1808  if (c_op == TextureStage::CO_one_minus_src_color ||
1809  c_op == TextureStage::CO_one_minus_src_alpha) {
1810  csource << ")";
1811  }
1812  if (c_op == TextureStage::CO_src_color || c_op == TextureStage::CO_one_minus_src_color) {
1813  csource << ".rgb";
1814  } else {
1815  csource << ".a";
1816  if (!alpha) {
1817  // Dunno if it's legal in the FPP at all, but let's just allow it.
1818  return "float3(" + csource.str() + ")";
1819  }
1820  }
1821  return csource.str();
1822 }
1823 
1824 /**
1825  * Returns 1D, 2D, 3D or CUBE, depending on the given texture type.
1826  */
1827 const char *ShaderGenerator::
1828 texture_type_as_string(Texture::TextureType ttype) {
1829  switch (ttype) {
1830  case Texture::TT_1d_texture:
1831  return "1D";
1832  break;
1833  case Texture::TT_2d_texture:
1834  return "2D";
1835  break;
1836  case Texture::TT_3d_texture:
1837  return "3D";
1838  break;
1839  case Texture::TT_cube_map:
1840  return "CUBE";
1841  break;
1842  case Texture::TT_2d_texture_array:
1843  return "2DARRAY";
1844  break;
1845  default:
1846  pgraphnodes_cat.error() << "Unsupported texture type!\n";
1847  return "2D";
1848  }
1849 }
1850 
1851 /**
1852  * Initializes the ShaderKey to the empty state.
1853  */
1854 ShaderGenerator::ShaderKey::
1855 ShaderKey() :
1856  _color_type(ColorAttrib::T_vertex),
1857  _material_flags(0),
1858  _texture_flags(0),
1859  _lighting(false),
1860  _have_separate_ambient(false),
1861  _fog_mode(0),
1862  _outputs(0),
1863  _calc_primary_alpha(false),
1864  _disable_alpha_write(false),
1865  _alpha_test_mode(RenderAttrib::M_none),
1866  _alpha_test_ref(0.0),
1867  _num_clip_planes(0),
1868  _light_ramp(nullptr) {
1869 }
1870 
1871 /**
1872  * Returns true if this ShaderKey sorts less than the other one. This is an
1873  * arbitrary, but consistent ordering.
1874  */
1875 bool ShaderGenerator::ShaderKey::
1876 operator < (const ShaderKey &other) const {
1877  if (_anim_spec != other._anim_spec) {
1878  return _anim_spec < other._anim_spec;
1879  }
1880  if (_color_type != other._color_type) {
1881  return _color_type < other._color_type;
1882  }
1883  if (_material_flags != other._material_flags) {
1884  return _material_flags < other._material_flags;
1885  }
1886  if (_texture_flags != other._texture_flags) {
1887  return _texture_flags < other._texture_flags;
1888  }
1889  if (_textures.size() != other._textures.size()) {
1890  return _textures.size() < other._textures.size();
1891  }
1892  for (size_t i = 0; i < _textures.size(); ++i) {
1893  const ShaderKey::TextureInfo &tex = _textures[i];
1894  const ShaderKey::TextureInfo &other_tex = other._textures[i];
1895  if (tex._texcoord_name != other_tex._texcoord_name) {
1896  return tex._texcoord_name < other_tex._texcoord_name;
1897  }
1898  if (tex._type != other_tex._type) {
1899  return tex._type < other_tex._type;
1900  }
1901  if (tex._mode != other_tex._mode) {
1902  return tex._mode < other_tex._mode;
1903  }
1904  if (tex._gen_mode != other_tex._gen_mode) {
1905  return tex._gen_mode < other_tex._gen_mode;
1906  }
1907  if (tex._flags != other_tex._flags) {
1908  return tex._flags < other_tex._flags;
1909  }
1910  if (tex._combine_rgb != other_tex._combine_rgb) {
1911  return tex._combine_rgb < other_tex._combine_rgb;
1912  }
1913  if (tex._combine_alpha != other_tex._combine_alpha) {
1914  return tex._combine_alpha < other_tex._combine_alpha;
1915  }
1916  }
1917  if (_lights.size() != other._lights.size()) {
1918  return _lights.size() < other._lights.size();
1919  }
1920  for (size_t i = 0; i < _lights.size(); ++i) {
1921  const ShaderKey::LightInfo &light = _lights[i];
1922  const ShaderKey::LightInfo &other_light = other._lights[i];
1923  if (light._type != other_light._type) {
1924  return light._type < other_light._type;
1925  }
1926  if (light._flags != other_light._flags) {
1927  return light._flags < other_light._flags;
1928  }
1929  }
1930  if (_lighting != other._lighting) {
1931  return _lighting < other._lighting;
1932  }
1933  if (_have_separate_ambient != other._have_separate_ambient) {
1934  return _have_separate_ambient < other._have_separate_ambient;
1935  }
1936  if (_fog_mode != other._fog_mode) {
1937  return _fog_mode < other._fog_mode;
1938  }
1939  if (_outputs != other._outputs) {
1940  return _outputs < other._outputs;
1941  }
1942  if (_calc_primary_alpha != other._calc_primary_alpha) {
1943  return _calc_primary_alpha < other._calc_primary_alpha;
1944  }
1945  if (_disable_alpha_write != other._disable_alpha_write) {
1946  return _disable_alpha_write < other._disable_alpha_write;
1947  }
1948  if (_alpha_test_mode != other._alpha_test_mode) {
1949  return _alpha_test_mode < other._alpha_test_mode;
1950  }
1951  if (_alpha_test_ref != other._alpha_test_ref) {
1952  return _alpha_test_ref < other._alpha_test_ref;
1953  }
1954  if (_num_clip_planes != other._num_clip_planes) {
1955  return _num_clip_planes < other._num_clip_planes;
1956  }
1957  return _light_ramp < other._light_ramp;
1958 }
1959 
1960 /**
1961  * Returns true if this ShaderKey is equal to the other one.
1962  */
1963 bool ShaderGenerator::ShaderKey::
1964 operator == (const ShaderKey &other) const {
1965  if (_anim_spec != other._anim_spec) {
1966  return false;
1967  }
1968  if (_color_type != other._color_type) {
1969  return false;
1970  }
1971  if (_material_flags != other._material_flags) {
1972  return false;
1973  }
1974  if (_texture_flags != other._texture_flags) {
1975  return false;
1976  }
1977  if (_textures.size() != other._textures.size()) {
1978  return false;
1979  }
1980  for (size_t i = 0; i < _textures.size(); ++i) {
1981  const ShaderKey::TextureInfo &tex = _textures[i];
1982  const ShaderKey::TextureInfo &other_tex = other._textures[i];
1983  if (tex._texcoord_name != other_tex._texcoord_name ||
1984  tex._type != other_tex._type ||
1985  tex._mode != other_tex._mode ||
1986  tex._gen_mode != other_tex._gen_mode ||
1987  tex._flags != other_tex._flags ||
1988  tex._combine_rgb != other_tex._combine_rgb ||
1989  tex._combine_alpha != other_tex._combine_alpha) {
1990  return false;
1991  }
1992  }
1993  if (_lights.size() != other._lights.size()) {
1994  return false;
1995  }
1996  for (size_t i = 0; i < _lights.size(); ++i) {
1997  const ShaderKey::LightInfo &light = _lights[i];
1998  const ShaderKey::LightInfo &other_light = other._lights[i];
1999  if (light._type != other_light._type ||
2000  light._flags != other_light._flags) {
2001  return false;
2002  }
2003  }
2004  return _lighting == other._lighting
2005  && _have_separate_ambient == other._have_separate_ambient
2006  && _fog_mode == other._fog_mode
2007  && _outputs == other._outputs
2008  && _calc_primary_alpha == other._calc_primary_alpha
2009  && _disable_alpha_write == other._disable_alpha_write
2010  && _alpha_test_mode == other._alpha_test_mode
2011  && _alpha_test_ref == other._alpha_test_ref
2012  && _num_clip_planes == other._num_clip_planes
2013  && _light_ramp == other._light_ramp;
2014 }
2015 
2016 #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:64
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