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