Panda3D
shaderGenerator.cxx
1 // Filename: shaderGenerator.cxx
2 // Created by: jyelon (15Dec07)
3 // Updated by: weifengh, PandaSE(15Apr10)
4 // Updated by: agartner, PandaSE(16Apr10) - bug fix to synthesize_shader;
5 // TextureStage::M_modulate (before this, separate textures formatted as
6 // alpha wiped color off resulting rgb)
7 //
8 ////////////////////////////////////////////////////////////////////
9 //
10 // PANDA 3D SOFTWARE
11 // Copyright (c) Carnegie Mellon University. All rights reserved.
12 //
13 // All use of this software is subject to the terms of the revised BSD
14 // license. You should have received a copy of this license along
15 // with this source code in a file named "LICENSE."
16 //
17 ////////////////////////////////////////////////////////////////////
18 
19 #include "shaderGenerator.h"
20 #include "renderState.h"
21 #include "shaderAttrib.h"
22 #include "auxBitplaneAttrib.h"
23 #include "alphaTestAttrib.h"
24 #include "colorBlendAttrib.h"
25 #include "transparencyAttrib.h"
26 #include "textureAttrib.h"
27 #include "colorAttrib.h"
28 #include "lightAttrib.h"
29 #include "materialAttrib.h"
30 #include "lightRampAttrib.h"
31 #include "texMatrixAttrib.h"
32 #include "texGenAttrib.h"
33 #include "colorScaleAttrib.h"
34 #include "clipPlaneAttrib.h"
35 #include "fogAttrib.h"
36 #include "texture.h"
37 #include "ambientLight.h"
38 #include "directionalLight.h"
39 #include "pointLight.h"
40 #include "spotlight.h"
41 #include "lightLensNode.h"
42 #include "lvector4.h"
43 #include "config_pgraphnodes.h"
44 
45 TypeHandle ShaderGenerator::_type_handle;
46 
47 ////////////////////////////////////////////////////////////////////
48 // Function: ShaderGenerator::Constructor
49 // Access: Published
50 // Description: Create a ShaderGenerator. This has no state,
51 // except possibly to cache certain results.
52 // The parameter that must be passed is the GSG to
53 // which the shader generator belongs.
54 ////////////////////////////////////////////////////////////////////
57  _gsg(gsg), _host(host) {
58 }
59 
60 ////////////////////////////////////////////////////////////////////
61 // Function: ShaderGenerator::Destructor
62 // Access: Published, Virtual
63 // Description: Destroy a ShaderGenerator.
64 ////////////////////////////////////////////////////////////////////
67 }
68 
69 ////////////////////////////////////////////////////////////////////
70 // Function: ShaderGenerator::reset_register_allocator
71 // Access: Protected
72 // Description: Clears the register allocator. Initially, the pool
73 // of available registers is empty. You have to add
74 // some if you want there to be any.
75 ////////////////////////////////////////////////////////////////////
76 void ShaderGenerator::
77 reset_register_allocator() {
78  _vtregs_used = 0;
79  _vcregs_used = 0;
80  _ftregs_used = 0;
81  _fcregs_used = 0;
82 }
83 
84 ////////////////////////////////////////////////////////////////////
85 // Function: ShaderGenerator::alloc_vreg
86 // Access: Protected
87 // Description: Allocate a vreg.
88 ////////////////////////////////////////////////////////////////////
89 const char *ShaderGenerator::
90 alloc_vreg() {
91  switch (_vtregs_used) {
92  case 0: _vtregs_used += 1; return "TEXCOORD0";
93  case 1: _vtregs_used += 1; return "TEXCOORD1";
94  case 2: _vtregs_used += 1; return "TEXCOORD2";
95  case 3: _vtregs_used += 1; return "TEXCOORD3";
96  case 4: _vtregs_used += 1; return "TEXCOORD4";
97  case 5: _vtregs_used += 1; return "TEXCOORD5";
98  case 6: _vtregs_used += 1; return "TEXCOORD6";
99  case 7: _vtregs_used += 1; return "TEXCOORD7";
100  }
101  switch (_vcregs_used) {
102  case 0: _vcregs_used += 1; return "COLOR0";
103  case 1: _vcregs_used += 1; return "COLOR1";
104  }
105  // These don't exist in arbvp1, though they're reportedly
106  // supported by other profiles.
107  switch (_vtregs_used) {
108  case 8: _vtregs_used += 1; return "TEXCOORD8";
109  case 9: _vtregs_used += 1; return "TEXCOORD9";
110  case 10: _vtregs_used += 1; return "TEXCOORD10";
111  case 11: _vtregs_used += 1; return "TEXCOORD11";
112  case 12: _vtregs_used += 1; return "TEXCOORD12";
113  case 13: _vtregs_used += 1; return "TEXCOORD13";
114  case 14: _vtregs_used += 1; return "TEXCOORD14";
115  case 15: _vtregs_used += 1; return "TEXCOORD15";
116  }
117  return "UNKNOWN";
118 }
119 
120 ////////////////////////////////////////////////////////////////////
121 // Function: ShaderGenerator::alloc_freg
122 // Access: Protected
123 // Description: Allocate a freg.
124 ////////////////////////////////////////////////////////////////////
125 const char *ShaderGenerator::
126 alloc_freg() {
127  switch (_ftregs_used) {
128  case 0: _ftregs_used += 1; return "TEXCOORD0";
129  case 1: _ftregs_used += 1; return "TEXCOORD1";
130  case 2: _ftregs_used += 1; return "TEXCOORD2";
131  case 3: _ftregs_used += 1; return "TEXCOORD3";
132  case 4: _ftregs_used += 1; return "TEXCOORD4";
133  case 5: _ftregs_used += 1; return "TEXCOORD5";
134  case 6: _ftregs_used += 1; return "TEXCOORD6";
135  case 7: _ftregs_used += 1; return "TEXCOORD7";
136  }
137  // We really shouldn't rely on COLOR fregs,
138  // since the clamping can have unexpected side-effects.
139  //switch (_fcregs_used) {
140  //case 0: _fcregs_used += 1; return "COLOR0";
141  //case 1: _fcregs_used += 1; return "COLOR1";
142  //}
143  // These don't exist in arbvp1/arbfp1, though they're
144  // reportedly supported by other profiles.
145  switch (_ftregs_used) {
146  case 8: _ftregs_used += 1; return "TEXCOORD8";
147  case 9: _ftregs_used += 1; return "TEXCOORD9";
148  case 10: _ftregs_used += 1; return "TEXCOORD10";
149  case 11: _ftregs_used += 1; return "TEXCOORD11";
150  case 12: _ftregs_used += 1; return "TEXCOORD12";
151  case 13: _ftregs_used += 1; return "TEXCOORD13";
152  case 14: _ftregs_used += 1; return "TEXCOORD14";
153  case 15: _ftregs_used += 1; return "TEXCOORD15";
154  }
155  return "UNKNOWN";
156 }
157 
158 ////////////////////////////////////////////////////////////////////
159 // Function: ShaderGenerator::analyze_renderstate
160 // Access: Protected
161 // Description: Analyzes the RenderState prior to shader generation.
162 // The results of the analysis are stored in instance
163 // variables of the Shader Generator.
164 ////////////////////////////////////////////////////////////////////
165 void ShaderGenerator::
166 analyze_renderstate(const RenderState *rs) {
167  clear_analysis();
168 
169  // verify_enforce_attrib_lock();
170  _state = rs;
171  const AuxBitplaneAttrib *aux_bitplane = DCAST(AuxBitplaneAttrib, rs->get_attrib_def(AuxBitplaneAttrib::get_class_slot()));
172  int outputs = aux_bitplane->get_outputs();
173 
174  // Decide whether or not we need alpha testing or alpha blending.
175 
176  const AlphaTestAttrib *alpha_test = DCAST(AlphaTestAttrib, rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
177  if ((alpha_test->get_mode() != RenderAttrib::M_none)&&
178  (alpha_test->get_mode() != RenderAttrib::M_always)) {
179  _have_alpha_test = true;
180  }
181  const ColorBlendAttrib *color_blend = DCAST(ColorBlendAttrib, rs->get_attrib_def(ColorBlendAttrib::get_class_slot()));
182  if (color_blend->get_mode() != ColorBlendAttrib::M_none) {
183  _have_alpha_blend = true;
184  }
185  const TransparencyAttrib *transparency = DCAST(TransparencyAttrib, rs->get_attrib_def(TransparencyAttrib::get_class_slot()));
186  if ((transparency->get_mode() == TransparencyAttrib::M_alpha)||
187  (transparency->get_mode() == TransparencyAttrib::M_dual)) {
188  _have_alpha_blend = true;
189  }
190 
191  // Decide what to send to the framebuffer alpha, if anything.
192 
193  if (outputs & AuxBitplaneAttrib::ABO_glow) {
194  if (_have_alpha_blend) {
195  _calc_primary_alpha = true;
196  _out_primary_glow = false;
197  _disable_alpha_write = true;
198  } else if (_have_alpha_test) {
199  _calc_primary_alpha = true;
200  _out_primary_glow = true;
201  _subsume_alpha_test = true;
202  } else {
203  _calc_primary_alpha = false;
204  _out_primary_glow = true;
205  }
206  } else {
207  if (_have_alpha_blend || _have_alpha_test) {
208  _calc_primary_alpha = true;
209  }
210  }
211 
212  // Determine what to put into the aux bitplane.
213 
214  _out_aux_normal = (outputs & AuxBitplaneAttrib::ABO_aux_normal) ? true:false;
215  _out_aux_glow = (outputs & AuxBitplaneAttrib::ABO_aux_glow) ? true:false;
216  _out_aux_any = (_out_aux_normal || _out_aux_glow);
217 
218  if (_out_aux_normal) {
219  _need_eye_normal = true;
220  }
221 
222  // Count number of textures.
223 
224  const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot()));
225  _num_textures = texture->get_num_on_stages();
226 
227  // Determine whether or not vertex colors or flat colors are present.
228 
229  const ColorAttrib *color = DCAST(ColorAttrib, rs->get_attrib_def(ColorAttrib::get_class_slot()));
230  if (color->get_color_type() == ColorAttrib::T_vertex) {
231  _vertex_colors = true;
232  } else if (color->get_color_type() == ColorAttrib::T_flat) {
233  _flat_colors = true;
234  }
235 
236  // Break out the lights by type.
237 
238  _shadows = false;
239  const LightAttrib *la = DCAST(LightAttrib, rs->get_attrib_def(LightAttrib::get_class_slot()));
240  for (int i=0; i<la->get_num_on_lights(); i++) {
241  NodePath light = la->get_on_light(i);
242  nassertv(!light.is_empty());
243  PandaNode *light_obj = light.node();
244  nassertv(light_obj != (PandaNode *)NULL);
245 
246  if (light_obj->get_type() == AmbientLight::get_class_type()) {
247  _alights_np.push_back(light);
248  _alights.push_back((AmbientLight*)light_obj);
249  }
250  else if (light_obj->get_type() == DirectionalLight::get_class_type()) {
251  _dlights_np.push_back(light);
252  _dlights.push_back((DirectionalLight*)light_obj);
253  if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) {
254  _shadows = true;
255  }
256  }
257  else if (light_obj->get_type() == PointLight::get_class_type()) {
258  _plights_np.push_back(light);
259  _plights.push_back((PointLight*)light_obj);
260  }
261  else if (light_obj->get_type() == Spotlight::get_class_type()) {
262  _slights_np.push_back(light);
263  _slights.push_back((Spotlight*)light_obj);
264  if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) {
265  _shadows = true;
266  }
267  }
268  }
269 
270  // See if there is a normal map, height map, gloss map, or glow map.
271  // Also check if anything has TexGen.
272 
273  const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, rs->get_attrib_def(TexGenAttrib::get_class_slot()));
274  for (int i=0; i<_num_textures; i++) {
275  TextureStage *stage = texture->get_on_stage(i);
276  TextureStage::Mode mode = stage->get_mode();
277  if ((mode == TextureStage::M_normal)||
278  (mode == TextureStage::M_normal_height)||
279  (mode == TextureStage::M_normal_gloss)) {
280  _map_index_normal = i;
281  }
282  if ((mode == TextureStage::M_height)||(mode == TextureStage::M_normal_height)) {
283  _map_index_height = i;
284  }
285  if ((mode == TextureStage::M_glow)||(mode == TextureStage::M_modulate_glow)) {
286  _map_index_glow = i;
287  }
288  if ((mode == TextureStage::M_gloss)||
289  (mode == TextureStage::M_modulate_gloss)||
290  (mode == TextureStage::M_normal_gloss)) {
291  _map_index_gloss = i;
292  }
293  if (mode == TextureStage::M_height) {
294  _map_height_in_alpha = false;
295  }
296  if (mode == TextureStage::M_normal_height) {
297  _map_height_in_alpha = true;
298  }
299  if (tex_gen->has_stage(stage)) {
300  switch (tex_gen->get_mode(stage)) {
301  case TexGenAttrib::M_world_position:
302  _need_world_position = true;
303  break;
304  case TexGenAttrib::M_world_normal:
305  _need_world_normal = true;
306  break;
307  case TexGenAttrib::M_eye_position:
308  _need_eye_position = true;
309  break;
310  case TexGenAttrib::M_eye_normal:
311  _need_eye_normal = true;
312  break;
313  default:
314  break;
315  }
316  }
317  }
318 
319  // Determine whether lighting is needed.
320 
321  if (la->get_num_on_lights() > 0) {
322  _lighting = true;
323  _need_eye_normal = true;
324  }
325 
326  // Find the material.
327 
328  const MaterialAttrib *material = DCAST(MaterialAttrib, rs->get_attrib_def(MaterialAttrib::get_class_slot()));
329 
330  if (!material->is_off()) {
331  _material = material->get_material();
332  } else {
333  _material = Material::get_default();
334  }
335 
336  // Decide which material modes need to be calculated.
337 
338  if (_lighting && (_alights.size() > 0)) {
339  if (_material->has_ambient()) {
340  LColor a = _material->get_ambient();
341  if ((a[0]!=0.0)||(a[1]!=0.0)||(a[2]!=0.0)) {
342  _have_ambient = true;
343  }
344  } else {
345  _have_ambient = true;
346  }
347  }
348 
349  if (_lighting && (_dlights.size() + _plights.size() + _slights.size())) {
350  if (_material->has_diffuse()) {
351  LColor d = _material->get_diffuse();
352  if ((d[0]!=0.0)||(d[1]!=0.0)||(d[2]!=0.0)) {
353  _have_diffuse = true;
354  }
355  } else {
356  _have_diffuse = true;
357  }
358  }
359 
360  if (_lighting && (_material->has_emission())) {
361  LColor e = _material->get_emission();
362  if ((e[0]!=0.0)||(e[1]!=0.0)||(e[2]!=0.0)) {
363  _have_emission = true;
364  }
365  }
366 
367  if (_lighting && (_dlights.size() + _plights.size() + _slights.size())) {
368  if (_material->has_specular()) {
369  LColor s = _material->get_specular();
370  if ((s[0]!=0.0)||(s[1]!=0.0)||(s[2]!=0.0)) {
371  _have_specular = true;
372  }
373  } else if (_map_index_gloss >= 0) {
374  _have_specular = true;
375  }
376 
377  if (_plights.size() + _slights.size() > 0) {
378  _need_eye_position = true;
379 
380  } else if (_have_specular && _material->get_local()) {
381  _need_eye_position = true;
382  }
383  }
384 
385  // Decide whether to separate ambient and diffuse calculations.
386 
387  if (_have_ambient && _have_diffuse) {
388  if (_material->has_ambient()) {
389  if (_material->has_diffuse()) {
390  _separate_ambient_diffuse = _material->get_ambient() != _material->get_diffuse();
391  } else {
392  _separate_ambient_diffuse = true;
393  }
394  } else {
395  if (_material->has_diffuse()) {
396  _separate_ambient_diffuse = true;
397  } else {
398  _separate_ambient_diffuse = false;
399  }
400  }
401  }
402 
403  const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
404  if (_lighting &&
405  (light_ramp->get_mode() != LightRampAttrib::LRT_identity)) {
406  _separate_ambient_diffuse = true;
407  }
408 
409  // Do we want to use the ARB_shadow extension?
410  // This also allows us to use hardware shadows / PCF.
411 
412  _use_shadow_filter = _gsg->get_supports_shadow_filter();
413 
414  // Does the shader need material properties as input?
415 
416  _need_material_props =
417  (_have_ambient && (_material->has_ambient()))||
418  (_have_diffuse && (_material->has_diffuse()))||
419  (_have_emission && (_material->has_emission()))||
420  (_have_specular && (_material->has_specular()));
421 
422  // Check for clip planes.
423 
424  const ClipPlaneAttrib *clip_plane = DCAST(ClipPlaneAttrib, rs->get_attrib_def(ClipPlaneAttrib::get_class_slot()));
425  _num_clip_planes = clip_plane->get_num_on_planes();
426  if (_num_clip_planes > 0) {
427  _need_world_position = true;
428  }
429 
430  const ShaderAttrib *shader_attrib = DCAST(ShaderAttrib, rs->get_attrib_def(ShaderAttrib::get_class_slot()));
431  if (shader_attrib->auto_shader()) {
432  _auto_normal_on = shader_attrib->auto_normal_on();
433  _auto_glow_on = shader_attrib->auto_glow_on();
434  _auto_gloss_on = shader_attrib->auto_gloss_on();
435  _auto_ramp_on = shader_attrib->auto_ramp_on();
436  _auto_shadow_on = shader_attrib->auto_shadow_on();
437  }
438 
439  // Check for fog.
440  const FogAttrib *fog = DCAST(FogAttrib, rs->get_attrib_def(FogAttrib::get_class_slot()));
441  if (!fog->is_off()) {
442  _fog = true;
443  }
444 }
445 
446 ////////////////////////////////////////////////////////////////////
447 // Function: ShaderGenerator::clear_analysis
448 // Access: Protected
449 // Description: Called after analyze_renderstate to discard all
450 // the results of the analysis. This is generally done
451 // after shader generation is complete.
452 ////////////////////////////////////////////////////////////////////
453 void ShaderGenerator::
454 clear_analysis() {
455  _vertex_colors = false;
456  _flat_colors = false;
457  _lighting = false;
458  _shadows = false;
459  _fog = false;
460  _have_ambient = false;
461  _have_diffuse = false;
462  _have_emission = false;
463  _have_specular = false;
464  _separate_ambient_diffuse = false;
465  _map_index_normal = -1;
466  _map_index_glow = -1;
467  _map_index_gloss = -1;
468  _map_index_height = -1;
469  _map_height_in_alpha = false;
470  _calc_primary_alpha = false;
471  _have_alpha_test = false;
472  _have_alpha_blend = false;
473  _subsume_alpha_test = false;
474  _disable_alpha_write = false;
475  _num_clip_planes = 0;
476  _use_shadow_filter = false;
477  _out_primary_glow = false;
478  _out_aux_normal = false;
479  _out_aux_glow = false;
480  _out_aux_any = false;
481  _material = (Material*)NULL;
482  _need_material_props = false;
483  _need_world_position = false;
484  _need_world_normal = false;
485  _need_eye_position = false;
486  _need_eye_normal = false;
487  _auto_normal_on = false;
488  _auto_glow_on = false;
489  _auto_gloss_on = false;
490  _auto_ramp_on = false;
491  _auto_shadow_on = false;
492 
493  _alights.clear();
494  _dlights.clear();
495  _plights.clear();
496  _slights.clear();
497  _alights_np.clear();
498  _dlights_np.clear();
499  _plights_np.clear();
500  _slights_np.clear();
501 }
502 
503 ////////////////////////////////////////////////////////////////////
504 // Function: ShaderGenerator::create_shader_attrib
505 // Access: Protected
506 // Description: Creates a ShaderAttrib given a generated shader's
507 // body. Also inserts the lights into the shader
508 // attrib.
509 ////////////////////////////////////////////////////////////////////
510 CPT(RenderAttrib) ShaderGenerator::
511 create_shader_attrib(const string &txt) {
512  PT(Shader) shader = Shader::make(txt, Shader::SL_Cg);
513  CPT(RenderAttrib) shattr = ShaderAttrib::make();
514  shattr = DCAST(ShaderAttrib, shattr)->set_shader(shader);
515  if (_lighting) {
516  for (int i=0; i < (int)_alights.size(); i++) {
517  shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("alight", i), _alights_np[i]);
518  }
519  for (int i=0; i < (int)_dlights.size(); i++) {
520  shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("dlight", i), _dlights_np[i]);
521  if (_shadows && _dlights[i]->_shadow_caster) {
522  PT(Texture) tex = update_shadow_buffer(_dlights_np[i]);
523  if (tex == NULL) {
524  pgraph_cat.error() << "Failed to create shadow buffer for DirectionalLight '" << _dlights[i]->get_name() << "'!\n";
525  }
526  shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("dlighttex", i), tex);
527  } else {
528  _dlights[i]->clear_shadow_buffers();
529  }
530  }
531  for (int i=0; i < (int)_plights.size(); i++) {
532  shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("plight", i), _plights_np[i]);
533  }
534  for (int i=0; i < (int)_slights.size(); i++) {
535  shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("slight", i), _slights_np[i]);
536  if (_shadows && _slights[i]->_shadow_caster) {
537  PT(Texture) tex = update_shadow_buffer(_slights_np[i]);
538  if (tex == NULL) {
539  pgraph_cat.error() << "Failed to create shadow buffer for Spotlight '" << _slights[i]->get_name() << "'!\n";
540  }
541  shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("slighttex", i), tex);
542  } else {
543  _slights[i]->clear_shadow_buffers();
544  }
545  }
546  }
547  return shattr;
548 }
549 
550 ////////////////////////////////////////////////////////////////////
551 // Function: ShaderGenerator::update_shadow_buffer
552 // Access: Protected, Virtual
553 // Description: Updates the depth buffer of the specified light,
554 // if it is configured to cast shadows.
555 // Only call this function for DirectionalLights
556 // and Spotlights. Returns the depth texture.
557 ////////////////////////////////////////////////////////////////////
558 PT(Texture) ShaderGenerator::
559 update_shadow_buffer(NodePath light_np) {
560  // Make sure everything is valid.
561  nassertr(light_np.node()->is_of_type(DirectionalLight::get_class_type()) ||
562  light_np.node()->is_of_type(Spotlight::get_class_type()), NULL);
563  PT(LightLensNode) light = DCAST(LightLensNode, light_np.node());
564  if (light == NULL || !light->_shadow_caster) {
565  return NULL;
566  }
567 
568  // See if we already have a buffer. If not, create one.
569  Texture *tex;
570  if (light->_sbuffers.count(_gsg) == 0) {
571  // Nope, the light doesn't have a buffer for our GSG. Make one.
572  tex = _gsg->make_shadow_buffer(light_np, _host);
573  } else {
574  // There's already a buffer - use that.
575  tex = light->_sbuffers[_gsg]->get_texture();
576  }
577  nassertr(tex != NULL, NULL);
578 
579  return tex;
580 }
581 
582 ////////////////////////////////////////////////////////////////////
583 // Function: ShaderGenerator::synthesize_shader
584 // Access: Published, Virtual
585 // Description: This is the routine that implements the next-gen
586 // fixed function pipeline by synthesizing a shader.
587 // It also takes care of setting up any buffers
588 // needed to produce the requested effects.
589 //
590 // Currently supports:
591 // - flat colors
592 // - vertex colors
593 // - lighting
594 // - normal maps, but not multiple
595 // - gloss maps, but not multiple
596 // - glow maps, but not multiple
597 // - materials, but not updates to materials
598 // - 2D textures
599 // - all texture stage modes, including combine modes
600 // - color scale attrib
601 // - light ramps (for cartoon shading)
602 // - shadow mapping
603 // - most texgen modes
604 // - texmatrix
605 // - 1D/2D/3D textures, cube textures, 2D tex arrays
606 // - linear/exp/exp2 fog
607 //
608 // Not yet supported:
609 // - dot3_rgb and dot3_rgba combine modes
610 //
611 // Potential optimizations
612 // - omit attenuation calculations if attenuation off
613 //
614 ////////////////////////////////////////////////////////////////////
615 CPT(ShaderAttrib) ShaderGenerator::
616 synthesize_shader(const RenderState *rs) {
617  analyze_renderstate(rs);
618  reset_register_allocator();
619 
620  if (pgraph_cat.is_debug()) {
621  pgraph_cat.debug()
622  << "Generating shader for render state " << *rs << "\n";
623  }
624 
625  // These variables will hold the results of register allocation.
626 
627  const char *tangent_freg = 0;
628  const char *binormal_freg = 0;
629  string tangent_input;
630  string binormal_input;
632  pvector<const char *> dlightcoord_fregs;
633  pvector<const char *> slightcoord_fregs;
634  const char *world_position_freg = 0;
635  const char *world_normal_freg = 0;
636  const char *eye_position_freg = 0;
637  const char *eye_normal_freg = 0;
638  const char *hpos_freg = 0;
639 
640  if (_vertex_colors) {
641  // Reserve COLOR0
642  _vcregs_used = 1;
643  _fcregs_used = 1;
644  }
645 
646  // Generate the shader's text.
647 
648  ostringstream text;
649 
650  text << "//Cg\n";
651 
652  text << "/* Generated shader for render state:\n";
653  rs->write(text, 2);
654  text << "*/\n";
655 
656  text << "void vshader(\n";
657  const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot()));
658  const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, rs->get_attrib_def(TexGenAttrib::get_class_slot()));
659  for (int i = 0; i < _num_textures; ++i) {
660  TextureStage *stage = texture->get_on_stage(i);
661  if (!tex_gen->has_stage(stage)) {
662  const InternalName *texcoord_name = stage->get_texcoord_name();
663 
664  if (texcoord_fregs.count(texcoord_name) == 0) {
665  const char *freg = alloc_freg();
666  string tcname = texcoord_name->join("_");
667  texcoord_fregs[texcoord_name] = freg;
668 
669  text << "\t in float4 vtx_" << tcname << " : " << alloc_vreg() << ",\n";
670  text << "\t out float4 l_" << tcname << " : " << freg << ",\n";
671  }
672  }
673 
674  if ((_map_index_normal == i && (_lighting || _out_aux_normal) && _auto_normal_on) || _map_index_height == i) {
675  const InternalName *texcoord_name = stage->get_texcoord_name();
676  PT(InternalName) tangent_name = InternalName::get_tangent();
677  PT(InternalName) binormal_name = InternalName::get_binormal();
678 
679  if (texcoord_name != InternalName::get_texcoord()) {
680  tangent_name = tangent_name->append(texcoord_name->get_basename());
681  binormal_name = binormal_name->append(texcoord_name->get_basename());
682  }
683  tangent_input = tangent_name->join("_");
684  binormal_input = binormal_name->join("_");
685 
686  text << "\t in float4 vtx_" << tangent_input << " : " << alloc_vreg() << ",\n";
687  text << "\t in float4 vtx_" << binormal_input << " : " << alloc_vreg() << ",\n";
688 
689  if (_map_index_normal == i && (_lighting || _out_aux_normal) && _auto_normal_on) {
690  tangent_freg = alloc_freg();
691  binormal_freg = alloc_freg();
692  text << "\t out float4 l_tangent : " << tangent_freg << ",\n";
693  text << "\t out float4 l_binormal : " << binormal_freg << ",\n";
694  }
695  }
696  }
697  if (_vertex_colors) {
698  text << "\t in float4 vtx_color : COLOR0,\n";
699  text << "\t out float4 l_color : COLOR0,\n";
700  }
701  if (_need_world_position || _need_world_normal) {
702  text << "\t uniform float4x4 trans_model_to_world,\n";
703  }
704  if (_need_world_position) {
705  world_position_freg = alloc_freg();
706  text << "\t out float4 l_world_position : " << world_position_freg << ",\n";
707  }
708  if (_need_world_normal) {
709  world_normal_freg = alloc_freg();
710  text << "\t out float4 l_world_normal : " << world_normal_freg << ",\n";
711  }
712  if (_need_eye_position) {
713  text << "\t uniform float4x4 trans_model_to_view,\n";
714  eye_position_freg = alloc_freg();
715  text << "\t out float4 l_eye_position : " << eye_position_freg << ",\n";
716  } else if ((_lighting || _out_aux_normal) && (_map_index_normal >= 0 && _auto_normal_on)) {
717  text << "\t uniform float4x4 trans_model_to_view,\n";
718  }
719  if (_need_eye_normal) {
720  eye_normal_freg = alloc_freg();
721  text << "\t uniform float4x4 tpose_view_to_model,\n";
722  text << "\t out float4 l_eye_normal : " << eye_normal_freg << ",\n";
723  }
724  if (_map_index_height >= 0 || _need_world_normal || _need_eye_normal) {
725  text << "\t in float3 vtx_normal : NORMAL,\n";
726  }
727  if (_map_index_height >= 0) {
728  text << "\t uniform float4 mspos_view,\n";
729  text << "\t out float3 l_eyevec,\n";
730  }
731  if (_lighting) {
732  if (_shadows && _auto_shadow_on) {
733  for (int i=0; i < (int)_dlights.size(); i++) {
734  if (_dlights[i]->_shadow_caster) {
735  dlightcoord_fregs.push_back(alloc_freg());
736  text << "\t uniform float4x4 trans_model_to_clip_of_dlight" << i << ",\n";
737  text << "\t out float4 l_dlightcoord" << i << " : " << dlightcoord_fregs[i] << ",\n";
738  } else {
739  dlightcoord_fregs.push_back(NULL);
740  }
741  }
742  for (int i=0; i < (int)_slights.size(); i++) {
743  if (_slights[i]->_shadow_caster) {
744  slightcoord_fregs.push_back(alloc_freg());
745  text << "\t uniform float4x4 trans_model_to_clip_of_slight" << i << ",\n";
746  text << "\t out float4 l_slightcoord" << i << " : " << slightcoord_fregs[i] << ",\n";
747  } else {
748  slightcoord_fregs.push_back(NULL);
749  }
750  }
751  }
752  }
753  if (_fog) {
754  hpos_freg = alloc_freg();
755  text << "\t out float4 l_hpos : " << hpos_freg << ",\n";
756  }
757  text << "\t float4 vtx_position : POSITION,\n";
758  text << "\t out float4 l_position : POSITION,\n";
759  text << "\t uniform float4x4 mat_modelproj\n";
760  text << ") {\n";
761 
762  text << "\t l_position = mul(mat_modelproj, vtx_position);\n";
763  if (_fog) {
764  text << "\t l_hpos = l_position;\n";
765  }
766  if (_need_world_position) {
767  text << "\t l_world_position = mul(trans_model_to_world, vtx_position);\n";
768  }
769  if (_need_world_normal) {
770  text << "\t l_world_normal = mul(trans_model_to_world, float4(vtx_normal, 0));\n";
771  }
772  if (_need_eye_position) {
773  text << "\t l_eye_position = mul(trans_model_to_view, vtx_position);\n";
774  }
775  if (_need_eye_normal) {
776  text << "\t l_eye_normal.xyz = mul((float3x3)tpose_view_to_model, vtx_normal);\n";
777  text << "\t l_eye_normal.w = 0;\n";
778  }
780  for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
781  // Pass through all texcoord inputs as-is.
782  string tcname = it->first->join("_");
783  text << "\t l_" << tcname << " = vtx_" << tcname << ";\n";
784  }
785  if (_vertex_colors) {
786  text << "\t l_color = vtx_color;\n";
787  }
788  if ((_lighting || _out_aux_normal) && (_map_index_normal >= 0 && _auto_normal_on)) {
789  text << "\t l_tangent.xyz = normalize(mul((float3x3)trans_model_to_view, vtx_" << tangent_input << ".xyz));\n";
790  text << "\t l_tangent.w = 0;\n";
791  text << "\t l_binormal.xyz = normalize(mul((float3x3)trans_model_to_view, -vtx_" << binormal_input << ".xyz));\n";
792  text << "\t l_binormal.w = 0;\n";
793  }
794  if (_shadows && _auto_shadow_on) {
795  text << "\t float4x4 biasmat = {0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f};\n";
796  for (int i=0; i < (int)_dlights.size(); i++) {
797  if (_dlights[i]->_shadow_caster) {
798  text << "\t l_dlightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_dlight" << i << ", vtx_position));\n";
799  }
800  }
801  for (int i=0; i < (int)_slights.size(); i++) {
802  if (_slights[i]->_shadow_caster) {
803  text << "\t l_slightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_slight" << i << ", vtx_position));\n";
804  }
805  }
806  }
807  if (_map_index_height >= 0) {
808  text << "\t float3 eyedir = mspos_view.xyz - vtx_position.xyz;\n";
809  text << "\t l_eyevec.x = dot(vtx_" << tangent_input << ".xyz, eyedir);\n";
810  text << "\t l_eyevec.y = dot(vtx_" << binormal_input << ".xyz, eyedir);\n";
811  text << "\t l_eyevec.z = dot(vtx_normal, eyedir);\n";
812  text << "\t l_eyevec = normalize(l_eyevec);\n";
813  }
814  text << "}\n\n";
815 
816  // Fragment shader
817 
818  text << "void fshader(\n";
819  if (_fog) {
820  text << "\t in float4 l_hpos : " << hpos_freg << ",\n";
821  text << "\t in uniform float4 attr_fog,\n";
822  text << "\t in uniform float4 attr_fogcolor,\n";
823  }
824  if (_need_world_position) {
825  text << "\t in float4 l_world_position : " << world_position_freg << ",\n";
826  }
827  if (_need_world_normal) {
828  text << "\t in float4 l_world_normal : " << world_normal_freg << ",\n";
829  }
830  if (_need_eye_position) {
831  text << "\t in float4 l_eye_position : " << eye_position_freg << ",\n";
832  }
833  if (_need_eye_normal) {
834  text << "\t in float4 l_eye_normal : " << eye_normal_freg << ",\n";
835  }
836  for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
837  text << "\t in float4 l_" << it->first->join("_") << " : " << it->second << ",\n";
838  }
839  const TexMatrixAttrib *tex_matrix = DCAST(TexMatrixAttrib, rs->get_attrib_def(TexMatrixAttrib::get_class_slot()));
840  for (int i=0; i<_num_textures; i++) {
841  TextureStage *stage = texture->get_on_stage(i);
842  Texture *tex = texture->get_on_texture(stage);
843  nassertr(tex != NULL, NULL);
844  text << "\t uniform sampler" << texture_type_as_string(tex->get_texture_type()) << " tex_" << i << ",\n";
845  if (tex_matrix->has_stage(stage)) {
846  text << "\t uniform float4x4 texmat_" << i << ",\n";
847  }
848  }
849  if ((_lighting || _out_aux_normal) && (_map_index_normal >= 0 && _auto_normal_on)) {
850  text << "\t in float3 l_tangent : " << tangent_freg << ",\n";
851  text << "\t in float3 l_binormal : " << binormal_freg << ",\n";
852  }
853  if (_lighting) {
854  for (int i=0; i < (int)_alights.size(); i++) {
855  text << "\t uniform float4 alight_alight" << i << ",\n";
856  }
857  for (int i=0; i < (int)_dlights.size(); i++) {
858  text << "\t uniform float4x4 dlight_dlight" << i << "_rel_view,\n";
859  if (_shadows && _dlights[i]->_shadow_caster && _auto_shadow_on) {
860  if (_use_shadow_filter) {
861  text << "\t uniform sampler2DShadow k_dlighttex" << i << ",\n";
862  } else {
863  text << "\t uniform sampler2D k_dlighttex" << i << ",\n";
864  }
865  text << "\t in float4 l_dlightcoord" << i << " : " << dlightcoord_fregs[i] << ",\n";
866  }
867  }
868  for (int i=0; i < (int)_plights.size(); i++) {
869  text << "\t uniform float4x4 plight_plight" << i << "_rel_view,\n";
870  }
871  for (int i=0; i < (int)_slights.size(); i++) {
872  text << "\t uniform float4x4 slight_slight" << i << "_rel_view,\n";
873  text << "\t uniform float4 satten_slight" << i << ",\n";
874  if (_shadows && _slights[i]->_shadow_caster && _auto_shadow_on) {
875  if (_use_shadow_filter) {
876  text << "\t uniform sampler2DShadow k_slighttex" << i << ",\n";
877  } else {
878  text << "\t uniform sampler2D k_slighttex" << i << ",\n";
879  }
880  text << "\t in float4 l_slightcoord" << i << " : " << slightcoord_fregs[i] << ",\n";
881  }
882  }
883  if (_need_material_props) {
884  text << "\t uniform float4x4 attr_material,\n";
885  }
886  if (_have_specular) {
887  if (_material->get_local()) {
888  text << "\t uniform float4 mspos_view,\n";
889  } else {
890  text << "\t uniform float4 row1_view_to_model,\n";
891  }
892  }
893  }
894  if (_map_index_height >= 0) {
895  text << "\t float3 l_eyevec,\n";
896  }
897  if (_out_aux_any) {
898  text << "\t out float4 o_aux : COLOR1,\n";
899  }
900  text << "\t out float4 o_color : COLOR0,\n";
901  if (_vertex_colors) {
902  text << "\t in float4 l_color : COLOR0,\n";
903  } else {
904  text << "\t uniform float4 attr_color,\n";
905  }
906  for (int i=0; i<_num_clip_planes; ++i) {
907  text << "\t uniform float4 clipplane_" << i << ",\n";
908  }
909  text << "\t uniform float4 attr_colorscale\n";
910  text << ") {\n";
911  // Clipping first!
912  for (int i=0; i<_num_clip_planes; ++i) {
913  text << "\t if (l_world_position.x * clipplane_" << i << ".x + l_world_position.y ";
914  text << "* clipplane_" << i << ".y + l_world_position.z * clipplane_" << i << ".z + clipplane_" << i << ".w <= 0) {\n";
915  text << "\t discard;\n";
916  text << "\t }\n";
917  }
918  text << "\t float4 result;\n";
919  if (_out_aux_any) {
920  text << "\t o_aux = float4(0, 0, 0, 0);\n";
921  }
922  // Now generate any texture coordinates according to TexGenAttrib. If it has a TexMatrixAttrib, also transform them.
923  for (int i=0; i<_num_textures; i++) {
924  TextureStage *stage = texture->get_on_stage(i);
925  if (tex_gen != NULL && tex_gen->has_stage(stage)) {
926  switch (tex_gen->get_mode(stage)) {
927  case TexGenAttrib::M_world_position:
928  text << "\t float4 texcoord" << i << " = l_world_position;\n";
929  break;
930  case TexGenAttrib::M_world_normal:
931  text << "\t float4 texcoord" << i << " = l_world_normal;\n";
932  break;
933  case TexGenAttrib::M_eye_position:
934  text << "\t float4 texcoord" << i << " = l_eye_position;\n";
935  break;
936  case TexGenAttrib::M_eye_normal:
937  text << "\t float4 texcoord" << i << " = l_eye_normal;\n";
938  text << "\t texcoord" << i << ".w = 1.0f;\n";
939  break;
940  default:
941  pgraph_cat.error() << "Unsupported TexGenAttrib mode\n";
942  text << "\t float4 texcoord" << i << " = float4(0, 0, 0, 0);\n";
943  }
944  } else {
945  // Cg seems to be able to optimize this temporary away when appropriate.
946  const InternalName *texcoord_name = stage->get_texcoord_name();
947  text << "\t float4 texcoord" << i << " = l_" << texcoord_name->join("_") << ";\n";
948  }
949  if (tex_matrix != NULL && tex_matrix->has_stage(stage)) {
950  text << "\t texcoord" << i << " = mul(texmat_" << i << ", texcoord" << i << ");\n";
951  text << "\t texcoord" << i << ".xyz /= texcoord" << i << ".w;\n";
952  }
953  }
954  text << "\t // Fetch all textures.\n";
955  if (_map_index_height >= 0 && parallax_mapping_samples > 0) {
956  Texture *tex = texture->get_on_texture(texture->get_on_stage(_map_index_height));
957  nassertr(tex != NULL, NULL);
958  text << "\t float4 tex" << _map_index_height << " = tex" << texture_type_as_string(tex->get_texture_type());
959  text << "(tex_" << _map_index_height << ", texcoord" << _map_index_height << ".";
960  switch (tex->get_texture_type()) {
961  case Texture::TT_cube_map:
962  case Texture::TT_3d_texture:
963  case Texture::TT_2d_texture_array:
964  text << "xyz";
965  break;
966  case Texture::TT_2d_texture:
967  text << "xy";
968  break;
969  case Texture::TT_1d_texture:
970  text << "x";
971  break;
972  default:
973  break;
974  }
975  text << ");\n\t float3 parallax_offset = l_eyevec.xyz * (tex" << _map_index_height;
976  if (_map_height_in_alpha) {
977  text << ".aaa";
978  } else {
979  text << ".rgb";
980  }
981  text << " * 2.0 - 1.0) * " << parallax_mapping_scale << ";\n";
982  // Additional samples
983  for (int i=0; i<parallax_mapping_samples-1; i++) {
984  text << "\t parallax_offset = l_eyevec.xyz * (parallax_offset + (tex" << _map_index_height;
985  if (_map_height_in_alpha) {
986  text << ".aaa";
987  } else {
988  text << ".rgb";
989  }
990  text << " * 2.0 - 1.0)) * " << 0.5 * parallax_mapping_scale << ";\n";
991  }
992  }
993  for (int i=0; i<_num_textures; i++) {
994  if (i != _map_index_height) {
995  Texture *tex = texture->get_on_texture(texture->get_on_stage(i));
996  nassertr(tex != NULL, NULL);
997  // Parallax mapping pushes the texture coordinates of the other textures away from the camera.
998  if (_map_index_height >= 0 && parallax_mapping_samples > 0) {
999  text << "\t texcoord" << i << ".xyz -= parallax_offset;\n";
1000  }
1001  text << "\t float4 tex" << i << " = tex" << texture_type_as_string(tex->get_texture_type());
1002  text << "(tex_" << i << ", texcoord" << i << ".";
1003  switch(tex->get_texture_type()) {
1004  case Texture::TT_cube_map:
1005  case Texture::TT_3d_texture:
1006  case Texture::TT_2d_texture_array:
1007  text << "xyz";
1008  break;
1009  case Texture::TT_2d_texture:
1010  text << "xy";
1011  break;
1012  case Texture::TT_1d_texture:
1013  text << "x";
1014  break;
1015  default:
1016  break;
1017  }
1018  text << ");\n";
1019  }
1020  }
1021  if (_lighting || _out_aux_normal) {
1022  if (_map_index_normal >= 0 && _auto_normal_on) {
1023  text << "\t // Translate tangent-space normal in map to view-space.\n";
1024  text << "\t float3 tsnormal = ((float3)tex" << _map_index_normal << " * 2) - 1;\n";
1025  text << "\t l_eye_normal.xyz *= tsnormal.z;\n";
1026  text << "\t l_eye_normal.xyz += l_tangent * tsnormal.x;\n";
1027  text << "\t l_eye_normal.xyz += l_binormal * tsnormal.y;\n";
1028  }
1029  }
1030  if (_need_eye_normal) {
1031  text << "\t // Correct the surface normal for interpolation effects\n";
1032  text << "\t l_eye_normal.xyz = normalize(l_eye_normal.xyz);\n";
1033  }
1034  if (_out_aux_normal) {
1035  text << "\t // Output the camera-space surface normal\n";
1036  text << "\t o_aux.rgb = (l_eye_normal.xyz*0.5) + float3(0.5,0.5,0.5);\n";
1037  }
1038  if (_lighting) {
1039  text << "\t // Begin view-space light calculations\n";
1040  text << "\t float ldist,lattenv,langle;\n";
1041  text << "\t float4 lcolor,lspec,lvec,lpoint,latten,ldir,leye,lhalf;\n";
1042  if (_shadows && _auto_shadow_on) {
1043  text << "\t float lshad;\n";
1044  }
1045  if (_separate_ambient_diffuse) {
1046  if (_have_ambient) {
1047  text << "\t float4 tot_ambient = float4(0,0,0,0);\n";
1048  }
1049  if (_have_diffuse) {
1050  text << "\t float4 tot_diffuse = float4(0,0,0,0);\n";
1051  }
1052  } else {
1053  if (_have_ambient || _have_diffuse) {
1054  text << "\t float4 tot_diffuse = float4(0,0,0,0);\n";
1055  }
1056  }
1057  if (_have_specular) {
1058  text << "\t float4 tot_specular = float4(0,0,0,0);\n";
1059  if (_material->has_specular()) {
1060  text << "\t float shininess = attr_material[3].w;\n";
1061  } else {
1062  text << "\t float shininess = 50; // no shininess specified, using default\n";
1063  }
1064  }
1065  for (int i=0; i < (int)_alights.size(); i++) {
1066  text << "\t // Ambient Light " << i << "\n";
1067  text << "\t lcolor = alight_alight" << i << ";\n";
1068  if (_separate_ambient_diffuse && _have_ambient) {
1069  text << "\t tot_ambient += lcolor;\n";
1070  } else if(_have_diffuse) {
1071  text << "\t tot_diffuse += lcolor;\n";
1072  }
1073  }
1074  for (int i=0; i < (int)_dlights.size(); i++) {
1075  text << "\t // Directional Light " << i << "\n";
1076  text << "\t lcolor = dlight_dlight" << i << "_rel_view[0];\n";
1077  text << "\t lspec = dlight_dlight" << i << "_rel_view[1];\n";
1078  text << "\t lvec = dlight_dlight" << i << "_rel_view[2];\n";
1079  text << "\t lcolor *= saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
1080  if (_shadows && _dlights[i]->_shadow_caster && _auto_shadow_on) {
1081  if (_use_shadow_filter) {
1082  text << "\t lshad = shadow2DProj(k_dlighttex" << i << ", l_dlightcoord" << i << ").r;\n";
1083  } else {
1084  text << "\t lshad = tex2Dproj(k_dlighttex" << i << ", l_dlightcoord" << i << ").r > l_dlightcoord" << i << ".z / l_dlightcoord" << i << ".w;\n";
1085  }
1086  text << "\t lcolor *= lshad;\n";
1087  text << "\t lspec *= lshad;\n";
1088  }
1089  if (_have_diffuse) {
1090  text << "\t tot_diffuse += lcolor;\n";
1091  }
1092  if (_have_specular) {
1093  if (_material->get_local()) {
1094  text << "\t lhalf = normalize(lvec - normalize(l_eye_position));\n";
1095  } else {
1096  text << "\t lhalf = dlight_dlight" << i << "_rel_view[3];\n";
1097  }
1098  text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
1099  text << "\t tot_specular += lspec;\n";
1100  }
1101  }
1102  for (int i=0; i < (int)_plights.size(); i++) {
1103  text << "\t // Point Light " << i << "\n";
1104  text << "\t lcolor = plight_plight" << i << "_rel_view[0];\n";
1105  text << "\t lspec = plight_plight" << i << "_rel_view[1];\n";
1106  text << "\t lpoint = plight_plight" << i << "_rel_view[2];\n";
1107  text << "\t latten = plight_plight" << i << "_rel_view[3];\n";
1108  text << "\t lvec = lpoint - l_eye_position;\n";
1109  text << "\t ldist = length(float3(lvec));\n";
1110  text << "\t lvec /= ldist;\n";
1111  text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1112  text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
1113  if (_have_diffuse) {
1114  text << "\t tot_diffuse += lcolor;\n";
1115  }
1116  if (_have_specular) {
1117  if (_material->get_local()) {
1118  text << "\t lhalf = normalize(lvec - normalize(l_eye_position));\n";
1119  } else {
1120  text << "\t lhalf = normalize(lvec - float4(0, 1, 0, 0));\n";
1121  }
1122  text << "\t lspec *= lattenv;\n";
1123  text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
1124  text << "\t tot_specular += lspec;\n";
1125  }
1126  }
1127  for (int i=0; i < (int)_slights.size(); i++) {
1128  text << "\t // Spot Light " << i << "\n";
1129  text << "\t lcolor = slight_slight" << i << "_rel_view[0];\n";
1130  text << "\t lspec = slight_slight" << i << "_rel_view[1];\n";
1131  text << "\t lpoint = slight_slight" << i << "_rel_view[2];\n";
1132  text << "\t ldir = slight_slight" << i << "_rel_view[3];\n";
1133  text << "\t latten = satten_slight" << i << ";\n";
1134  text << "\t lvec = lpoint - l_eye_position;\n";
1135  text << "\t ldist = length(float3(lvec));\n";
1136  text << "\t lvec /= ldist;\n";
1137  text << "\t langle = saturate(dot(ldir.xyz, lvec.xyz));\n";
1138  text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1139  text << "\t lattenv *= pow(langle, latten.w);\n";
1140  text << "\t if (langle < ldir.w) lattenv = 0;\n";
1141  text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
1142  if (_shadows && _slights[i]->_shadow_caster && _auto_shadow_on) {
1143  if (_use_shadow_filter) {
1144  text << "\t lshad = shadow2DProj(k_slighttex" << i << ", l_slightcoord" << i << ").r;\n";
1145  } else {
1146  text << "\t lshad = tex2Dproj(k_slighttex" << i << ", l_slightcoord" << i << ").r > l_slightcoord" << i << ".z / l_slightcoord" << i << ".w;\n";
1147  }
1148  text << "\t lcolor *= lshad;\n";
1149  text << "\t lspec *= lshad;\n";
1150  }
1151 
1152  if (_have_diffuse) {
1153  text << "\t tot_diffuse += lcolor;\n";
1154  }
1155  if (_have_specular) {
1156  if (_material->get_local()) {
1157  text << "\t lhalf = normalize(lvec - normalize(l_eye_position));\n";
1158  } else {
1159  text << "\t lhalf = normalize(lvec - float4(0,1,0,0));\n";
1160  }
1161  text << "\t lspec *= lattenv;\n";
1162  text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
1163  text << "\t tot_specular += lspec;\n";
1164  }
1165  }
1166  const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
1167  if (_auto_ramp_on && _have_diffuse) {
1168  switch (light_ramp->get_mode()) {
1169  case LightRampAttrib::LRT_single_threshold:
1170  {
1171  PN_stdfloat t = light_ramp->get_threshold(0);
1172  PN_stdfloat l0 = light_ramp->get_level(0);
1173  text << "\t // Single-threshold light ramp\n";
1174  text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1175  text << "\t float lr_scale = (lr_in < " << t << ") ? 0.0 : (" << l0 << "/lr_in);\n";
1176  text << "\t tot_diffuse = tot_diffuse * lr_scale;\n";
1177  break;
1178  }
1179  case LightRampAttrib::LRT_double_threshold:
1180  {
1181  PN_stdfloat t0 = light_ramp->get_threshold(0);
1182  PN_stdfloat t1 = light_ramp->get_threshold(1);
1183  PN_stdfloat l0 = light_ramp->get_level(0);
1184  PN_stdfloat l1 = light_ramp->get_level(1);
1185  text << "\t // Double-threshold light ramp\n";
1186  text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1187  text << "\t float lr_out = 0.0;\n";
1188  text << "\t if (lr_in > " << t0 << ") lr_out=" << l0 << ";\n";
1189  text << "\t if (lr_in > " << t1 << ") lr_out=" << l1 << ";\n";
1190  text << "\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n";
1191  break;
1192  }
1193  default:
1194  break;
1195  }
1196  }
1197  text << "\t // Begin view-space light summation\n";
1198  if (_have_emission) {
1199  if (_map_index_glow >= 0 && _auto_glow_on) {
1200  text << "\t result = attr_material[2] * saturate(2 * (tex" << _map_index_glow << ".a - 0.5));\n";
1201  } else {
1202  text << "\t result = attr_material[2];\n";
1203  }
1204  } else {
1205  if (_map_index_glow >= 0 && _auto_glow_on) {
1206  text << "\t result = saturate(2 * (tex" << _map_index_glow << ".a - 0.5));\n";
1207  } else {
1208  text << "\t result = float4(0,0,0,0);\n";
1209  }
1210  }
1211  if ((_have_ambient)&&(_separate_ambient_diffuse)) {
1212  if (_material->has_ambient()) {
1213  text << "\t result += tot_ambient * attr_material[0];\n";
1214  } else if (_vertex_colors) {
1215  text << "\t result += tot_ambient * l_color;\n";
1216  } else if (_flat_colors) {
1217  text << "\t result += tot_ambient * attr_color;\n";
1218  } else {
1219  text << "\t result += tot_ambient;\n";
1220  }
1221  }
1222  if (_have_diffuse) {
1223  if (_material->has_diffuse()) {
1224  text << "\t result += tot_diffuse * attr_material[1];\n";
1225  } else if (_vertex_colors) {
1226  text << "\t result += tot_diffuse * l_color;\n";
1227  } else if (_flat_colors) {
1228  text << "\t result += tot_diffuse * attr_color;\n";
1229  } else {
1230  text << "\t result += tot_diffuse;\n";
1231  }
1232  }
1233  if (light_ramp->get_mode() == LightRampAttrib::LRT_default) {
1234  text << "\t result = saturate(result);\n";
1235  }
1236  text << "\t // End view-space light calculations\n";
1237 
1238  // Combine in alpha, which bypasses lighting calculations.
1239  // Use of lerp here is a workaround for a radeon driver bug.
1240  if (_calc_primary_alpha) {
1241  if (_vertex_colors) {
1242  text << "\t result.a = l_color.a;\n";
1243  } else if (_flat_colors) {
1244  text << "\t result.a = attr_color.a;\n";
1245  } else {
1246  text << "\t result.a = 1;\n";
1247  }
1248  }
1249  } else {
1250  if (_vertex_colors) {
1251  text << "\t result = l_color;\n";
1252  } else if (_flat_colors) {
1253  text << "\t result = attr_color;\n";
1254  } else {
1255  text << "\t result = float4(1, 1, 1, 1);\n";
1256  }
1257  }
1258 
1259  // Loop first to see if something is using primary_color or last_saved_result.
1260  bool have_saved_result = false;
1261  bool have_primary_color = false;
1262  for (int i=0; i<_num_textures; i++) {
1263  TextureStage *stage = texture->get_on_stage(i);
1264  if (stage->get_mode() != TextureStage::M_combine) continue;
1265  if (stage->uses_primary_color() && !have_primary_color) {
1266  text << "\t float4 primary_color = result;\n";
1267  have_primary_color = true;
1268  }
1269  if (stage->uses_last_saved_result() && !have_saved_result) {
1270  text << "\t float4 last_saved_result = result;\n";
1271  have_saved_result = true;
1272  }
1273  }
1274 
1275  // Now loop through the textures to compose our magic blending formulas.
1276  for (int i=0; i<_num_textures; i++) {
1277  TextureStage *stage = texture->get_on_stage(i);
1278  switch (stage->get_mode()) {
1279  case TextureStage::M_modulate: {
1280  int num_components = texture->get_on_texture(texture->get_on_stage(i))->get_num_components();
1281 
1282  if (num_components == 1) {
1283  text << "\t result.a *= tex" << i << ".a;\n";
1284  } else if (num_components == 3) {
1285  text << "\t result.rgb *= tex" << i << ".rgb;\n";
1286  } else {
1287  text << "\t result.rgba *= tex" << i << ".rgba;\n";
1288  }
1289 
1290  break; }
1291  case TextureStage::M_modulate_glow:
1292  case TextureStage::M_modulate_gloss:
1293  //in the case of glow or spec we currently see the specularity evenly across the surface
1294  //even if transparency or masking is present
1295  //not sure if this is desired behavior or not.
1296  //*MOST* would construct a spec map based off of
1297  //what is/isn't seen based on the mask/transparency
1298  //this may have to be left alone for now
1299  //agartner
1300  text << "\t result.rgb *= tex" << i << ";\n";
1301  break;
1302  case TextureStage::M_decal:
1303  text << "\t result.rgb = lerp(result, tex" << i << ", tex" << i << ".a).rgb;\n";
1304  break;
1305  case TextureStage::M_blend: {
1306  LVecBase4 c = stage->get_color();
1307  text << "\t result.rgb = lerp(result, tex" << i << " * float4("
1308  << c[0] << ", " << c[1] << ", " << c[2] << ", " << c[3] << "), tex" << i << ".r).rgb;\n";
1309  break; }
1310  case TextureStage::M_replace:
1311  text << "\t result = tex" << i << ";\n";
1312  break;
1313  case TextureStage::M_add:
1314  text << "\t result.rgb += tex" << i << ".rgb;\n";
1315  if (_calc_primary_alpha) {
1316  text << "\t result.a *= tex" << i << ".a;\n";
1317  }
1318  break;
1319  case TextureStage::M_combine:
1320  text << "\t result.rgb = ";
1321  if (stage->get_combine_rgb_mode() != TextureStage::CM_undefined) {
1322  text << combine_mode_as_string(stage, stage->get_combine_rgb_mode(), false, i);
1323  } else {
1324  text << "tex" << i << ".rgb";
1325  }
1326  if (stage->get_rgb_scale() != 1) {
1327  text << " * " << stage->get_rgb_scale();
1328  }
1329  text << ";\n\t result.a = ";
1330  if (stage->get_combine_alpha_mode() != TextureStage::CM_undefined) {
1331  text << combine_mode_as_string(stage, stage->get_combine_alpha_mode(), true, i);
1332  } else {
1333  text << "tex" << i << ".a";
1334  }
1335  if (stage->get_alpha_scale() != 1) {
1336  text << " * " << stage->get_alpha_scale();
1337  }
1338  text << ";\n";
1339  break;
1340  case TextureStage::M_blend_color_scale:
1341  text << "\t result.rgb = lerp(result, tex" << i << " * attr_colorscale, tex" << i << ".r).rgb;\n";
1342  break;
1343  default:
1344  break;
1345  }
1346  if (stage->get_saved_result() && have_saved_result) {
1347  text << "\t last_saved_result = result;\n";
1348  }
1349  }
1350  // Apply the color scale.
1351  text << "\t result *= attr_colorscale;\n";
1352 
1353  if (_subsume_alpha_test) {
1354  const AlphaTestAttrib *alpha_test = DCAST(AlphaTestAttrib, rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
1355  text << "\t // Shader includes alpha test:\n";
1356  double ref = alpha_test->get_reference_alpha();
1357  switch (alpha_test->get_mode()) {
1358  case RenderAttrib::M_never:
1359  text << "\t discard;\n";
1360  break;
1361  case RenderAttrib::M_less:
1362  text << "\t if (result.a >= " << ref << ") discard;\n";
1363  break;
1364  case RenderAttrib::M_equal:
1365  text << "\t if (result.a != " << ref << ") discard;\n";
1366  break;
1367  case RenderAttrib::M_less_equal:
1368  text << "\t if (result.a > " << ref << ") discard;\n";
1369  break;
1370  case RenderAttrib::M_greater:
1371  text << "\t if (result.a <= " << ref << ") discard;\n";
1372  break;
1373  case RenderAttrib::M_not_equal:
1374  text << "\t if (result.a == " << ref << ") discard;\n";
1375  break;
1376  case RenderAttrib::M_greater_equal:
1377  text << "\t if (result.a < " << ref << ") discard;\n";
1378  break;
1379  case RenderAttrib::M_none:
1380  case RenderAttrib::M_always:
1381  default:
1382  break;
1383  }
1384  }
1385 
1386  if (_out_primary_glow) {
1387  if (_map_index_glow >= 0 && _auto_glow_on) {
1388  text << "\t result.a = tex" << _map_index_glow << ".a;\n";
1389  } else {
1390  text << "\t result.a = 0.5;\n";
1391  }
1392  }
1393  if (_out_aux_glow) {
1394  if (_map_index_glow >= 0 && _auto_glow_on) {
1395  text << "\t o_aux.a = tex" << _map_index_glow << ".a;\n";
1396  } else {
1397  text << "\t o_aux.a = 0.5;\n";
1398  }
1399  }
1400 
1401  if (_lighting) {
1402  if (_have_specular) {
1403  if (_material->has_specular()) {
1404  text << "\t tot_specular *= attr_material[3];\n";
1405  }
1406  if (_map_index_gloss >= 0 && _auto_gloss_on) {
1407  text << "\t tot_specular *= tex" << _map_index_gloss << ".a;\n";
1408  }
1409  text << "\t result.rgb = result.rgb + tot_specular.rgb;\n";
1410  }
1411  }
1412  if (_auto_ramp_on) {
1413  const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
1414  switch (light_ramp->get_mode()) {
1415  case LightRampAttrib::LRT_hdr0:
1416  text << "\t result.rgb = (result*result*result + result*result + result) / (result*result*result + result*result + result + 1);\n";
1417  break;
1418  case LightRampAttrib::LRT_hdr1:
1419  text << "\t result.rgb = (result*result + result) / (result*result + result + 1);\n";
1420  break;
1421  case LightRampAttrib::LRT_hdr2:
1422  text << "\t result.rgb = result / (result + 1);\n";
1423  break;
1424  default: break;
1425  }
1426  }
1427 
1428  // Apply fog.
1429  if (_fog) {
1430  const FogAttrib *fog_attr = DCAST(FogAttrib, rs->get_attrib_def(FogAttrib::get_class_slot()));
1431  Fog *fog = fog_attr->get_fog();
1432 
1433  switch (fog->get_mode()) {
1434  case Fog::M_linear:
1435  text << "\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate((attr_fog.z - l_hpos.z) * attr_fog.w));\n";
1436  break;
1437  case Fog::M_exponential: // 1.442695f = 1 / log(2)
1438  text << "\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate(exp2(attr_fog.x * l_hpos.z * -1.442695f)));\n";
1439  break;
1440  case Fog::M_exponential_squared:
1441  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";
1442  break;
1443  }
1444  }
1445 
1446  // The multiply is a workaround for a radeon driver bug.
1447  // It's annoying as heck, since it produces an extra instruction.
1448  text << "\t o_color = result * 1.000001;\n";
1449  if (_subsume_alpha_test) {
1450  text << "\t // Shader subsumes normal alpha test.\n";
1451  }
1452  if (_disable_alpha_write) {
1453  text << "\t // Shader disables alpha write.\n";
1454  }
1455  text << "}\n";
1456 
1457  // Insert the shader into the shader attrib.
1458  CPT(RenderAttrib) shattr = create_shader_attrib(text.str());
1459  if (_subsume_alpha_test) {
1460  shattr = DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_subsume_alpha_test, true);
1461  }
1462  if (_disable_alpha_write) {
1463  shattr = DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_disable_alpha_write, true);
1464  }
1465  clear_analysis();
1466  reset_register_allocator();
1467  return DCAST(ShaderAttrib, shattr);
1468 }
1469 
1470 ////////////////////////////////////////////////////////////////////
1471 // Function: ShaderGenerator::combine_mode_as_string
1472 // Access: Protected, Static
1473 // Description: This 'synthesizes' a combine mode into a string.
1474 ////////////////////////////////////////////////////////////////////
1475 const string ShaderGenerator::
1476 combine_mode_as_string(CPT(TextureStage) stage, TextureStage::CombineMode c_mode, bool alpha, short texindex) {
1477  ostringstream text;
1478  switch (c_mode) {
1479  case TextureStage::CM_modulate:
1480  text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
1481  text << " * ";
1482  text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
1483  break;
1484  case TextureStage::CM_add:
1485  text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
1486  text << " + ";
1487  text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
1488  break;
1489  case TextureStage::CM_add_signed:
1490  text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
1491  text << " + ";
1492  text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
1493  if (alpha) {
1494  text << " - 0.5";
1495  } else {
1496  text << " - float3(0.5, 0.5, 0.5)";
1497  }
1498  break;
1499  case TextureStage::CM_interpolate:
1500  text << "lerp(";
1501  text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
1502  text << ", ";
1503  text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
1504  text << ", ";
1505  text << combine_source_as_string(stage, 2, alpha, true, texindex);
1506  text << ")";
1507  break;
1508  case TextureStage::CM_subtract:
1509  text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
1510  text << " + ";
1511  text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
1512  break;
1513  case TextureStage::CM_dot3_rgb:
1514  pgraph_cat.error() << "TextureStage::CombineMode DOT3_RGB not yet supported in per-pixel mode.\n";
1515  break;
1516  case TextureStage::CM_dot3_rgba:
1517  pgraph_cat.error() << "TextureStage::CombineMode DOT3_RGBA not yet supported in per-pixel mode.\n";
1518  break;
1519  case TextureStage::CM_replace:
1520  default: // Not sure if this is correct as default value.
1521  text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
1522  break;
1523  }
1524  return text.str();
1525 }
1526 
1527 ////////////////////////////////////////////////////////////////////
1528 // Function: ShaderGenerator::combine_source_as_string
1529 // Access: Protected, Static
1530 // Description: This 'synthesizes' a combine source into a string.
1531 ////////////////////////////////////////////////////////////////////
1532 const string ShaderGenerator::
1533 combine_source_as_string(CPT(TextureStage) stage, short num, bool alpha, bool single_value, short texindex) {
1534  TextureStage::CombineSource c_src = TextureStage::CS_undefined;
1535  TextureStage::CombineOperand c_op = TextureStage::CO_undefined;
1536  if (alpha) {
1537  switch (num) {
1538  case 0:
1539  c_src = stage->get_combine_alpha_source0();
1540  c_op = stage->get_combine_alpha_operand0();
1541  break;
1542  case 1:
1543  c_src = stage->get_combine_alpha_source1();
1544  c_op = stage->get_combine_alpha_operand1();
1545  break;
1546  case 2:
1547  c_src = stage->get_combine_alpha_source2();
1548  c_op = stage->get_combine_alpha_operand2();
1549  break;
1550  }
1551  } else {
1552  switch (num) {
1553  case 0:
1554  c_src = stage->get_combine_rgb_source0();
1555  c_op = stage->get_combine_rgb_operand0();
1556  break;
1557  case 1:
1558  c_src = stage->get_combine_rgb_source1();
1559  c_op = stage->get_combine_rgb_operand1();
1560  break;
1561  case 2:
1562  c_src = stage->get_combine_rgb_source2();
1563  c_op = stage->get_combine_rgb_operand2();
1564  break;
1565  }
1566  }
1567  ostringstream csource;
1568  if (c_op == TextureStage::CO_one_minus_src_color ||
1569  c_op == TextureStage::CO_one_minus_src_alpha) {
1570  csource << "1.0f - ";
1571  }
1572  switch (c_src) {
1573  case TextureStage::CS_texture:
1574  csource << "tex" << texindex;
1575  break;
1576  case TextureStage::CS_constant: {
1577  LVecBase4 c = stage->get_color();
1578  csource << "float4(" << c[0] << ", " << c[1] << ", " << c[2] << ", " << c[3] << ")";
1579  break; }
1580  case TextureStage::CS_primary_color:
1581  csource << "primary_color";
1582  break;
1583  case TextureStage::CS_previous:
1584  csource << "result";
1585  break;
1586  case TextureStage::CS_constant_color_scale:
1587  csource << "attr_colorscale";
1588  break;
1589  case TextureStage::CS_last_saved_result:
1590  csource << "last_saved_result";
1591  break;
1592  case TextureStage::CS_undefined:
1593  break;
1594  }
1595  if (c_op == TextureStage::CO_src_color || c_op == TextureStage::CO_one_minus_src_color) {
1596  if (single_value) {
1597  // Let's take the red channel.
1598  csource << ".r";
1599  } else {
1600  csource << ".rgb";
1601  }
1602  } else {
1603  csource << ".a";
1604  if (!single_value) {
1605  // Dunno if it's legal in the FPP at all, but let's just allow it.
1606  return "float3(" + csource.str() + ")";
1607  }
1608  }
1609  return csource.str();
1610 }
1611 
1612 ////////////////////////////////////////////////////////////////////
1613 // Function: ShaderGenerator::texture_type_as_string
1614 // Access: Protected, Static
1615 // Description: Returns 1D, 2D, 3D or CUBE, depending on the given
1616 // texture type.
1617 ////////////////////////////////////////////////////////////////////
1618 const string ShaderGenerator::
1619 texture_type_as_string(Texture::TextureType ttype) {
1620  switch (ttype) {
1621  case Texture::TT_1d_texture:
1622  return "1D";
1623  break;
1624  case Texture::TT_2d_texture:
1625  return "2D";
1626  break;
1627  case Texture::TT_3d_texture:
1628  return "3D";
1629  break;
1630  case Texture::TT_cube_map:
1631  return "CUBE";
1632  break;
1633  case Texture::TT_2d_texture_array:
1634  return "2DARRAY";
1635  break;
1636  default:
1637  pgraph_cat.error() << "Unsupported texture type!\n";
1638  return "2D";
1639  }
1640 }
CombineSource get_combine_alpha_source2() const
Get source2 of combine_alpha_mode.
Definition: textureStage.I:667
A light shining from infinitely far away in a particular direction, like sunlight.
Fog * get_fog() const
If the FogAttrib is not an &#39;off&#39; FogAttrib, returns the fog that is associated.
Definition: fogAttrib.I:45
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
Mode get_mode() const
Returns the colorBlend mode.
This is our own Panda specialization on the default STL map.
Definition: pmap.h:52
bool auto_shader() const
If true, then this ShaderAttrib does not contain an explicit shader - instead, it requests the automa...
Definition: shaderAttrib.I:81
LightRampMode get_mode() const
Returns the LightRampAttrib mode.
bool get_local() const
Returns the local viewer flag.
Definition: material.I:242
Material * get_material() const
If the MaterialAttrib is not an &#39;off&#39; MaterialAttrib, returns the material that is associated...
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:60
LColor get_color() const
return the color for this stage
Definition: textureStage.I:238
CombineOperand get_combine_alpha_operand0() const
Get operand0 of combine_alpha_mode.
Definition: textureStage.I:637
int get_rgb_scale() const
See set_rgb_scale().
Definition: textureStage.I:264
TextureType get_texture_type() const
Returns the overall interpretation of the texture.
Definition: texture.I:859
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:236
Indicates which, if any, material should be applied to geometry.
bool has_ambient() const
Returns true if the ambient color has been explicitly set for this material, false otherwise...
Definition: material.I:70
virtual ~ShaderGenerator()
Destroy a ShaderGenerator.
This controls the enabling of transparency.
PN_stdfloat get_threshold(int n) const
Returns the nth threshold level.
Mode get_mode() const
Returns the transparency mode.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
PandaCompareFunc get_mode() const
Returns the alpha write mode.
Definition: shader.h:50
int get_outputs() const
Returns the AuxBitplaneAttrib output bits.
A light source that seems to illuminate all points in space at once.
Definition: ambientLight.h:29
This functions similarly to a LightAttrib.
int get_alpha_scale() const
See set_alpha_scale().
Definition: textureStage.I:289
A Light Ramp is any unary operator that takes a rendered pixel as input, and adjusts the brightness o...
Mode get_mode() const
Return the mode of this stage.
Definition: textureStage.I:206
CombineOperand get_combine_rgb_operand1() const
Get operand1 of combine_rgb_mode.
Definition: textureStage.I:493
static Material * get_default()
Returns the default material.
Definition: material.I:56
Type get_color_type() const
Returns the type of color specified by this ColorAttrib.
Definition: colorAttrib.I:46
CombineSource get_combine_rgb_source1() const
Get source1 of combine_rgb_mode.
Definition: textureStage.I:483
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:34
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
const LColor & get_diffuse() const
Returns the diffuse color setting, if it has been set.
Definition: material.I:119
Applies a Fog to the geometry at and below this node.
Definition: fogAttrib.h:27
Modern frame buffers can have &#39;aux&#39; bitplanes, which are additional bitplanes above and beyond the st...
const LColor & get_ambient() const
Returns the ambient color setting, if it has been set.
Definition: material.I:82
Texture * get_on_texture(TextureStage *stage) const
Returns the texture associated with the indicated stage, or NULL if no texture is associated...
bool uses_last_saved_result() const
Returns true if the TextureStage makes use of the CS_primary_color combine source.
Definition: textureStage.I:723
int get_num_on_planes() const
Returns the number of planes that are enabled by the attribute.
CombineSource get_combine_alpha_source0() const
Get source0 of combine_alpha_mode.
Definition: textureStage.I:627
bool uses_primary_color() const
Returns true if the TextureStage makes use of the CS_primary_color combine source.
Definition: textureStage.I:712
ShaderGenerator(GraphicsStateGuardianBase *gsg, GraphicsOutputBase *host)
Create a ShaderGenerator.
CombineSource get_combine_rgb_source2() const
Get source2 of combine_rgb_mode.
Definition: textureStage.I:503
Specifies how atmospheric fog effects are applied to geometry.
Definition: fog.h:46
CombineOperand get_combine_rgb_operand0() const
Get operand0 of combine_rgb_mode.
Definition: textureStage.I:473
A light originating from a single point in space, and shining in a particular direction, with a cone-shaped falloff.
Definition: spotlight.h:37
bool has_specular() const
Returns true if the specular color has been explicitly set for this material, false otherwise...
Definition: material.I:144
TextureStage * get_on_stage(int n) const
Returns the nth stage turned on by the attribute, sorted in render order.
InternalName * get_texcoord_name() const
See set_texcoord_name.
Definition: textureStage.I:148
CombineMode get_combine_alpha_mode() const
Get combine_alpha_mode.
Definition: textureStage.I:605
Enables or disables writing of pixel to framebuffer based on its alpha value relative to a reference ...
CombineOperand get_combine_alpha_operand1() const
Get operand1 of combine_alpha_mode.
Definition: textureStage.I:657
Defines the way an object appears in the presence of lighting.
Definition: material.h:34
void ref() const
Explicitly increments the reference count.
PN_stdfloat get_level(int n) const
Returns the nth lighting level.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
int get_num_on_lights() const
Returns the number of lights that are turned on by the attribute.
Definition: lightAttrib.I:49
PN_stdfloat get_reference_alpha() const
Returns the alpha reference value.
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
Applies a transform matrix to UV&#39;s before they are rendered.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
This specifies how colors are blended into the frame buffer, for special effects. ...
CombineMode get_combine_rgb_mode() const
Get the combine_rgb_mode.
Definition: textureStage.I:441
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:284
CombineSource get_combine_rgb_source0() const
Get source0 of combine_rgb_mode.
Definition: textureStage.I:463
A derivative of Light and of Camera.
Definition: lightLensNode.h:35
bool is_off() const
Returns true if the MaterialAttrib is an &#39;off&#39; MaterialAttrib, indicating that it should disable the ...
int get_num_on_stages() const
Returns the number of stages that are turned on by the attribute.
Definition: textureAttrib.I:91
Indicates what color should be applied to renderable geometry.
Definition: colorAttrib.h:30
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
CombineOperand get_combine_rgb_operand2() const
Get operand2 of combine_rgb_mode.
Definition: textureStage.I:513
CombineSource get_combine_alpha_source1() const
Get source1 of combine_alpha_mode.
Definition: textureStage.I:647
CombineOperand get_combine_alpha_operand2() const
Get operand2 of combine_alpha_mode.
Definition: textureStage.I:677
An abstract base class for GraphicsOutput, for all the usual reasons.
const LColor & get_emission() const
Returns the emission color setting, if it has been set.
Definition: material.I:193
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
bool has_diffuse() const
Returns true if the diffuse color has been explicitly set for this material, false otherwise...
Definition: material.I:107
bool is_off() const
Returns true if the FogAttrib is an &#39;off&#39; FogAttrib, indicating that it should disable fog...
Definition: fogAttrib.I:33
bool has_emission() const
Returns true if the emission color has been explicitly set for this material, false otherwise...
Definition: material.I:181
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:38
Computes texture coordinates for geometry automatically based on vertex position and/or normal...
Definition: texGenAttrib.h:36
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
const LColor & get_specular() const
Returns the specular color setting, if it has been set.
Definition: material.I:156
A light originating from a single point in space, and shining in all directions.
Definition: pointLight.h:27
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
Definition: lightAttrib.h:33
NodePath get_on_light(int n) const
Returns the nth light turned on by the attribute, sorted in render order.
Definition: lightAttrib.I:60
bool get_saved_result() const
Returns the current setting of the saved_result flag.
Definition: textureStage.I:321