Panda3D

shaderGenerator.cxx

00001 // Filename: shaderGenerator.cxx
00002 // Created by: jyelon (15Dec07)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "shaderGenerator.h"
00016 #include "renderState.h"
00017 #include "shaderAttrib.h"
00018 #include "auxBitplaneAttrib.h"
00019 #include "alphaTestAttrib.h"
00020 #include "colorBlendAttrib.h"
00021 #include "transparencyAttrib.h"
00022 #include "textureAttrib.h"
00023 #include "colorAttrib.h"
00024 #include "lightAttrib.h"
00025 #include "materialAttrib.h"
00026 #include "lightRampAttrib.h"
00027 #include "texMatrixAttrib.h"
00028 #include "texGenAttrib.h"
00029 #include "colorScaleAttrib.h"
00030 #include "fogAttrib.h"
00031 #include "texture.h"
00032 #include "ambientLight.h"
00033 #include "directionalLight.h"
00034 #include "pointLight.h"
00035 #include "spotlight.h"
00036 #include "lightLensNode.h"
00037 #include "lvector4.h"
00038 
00039 TypeHandle ShaderGenerator::_type_handle;
00040 
00041 ////////////////////////////////////////////////////////////////////
00042 //     Function: ShaderGenerator::Constructor
00043 //       Access: Published
00044 //  Description: Create a ShaderGenerator.  This has no state,
00045 //               except possibly to cache certain results.
00046 //               The parameter that must be passed is the GSG to
00047 //               which the shader generator belongs.
00048 ////////////////////////////////////////////////////////////////////
00049 ShaderGenerator::
00050 ShaderGenerator(PT(GraphicsStateGuardianBase) gsg, PT(GraphicsOutputBase) host) :
00051   _gsg (gsg), _host (host) {
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: ShaderGenerator::Destructor
00056 //       Access: Published, Virtual
00057 //  Description: Destroy a ShaderGenerator.
00058 ////////////////////////////////////////////////////////////////////
00059 ShaderGenerator::
00060 ~ShaderGenerator() {
00061 }
00062 
00063 ////////////////////////////////////////////////////////////////////
00064 //     Function: ShaderGenerator::reset_register_allocator
00065 //       Access: Protected
00066 //  Description: Clears the register allocator.  Initially, the pool
00067 //               of available registers is empty.  You have to add
00068 //               some if you want there to be any.
00069 ////////////////////////////////////////////////////////////////////
00070 void ShaderGenerator::
00071 reset_register_allocator() {
00072   _vtregs_used = 0;
00073   _vcregs_used = 0;
00074   _ftregs_used = 0;
00075   _fcregs_used = 0;
00076 }
00077 
00078 ////////////////////////////////////////////////////////////////////
00079 //     Function: ShaderGenerator::alloc_vreg
00080 //       Access: Protected
00081 //  Description: Allocate a vreg.
00082 ////////////////////////////////////////////////////////////////////
00083 INLINE char *ShaderGenerator::
00084 alloc_vreg() {
00085   switch (_vtregs_used) {
00086   case  0: _vtregs_used += 1; return (char*)"TEXCOORD0";
00087   case  1: _vtregs_used += 1; return (char*)"TEXCOORD1";
00088   case  2: _vtregs_used += 1; return (char*)"TEXCOORD2";
00089   case  3: _vtregs_used += 1; return (char*)"TEXCOORD3";
00090   case  4: _vtregs_used += 1; return (char*)"TEXCOORD4";
00091   case  5: _vtregs_used += 1; return (char*)"TEXCOORD5";
00092   case  6: _vtregs_used += 1; return (char*)"TEXCOORD6";
00093   case  7: _vtregs_used += 1; return (char*)"TEXCOORD7";
00094   case  8: _vtregs_used += 1; return (char*)"TEXCOORD8";
00095   case  9: _vtregs_used += 1; return (char*)"TEXCOORD9";
00096   case 10: _vtregs_used += 1; return (char*)"TEXCOORD10";
00097   case 11: _vtregs_used += 1; return (char*)"TEXCOORD11";
00098   case 12: _vtregs_used += 1; return (char*)"TEXCOORD12";
00099   case 13: _vtregs_used += 1; return (char*)"TEXCOORD13";
00100   case 14: _vtregs_used += 1; return (char*)"TEXCOORD14";
00101   case 15: _vtregs_used += 1; return (char*)"TEXCOORD15";
00102   }
00103   switch (_vcregs_used) {
00104   case  0: _vcregs_used += 1; return (char*)"COLOR0";
00105   case  1: _vcregs_used += 1; return (char*)"COLOR1";
00106   case  2: _vcregs_used += 1; return (char*)"COLOR2";
00107   case  3: _vcregs_used += 1; return (char*)"COLOR3";
00108   case  4: _vcregs_used += 1; return (char*)"COLOR4";
00109   case  5: _vcregs_used += 1; return (char*)"COLOR5";
00110   case  6: _vcregs_used += 1; return (char*)"COLOR6";
00111   case  7: _vcregs_used += 1; return (char*)"COLOR7";
00112   case  8: _vcregs_used += 1; return (char*)"COLOR8";
00113   case  9: _vcregs_used += 1; return (char*)"COLOR9";
00114   case 10: _vcregs_used += 1; return (char*)"COLOR10";
00115   case 11: _vcregs_used += 1; return (char*)"COLOR11";
00116   case 12: _vcregs_used += 1; return (char*)"COLOR12";
00117   case 13: _vcregs_used += 1; return (char*)"COLOR13";
00118   case 14: _vcregs_used += 1; return (char*)"COLOR14";
00119   case 15: _vcregs_used += 1; return (char*)"COLOR15";
00120   }
00121   return (char*)"UNKNOWN";
00122 }
00123 
00124 ////////////////////////////////////////////////////////////////////
00125 //     Function: ShaderGenerator::alloc_freg
00126 //       Access: Protected
00127 //  Description: Allocate a freg.
00128 ////////////////////////////////////////////////////////////////////
00129 INLINE char *ShaderGenerator::
00130 alloc_freg() {
00131   switch (_ftregs_used) {
00132   case  0: _ftregs_used += 1; return (char*)"TEXCOORD0";
00133   case  1: _ftregs_used += 1; return (char*)"TEXCOORD1";
00134   case  2: _ftregs_used += 1; return (char*)"TEXCOORD2";
00135   case  3: _ftregs_used += 1; return (char*)"TEXCOORD3";
00136   case  4: _ftregs_used += 1; return (char*)"TEXCOORD4";
00137   case  5: _ftregs_used += 1; return (char*)"TEXCOORD5";
00138   case  6: _ftregs_used += 1; return (char*)"TEXCOORD6";
00139   case  7: _ftregs_used += 1; return (char*)"TEXCOORD7";
00140   case  8: _ftregs_used += 1; return (char*)"TEXCOORD8";
00141   case  9: _ftregs_used += 1; return (char*)"TEXCOORD9";
00142   case 10: _ftregs_used += 1; return (char*)"TEXCOORD10";
00143   case 11: _ftregs_used += 1; return (char*)"TEXCOORD11";
00144   case 12: _ftregs_used += 1; return (char*)"TEXCOORD12";
00145   case 13: _ftregs_used += 1; return (char*)"TEXCOORD13";
00146   case 14: _ftregs_used += 1; return (char*)"TEXCOORD14";
00147   case 15: _ftregs_used += 1; return (char*)"TEXCOORD15";
00148   }
00149   switch (_fcregs_used) {
00150   case  0: _fcregs_used += 1; return (char*)"COLOR0";
00151   case  1: _fcregs_used += 1; return (char*)"COLOR1";
00152   case  2: _fcregs_used += 1; return (char*)"COLOR2";
00153   case  3: _fcregs_used += 1; return (char*)"COLOR3";
00154   case  4: _fcregs_used += 1; return (char*)"COLOR4";
00155   case  5: _fcregs_used += 1; return (char*)"COLOR5";
00156   case  6: _fcregs_used += 1; return (char*)"COLOR6";
00157   case  7: _fcregs_used += 1; return (char*)"COLOR7";
00158   case  8: _fcregs_used += 1; return (char*)"COLOR8";
00159   case  9: _fcregs_used += 1; return (char*)"COLOR9";
00160   case 10: _fcregs_used += 1; return (char*)"COLOR10";
00161   case 11: _fcregs_used += 1; return (char*)"COLOR11";
00162   case 12: _fcregs_used += 1; return (char*)"COLOR12";
00163   case 13: _fcregs_used += 1; return (char*)"COLOR13";
00164   case 14: _fcregs_used += 1; return (char*)"COLOR14";
00165   case 15: _fcregs_used += 1; return (char*)"COLOR15";
00166   }
00167   return (char*)"UNKNOWN";
00168 }
00169 
00170 ////////////////////////////////////////////////////////////////////
00171 //     Function: ShaderGenerator::analyze_renderstate
00172 //       Access: Protected
00173 //  Description: Analyzes the RenderState prior to shader generation.
00174 //               The results of the analysis are stored in instance
00175 //               variables of the Shader Generator.
00176 ////////////////////////////////////////////////////////////////////
00177 void ShaderGenerator::
00178 analyze_renderstate(const RenderState *rs) {
00179   clear_analysis();
00180 
00181   //  verify_enforce_attrib_lock();
00182   _state = rs;
00183   const AuxBitplaneAttrib *aux_bitplane = DCAST(AuxBitplaneAttrib, rs->get_attrib_def(AuxBitplaneAttrib::get_class_slot()));
00184   int outputs = aux_bitplane->get_outputs();
00185 
00186   // Decide whether or not we need alpha testing or alpha blending.
00187 
00188   const AlphaTestAttrib *alpha_test = DCAST(AlphaTestAttrib, rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
00189   if ((alpha_test->get_mode() != RenderAttrib::M_none)&&
00190       (alpha_test->get_mode() != RenderAttrib::M_always)) {
00191     _have_alpha_test = true;
00192   }
00193   const ColorBlendAttrib *color_blend = DCAST(ColorBlendAttrib, rs->get_attrib_def(ColorBlendAttrib::get_class_slot()));
00194   if (color_blend->get_mode() != ColorBlendAttrib::M_none) {
00195     _have_alpha_blend = true;
00196   }
00197   const TransparencyAttrib *transparency = DCAST(TransparencyAttrib, rs->get_attrib_def(TransparencyAttrib::get_class_slot()));
00198   if ((transparency->get_mode() == TransparencyAttrib::M_alpha)||
00199       (transparency->get_mode() == TransparencyAttrib::M_dual)) {
00200     _have_alpha_blend = true;
00201   }
00202 
00203   // Decide what to send to the framebuffer alpha, if anything.
00204 
00205   if (outputs & AuxBitplaneAttrib::ABO_glow) {
00206     if (_have_alpha_blend) {
00207       _calc_primary_alpha = true;
00208       _out_primary_glow = false;
00209       _disable_alpha_write = true;
00210     } else if (_have_alpha_test) {
00211       _calc_primary_alpha = true;
00212       _out_primary_glow = true;
00213       _subsume_alpha_test = true;
00214     } else {
00215       _calc_primary_alpha = false;
00216       _out_primary_glow = true;
00217     }
00218   } else {
00219     if (_have_alpha_blend || _have_alpha_test) {
00220       _calc_primary_alpha = true;
00221     }
00222   }
00223 
00224   // Determine what to put into the aux bitplane.
00225 
00226   _out_aux_normal = (outputs & AuxBitplaneAttrib::ABO_aux_normal) ? true:false;
00227   _out_aux_glow = (outputs & AuxBitplaneAttrib::ABO_aux_glow) ? true:false;
00228   _out_aux_any = (_out_aux_normal || _out_aux_glow);
00229   
00230   if (_out_aux_normal) {
00231     _need_eye_normal = true;
00232   }
00233 
00234   // Count number of textures.
00235 
00236   const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot()));
00237   _num_textures = texture->get_num_on_stages();
00238 
00239   // Determine whether or not vertex colors or flat colors are present.
00240 
00241   const ColorAttrib *color = DCAST(ColorAttrib, rs->get_attrib_def(ColorAttrib::get_class_slot()));
00242   if (color->get_color_type() == ColorAttrib::T_vertex) {
00243     _vertex_colors = true;
00244   } else if (color->get_color_type() == ColorAttrib::T_flat) {
00245     _flat_colors = true;
00246   }
00247 
00248   // Break out the lights by type.
00249 
00250   _shadows = false;
00251   const LightAttrib *la = DCAST(LightAttrib, rs->get_attrib_def(LightAttrib::get_class_slot()));
00252   for (int i=0; i<la->get_num_on_lights(); i++) {
00253     NodePath light = la->get_on_light(i);
00254     nassertv(!light.is_empty());
00255     PandaNode *light_obj = light.node();
00256     nassertv(light_obj != (PandaNode *)NULL);
00257 
00258     if (light_obj->get_type() == AmbientLight::get_class_type()) {
00259       _alights_np.push_back(light);
00260       _alights.push_back((AmbientLight*)light_obj);
00261     }
00262     else if (light_obj->get_type() == DirectionalLight::get_class_type()) {
00263       _dlights_np.push_back(light);
00264       _dlights.push_back((DirectionalLight*)light_obj);
00265       if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) {
00266         _shadows = true;
00267       }
00268     }
00269     else if (light_obj->get_type() == PointLight::get_class_type()) {
00270       _plights_np.push_back(light);
00271       _plights.push_back((PointLight*)light_obj);
00272     }
00273     else if (light_obj->get_type() == Spotlight::get_class_type()) {
00274       _slights_np.push_back(light);
00275       _slights.push_back((Spotlight*)light_obj);
00276       if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) {
00277         _shadows = true;
00278       }
00279     }
00280   }
00281 
00282   // See if there is a normal map, height map, gloss map, or glow map.
00283   // Also check if anything has TexGen.
00284   
00285   const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, rs->get_attrib_def(TexGenAttrib::get_class_slot()));
00286   for (int i=0; i<_num_textures; i++) {
00287     TextureStage *stage = texture->get_on_stage(i);
00288     TextureStage::Mode mode = stage->get_mode();
00289     if ((mode == TextureStage::M_normal)||(mode == TextureStage::M_normal_height)) {
00290       _map_index_normal = i;
00291     }
00292     if ((mode == TextureStage::M_height)||(mode == TextureStage::M_normal_height)) {
00293       _map_index_height = i;
00294     }
00295     if ((mode == TextureStage::M_glow)||(mode == TextureStage::M_modulate_glow)) {
00296       _map_index_glow = i;
00297     }
00298     if ((mode == TextureStage::M_gloss)||(mode == TextureStage::M_modulate_gloss)) {
00299       _map_index_gloss = i;
00300     }
00301     if (mode == TextureStage::M_height) {
00302       _map_height_in_alpha = false;
00303     }
00304     if (mode == TextureStage::M_normal_height) {
00305       _map_height_in_alpha = true;
00306     }
00307     if (tex_gen->has_stage(stage)) {
00308       switch (tex_gen->get_mode(stage)) {
00309         case TexGenAttrib::M_world_position:
00310           _need_world_position = true;
00311           break;
00312         case TexGenAttrib::M_world_normal:
00313           _need_world_normal = true;
00314           break;
00315         case TexGenAttrib::M_eye_position:
00316           _need_eye_position = true;
00317           break;
00318         case TexGenAttrib::M_eye_normal:
00319           _need_eye_normal = true;
00320           break;
00321       }
00322     }
00323   }
00324 
00325   // Determine whether lighting is needed.
00326 
00327   if (la->get_num_on_lights() > 0) {
00328     _lighting = true;
00329     _need_eye_position = true;
00330     _need_eye_normal = true;
00331   }
00332 
00333   // Find the material.
00334 
00335   const MaterialAttrib *material = DCAST(MaterialAttrib, rs->get_attrib_def(MaterialAttrib::get_class_slot()));
00336 
00337   if (!material->is_off()) {
00338     _material = material->get_material();
00339   } else {
00340     _material = Material::get_default();
00341   }
00342 
00343   // Decide which material modes need to be calculated.
00344 
00345   if (_lighting && (_alights.size() > 0)) {
00346     if (_material->has_ambient()) {
00347       Colorf a = _material->get_ambient();
00348       if ((a[0]!=0.0)||(a[1]!=0.0)||(a[2]!=0.0)) {
00349         _have_ambient = true;
00350       }
00351     } else {
00352       _have_ambient = true;
00353     }
00354   }
00355 
00356   if (_lighting && (_dlights.size() + _plights.size() + _slights.size())) {
00357     if (_material->has_diffuse()) {
00358       Colorf d = _material->get_diffuse();
00359       if ((d[0]!=0.0)||(d[1]!=0.0)||(d[2]!=0.0)) {
00360         _have_diffuse = true;
00361       }
00362     } else {
00363       _have_diffuse = true;
00364     }
00365   }
00366 
00367   if (_lighting && (_material->has_emission())) {
00368     Colorf e = _material->get_emission();
00369     if ((e[0]!=0.0)||(e[1]!=0.0)||(e[2]!=0.0)) {
00370       _have_emission = true;
00371     }
00372   }
00373 
00374   if (_lighting && (_dlights.size() + _plights.size() + _slights.size())) {
00375     if (_material->has_specular()) {
00376       Colorf s = _material->get_specular();
00377       if ((s[0]!=0.0)||(s[1]!=0.0)||(s[2]!=0.0)) {
00378         _have_specular = true;
00379       }
00380     } else if (_map_index_gloss >= 0) {
00381       _have_specular = true;
00382     }
00383   }
00384 
00385   // Decide whether to separate ambient and diffuse calculations.
00386 
00387   if (_have_ambient && _have_diffuse) {
00388     if (_material->has_ambient()) {
00389       if (_material->has_diffuse()) {
00390         _separate_ambient_diffuse = _material->get_ambient() != _material->get_diffuse();
00391       } else {
00392         _separate_ambient_diffuse = true;
00393       }
00394     } else {
00395       if (_material->has_diffuse()) {
00396         _separate_ambient_diffuse = true;
00397       } else {
00398         _separate_ambient_diffuse = false;
00399       }
00400     }
00401   }
00402 
00403   const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
00404   if (_lighting &&
00405       (light_ramp->get_mode() != LightRampAttrib::LRT_identity)) {
00406     _separate_ambient_diffuse = true;
00407   }
00408 
00409   // Do we want to use the ARB_shadow extension?
00410   // This also allows us to use hardware shadows / PCF.
00411 
00412   _use_shadow_filter = _gsg->get_supports_shadow_filter();
00413 
00414   // Does the shader need material properties as input?
00415 
00416   _need_material_props =
00417     (_have_ambient  && (_material->has_ambient()))||
00418     (_have_diffuse  && (_material->has_diffuse()))||
00419     (_have_emission && (_material->has_emission()))||
00420     (_have_specular && (_material->has_specular()));
00421 
00422   // Check for clip planes.
00423 
00424   const ClipPlaneAttrib *clip_plane = DCAST(ClipPlaneAttrib, rs->get_attrib_def(ClipPlaneAttrib::get_class_slot()));
00425   _num_clip_planes = clip_plane->get_num_on_planes();
00426   if (_num_clip_planes > 0) {
00427     _need_world_position = true;
00428   }
00429 
00430   // Check for unimplemented features and issue warnings.
00431   const FogAttrib *fog = DCAST(FogAttrib, rs->get_attrib_def(FogAttrib::get_class_slot()));
00432   if (!fog->is_off()) {
00433     pgraph_cat.error() << "Shader Generator does not support Fog yet.\n";
00434   }
00435 }
00436 
00437 ////////////////////////////////////////////////////////////////////
00438 //     Function: ShaderGenerator::clear_analysis
00439 //       Access: Protected
00440 //  Description: Called after analyze_renderstate to discard all
00441 //               the results of the analysis.  This is generally done
00442 //               after shader generation is complete.
00443 ////////////////////////////////////////////////////////////////////
00444 void ShaderGenerator::
00445 clear_analysis() {
00446   _vertex_colors = false;
00447   _flat_colors = false;
00448   _lighting = false;
00449   _shadows = false;
00450   _have_ambient = false;
00451   _have_diffuse = false;
00452   _have_emission = false;
00453   _have_specular = false;
00454   _separate_ambient_diffuse = false;
00455   _map_index_normal = -1;
00456   _map_index_glow = -1;
00457   _map_index_gloss = -1;
00458   _map_index_height = -1;
00459   _map_height_in_alpha = false;
00460   _calc_primary_alpha = false;
00461   _have_alpha_test = false;
00462   _have_alpha_blend = false;
00463   _subsume_alpha_test = false;
00464   _disable_alpha_write = false;
00465   _num_clip_planes = 0;
00466   _use_shadow_filter = false;
00467   _out_primary_glow  = false;
00468   _out_aux_normal   = false;
00469   _out_aux_glow     = false;
00470   _out_aux_any      = false;
00471   _material = (Material*)NULL;
00472   _need_material_props = false;
00473   _need_world_position = false;
00474   _need_world_normal = false;
00475   _need_eye_position = false;
00476   _need_eye_normal = false;
00477   _alights.clear();
00478   _dlights.clear();
00479   _plights.clear();
00480   _slights.clear();
00481   _alights_np.clear();
00482   _dlights_np.clear();
00483   _plights_np.clear();
00484   _slights_np.clear();
00485 }
00486 
00487 ////////////////////////////////////////////////////////////////////
00488 //     Function: ShaderGenerator::create_shader_attrib
00489 //       Access: Protected
00490 //  Description: Creates a ShaderAttrib given a generated shader's
00491 //               body.  Also inserts the lights into the shader
00492 //               attrib.
00493 ////////////////////////////////////////////////////////////////////
00494 CPT(RenderAttrib) ShaderGenerator::
00495 create_shader_attrib(const string &txt) {
00496   PT(Shader) shader = Shader::make(txt);
00497   CPT(RenderAttrib) shattr = ShaderAttrib::make();
00498   shattr=DCAST(ShaderAttrib, shattr)->set_shader(shader);
00499   if (_lighting) {
00500     for (int i=0; i<(int)_alights.size(); i++) {
00501       shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("alight", i), _alights_np[i]);
00502     }
00503     for (int i=0; i<(int)_dlights.size(); i++) {
00504       shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("dlight", i), _dlights_np[i]);
00505       if (_shadows && _dlights[i]->_shadow_caster) {
00506         PT(Texture) tex = update_shadow_buffer(_dlights_np[i]);
00507         if (tex == NULL) {
00508           pgraph_cat.error() << "Failed to create shadow buffer for DirectionalLight '" << _dlights[i]->get_name() << "'!\n";
00509         }
00510         shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("dlighttex", i), tex);
00511       } else {
00512         _dlights[i]->clear_shadow_buffers();
00513       }
00514     }
00515     for (int i=0; i<(int)_plights.size(); i++) {
00516       shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("plight", i), _plights_np[i]);
00517     }
00518     for (int i=0; i<(int)_slights.size(); i++) {
00519       shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("slight", i), _slights_np[i]);
00520       if (_shadows && _slights[i]->_shadow_caster) {
00521         PT(Texture) tex = update_shadow_buffer(_slights_np[i]);
00522         if (tex == NULL) {
00523           pgraph_cat.error() << "Failed to create shadow buffer for Spotlight '" << _slights[i]->get_name() << "'!\n";
00524         }
00525         shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("slighttex", i), tex);
00526       } else {
00527         _slights[i]->clear_shadow_buffers();
00528       }
00529     }
00530   }
00531   return shattr;
00532 }
00533 
00534 ////////////////////////////////////////////////////////////////////
00535 //     Function: ShaderGenerator::update_shadow_buffer
00536 //       Access: Protected, Virtual
00537 //  Description: Updates the depth buffer of the specified light,
00538 //               if it is configured to cast shadows.
00539 //               Only call this function for DirectionalLights
00540 //               and Spotlights. Returns the depth texture.
00541 ////////////////////////////////////////////////////////////////////
00542 PT(Texture) ShaderGenerator::
00543 update_shadow_buffer(NodePath light_np) {
00544   // Make sure everything is valid.
00545   nassertr(light_np.node()->is_of_type(DirectionalLight::get_class_type()) ||
00546            light_np.node()->is_of_type(Spotlight::get_class_type()), NULL);
00547   PT(LightLensNode) light = DCAST(LightLensNode, light_np.node());
00548   if (light == NULL || !light->_shadow_caster) {
00549     return NULL;
00550   }
00551   
00552   // See if we already have a buffer. If not, create one.
00553   PT(Texture) tex;
00554   if (light->_sbuffers.count(_gsg) == 0) {
00555     // Nope, the light doesn't have a buffer for our GSG. Make one.
00556     tex = _gsg->make_shadow_buffer(light_np, _host);
00557   } else {
00558     // There's already a buffer - use that.
00559     tex = light->_sbuffers[_gsg]->get_texture();
00560   }
00561   nassertr(tex != NULL, NULL);
00562 
00563   return tex;
00564 }
00565 
00566 ////////////////////////////////////////////////////////////////////
00567 //     Function: ShaderGenerator::synthesize_shader
00568 //       Access: Published, Virtual
00569 //  Description: This is the routine that implements the next-gen
00570 //               fixed function pipeline by synthesizing a shader.
00571 //               It also takes care of setting up any buffers
00572 //               needed to produce the requested effects.
00573 //
00574 //               Currently supports:
00575 //               - flat colors
00576 //               - vertex colors
00577 //               - lighting
00578 //               - normal maps, but not multiple
00579 //               - gloss maps, but not multiple
00580 //               - glow maps, but not multiple
00581 //               - materials, but not updates to materials
00582 //               - 2D textures
00583 //               - all texture stage modes, including combine modes
00584 //               - color scale attrib
00585 //               - light ramps (for cartoon shading)
00586 //               - shadow mapping
00587 //               - most texgen modes
00588 //               - texmatrix
00589 //               - 1D/2D/3D textures, cube textures
00590 //
00591 //               Not yet supported:
00592 //               - dot3_rgb and dot3_rgba combine modes
00593 //               - fog
00594 //
00595 //               Potential optimizations
00596 //               - omit attenuation calculations if attenuation off
00597 //
00598 ////////////////////////////////////////////////////////////////////
00599 CPT(RenderAttrib) ShaderGenerator::
00600 synthesize_shader(const RenderState *rs) {
00601   analyze_renderstate(rs);
00602   reset_register_allocator();
00603 
00604   pgraph_cat.info() << "Generating shader for render state " << rs << "\n";
00605 
00606   // These variables will hold the results of register allocation.
00607 
00608   char *normal_vreg = 0;
00609   char *ntangent_vreg = 0;
00610   char *ntangent_freg = 0;
00611   char *nbinormal_vreg = 0;
00612   char *nbinormal_freg = 0;
00613   char *htangent_vreg = 0;
00614   char *hbinormal_vreg = 0;
00615   pvector<char *> texcoord_vreg;
00616   pvector<char *> texcoord_freg;
00617   pvector<char *> tslightvec_freg;
00618   char *world_position_freg = 0;
00619   char *world_normal_freg = 0;
00620   char *eye_position_freg = 0;
00621   char *eye_normal_freg = 0;
00622 
00623   if (_vertex_colors) {
00624     _vcregs_used = 1;
00625     _fcregs_used = 1;
00626   }
00627 
00628   // Generate the shader's text.
00629 
00630   ostringstream text;
00631 
00632   text << "//Cg\n";
00633 
00634   text << "void vshader(\n";
00635   const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot()));
00636   const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, rs->get_attrib_def(TexGenAttrib::get_class_slot()));
00637   for (int i=0; i<_num_textures; i++) {
00638     texcoord_vreg.push_back(alloc_vreg());
00639     texcoord_freg.push_back(alloc_freg());
00640     text << "\t in float4 vtx_texcoord" << i << " : " << texcoord_vreg[i] << ",\n";
00641     text << "\t out float4 l_texcoord" << i << " : " << texcoord_freg[i] << ",\n";
00642   }
00643   if (_vertex_colors) {
00644     text << "\t in float4 vtx_color : COLOR,\n";
00645     text << "\t out float4 l_color : COLOR,\n";
00646   }
00647   if (_need_world_position || _need_world_normal) {
00648     text << "\t uniform float4x4 trans_model_to_world,\n";
00649   }
00650   if (_need_world_position) {
00651     world_position_freg = alloc_freg();
00652     text << "\t out float4 l_world_position : " << world_position_freg << ",\n";
00653   }
00654   if (_need_world_normal) {
00655     world_normal_freg = alloc_freg();
00656     text << "\t out float4 l_world_normal : " << world_normal_freg << ",\n";
00657   }
00658   if (_need_eye_position) {
00659     text << "\t uniform float4x4 trans_model_to_view,\n";
00660     eye_position_freg = alloc_freg();
00661     text << "\t out float4 l_eye_position : " << eye_position_freg << ",\n";
00662   }
00663   if (_need_eye_normal) {
00664     eye_normal_freg = alloc_freg();
00665     text << "\t uniform float4x4 tpose_view_to_model,\n";
00666     text << "\t out float4 l_eye_normal : " << eye_normal_freg << ",\n";
00667   }
00668   if (_map_index_height >= 0 || _need_world_normal || _need_eye_normal) {
00669     normal_vreg = alloc_vreg();
00670     text << "\t in float4 vtx_normal : " << normal_vreg << ",\n";
00671   }
00672   if (_map_index_height >= 0) {
00673     htangent_vreg = alloc_vreg();
00674     hbinormal_vreg = alloc_vreg();
00675     if (_map_index_normal == _map_index_height) {
00676       ntangent_vreg = htangent_vreg;
00677       nbinormal_vreg = hbinormal_vreg;
00678     }
00679     text << "\t in float4 vtx_tangent" << _map_index_height << " : " << htangent_vreg << ",\n";
00680     text << "\t in float4 vtx_binormal" << _map_index_height << " : " << hbinormal_vreg << ",\n";
00681     text << "\t uniform float4 mspos_view,\n";
00682     text << "\t out float3 l_eyevec,\n";
00683   }
00684   if (_lighting) {
00685     if (_map_index_normal >= 0) {
00686       // If we had a height map and it used the same stage, that means we already have those inputs.
00687       if (_map_index_normal != _map_index_height) {
00688         ntangent_vreg = alloc_vreg();
00689         nbinormal_vreg = alloc_vreg();
00690         text << "\t in float4 vtx_tangent" << _map_index_normal << " : " << ntangent_vreg << ",\n";
00691         text << "\t in float4 vtx_binormal" << _map_index_normal << " : " << nbinormal_vreg << ",\n";
00692       }
00693       ntangent_freg = alloc_freg();
00694       nbinormal_freg = alloc_freg();
00695       text << "\t out float4 l_tangent : " << ntangent_freg << ",\n";
00696       text << "\t out float4 l_binormal : " << nbinormal_freg << ",\n";
00697     }
00698     if (_shadows) {
00699       for (int i=0; i<(int)_dlights.size(); i++) {
00700         if (_dlights[i]->_shadow_caster) {
00701           text << "\t uniform float4x4 trans_model_to_clip_of_dlight" << i << ",\n";
00702           text << "\t out float4 l_dlightcoord" << i << ",\n";
00703         }
00704       }
00705       for (int i=0; i<(int)_slights.size(); i++) {
00706         if (_slights[i]->_shadow_caster) {
00707           text << "\t uniform float4x4 trans_model_to_clip_of_slight" << i << ",\n";
00708           text << "\t out float4 l_slightcoord" << i << ",\n";
00709         }
00710       }
00711     }
00712   }
00713   text << "\t float4 vtx_position : POSITION,\n";
00714   text << "\t out float4 l_position : POSITION,\n";
00715   text << "\t uniform float4x4 mat_modelproj\n";
00716   text << ") {\n";
00717 
00718   text << "\t l_position = mul(mat_modelproj, vtx_position);\n";
00719   if (_need_world_position) {
00720     text << "\t l_world_position = mul(trans_model_to_world, vtx_position);\n";
00721   }
00722   if (_need_world_normal) {
00723     text << "\t l_world_normal = mul(trans_model_to_world, vtx_normal);\n";
00724   }
00725   if (_need_eye_position) {
00726     text << "\t l_eye_position = mul(trans_model_to_view, vtx_position);\n";
00727   }
00728   if (_need_eye_normal) {
00729     text << "\t l_eye_normal.xyz = mul((float3x3)tpose_view_to_model, vtx_normal.xyz);\n";
00730     text << "\t l_eye_normal.w = 0;\n";
00731   }
00732   for (int i=0; i<_num_textures; i++) {
00733     if (!tex_gen->has_stage(texture->get_on_stage(i))) {
00734       text << "\t l_texcoord" << i << " = vtx_texcoord" << i << ";\n";
00735     }
00736   }
00737   if (_vertex_colors) {
00738     text << "\t l_color = vtx_color;\n";
00739   }
00740   if (_lighting && (_map_index_normal >= 0)) {
00741     text << "\t l_tangent.xyz = mul((float3x3)tpose_view_to_model, vtx_tangent" << _map_index_normal << ".xyz);\n";
00742     text << "\t l_tangent.w = 0;\n";
00743     text << "\t l_binormal.xyz = mul((float3x3)tpose_view_to_model, -vtx_binormal" << _map_index_normal << ".xyz);\n";
00744     text << "\t l_binormal.w = 0;\n";
00745   }
00746   if (_shadows) {
00747     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";
00748     for (int i=0; i<(int)_dlights.size(); i++) {
00749       if (_dlights[i]->_shadow_caster) {
00750         text << "\t l_dlightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_dlight" << i << ", vtx_position));\n";
00751       }
00752     }
00753     for (int i=0; i<(int)_slights.size(); i++) {
00754       if (_slights[i]->_shadow_caster) {
00755         text << "\t l_slightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_slight" << i << ", vtx_position));\n";
00756       }
00757     }
00758   }
00759   if (_map_index_height >= 0) {
00760     text << "\t float3 eyedir = mspos_view.xyz - vtx_position.xyz;\n";
00761     text << "\t l_eyevec.x = dot(vtx_tangent" << _map_index_height << ".xyz, eyedir);\n";
00762     text << "\t l_eyevec.y = dot(vtx_binormal" << _map_index_height << ".xyz, eyedir);\n";
00763     text << "\t l_eyevec.z = dot(vtx_normal.xyz, eyedir);\n";
00764     text << "\t l_eyevec = normalize(l_eyevec);\n";
00765   }
00766   text << "}\n\n";
00767 
00768   text << "void fshader(\n";
00769   if (_need_world_position) {
00770     text << "\t in float4 l_world_position : " << world_position_freg << ",\n";
00771   }
00772   if (_need_world_normal) {
00773     text << "\t in float4 l_world_normal : " << world_normal_freg << ",\n";
00774   }
00775   if (_need_eye_position) { 
00776     text << "\t in float4 l_eye_position : " << eye_position_freg << ",\n";
00777   }
00778   if (_need_eye_normal) {
00779     text << "\t in float4 l_eye_normal : " << eye_normal_freg << ",\n";
00780   }
00781   const TexMatrixAttrib *tex_matrix = DCAST(TexMatrixAttrib, rs->get_attrib_def(TexMatrixAttrib::get_class_slot()));
00782   for (int i=0; i<_num_textures; i++) {
00783     TextureStage *stage = texture->get_on_stage(i);
00784     Texture *tex = texture->get_on_texture(stage);
00785     nassertr(tex != NULL, NULL);
00786     text << "\t uniform sampler" << texture_type_as_string(tex->get_texture_type()) << " tex_" << i << ",\n";
00787     if (!tex_gen->has_stage(stage)) {
00788       text << "\t in float4 l_texcoord" << i << " : " << texcoord_freg[i] << ",\n";
00789     }
00790     if (tex_matrix->has_stage(stage)) {
00791       text << "\t uniform float4x4 texmat_" << i << ",\n";
00792     }
00793   }
00794   if (_lighting && (_map_index_normal >= 0)) {
00795     text << "\t in float3 l_tangent : " << ntangent_freg << ",\n";
00796     text << "\t in float3 l_binormal : " << nbinormal_freg << ",\n";
00797   }
00798   if (_lighting) {
00799     for (int i=0; i<(int)_alights.size(); i++) {
00800       text << "\t uniform float4 alight_alight" << i << ",\n";
00801     }
00802     for (int i=0; i<(int)_dlights.size(); i++) {
00803       text << "\t uniform float4x4 dlight_dlight" << i << "_rel_view,\n";
00804       if (_shadows && _dlights[i]->_shadow_caster) {
00805         if (_use_shadow_filter) {
00806           text << "\t uniform sampler2DShadow k_dlighttex" << i << ",\n";
00807         } else {
00808           text << "\t uniform sampler2D k_dlighttex" << i << ",\n";
00809         }
00810         text << "\t float4 l_dlightcoord" << i << ",\n";
00811       }
00812     }
00813     for (int i=0; i<(int)_plights.size(); i++) {
00814       text << "\t uniform float4x4 plight_plight" << i << "_rel_view,\n";
00815     }
00816     for (int i=0; i<(int)_slights.size(); i++) {
00817       text << "\t uniform float4x4 slight_slight" << i << "_rel_view,\n";
00818       text << "\t uniform float4   satten_slight" << i << ",\n";
00819       if (_shadows && _slights[i]->_shadow_caster) {
00820         if (_use_shadow_filter) {
00821           text << "\t uniform sampler2DShadow k_slighttex" << i << ",\n";
00822         } else {
00823           text << "\t uniform sampler2D k_slighttex" << i << ",\n";
00824         }
00825         text << "\t float4 l_slightcoord" << i << ",\n";
00826       }
00827     }
00828     if (_need_material_props) {
00829       text << "\t uniform float4x4 attr_material,\n";
00830     }
00831     if (_have_specular) {
00832       if (_material->get_local()) {
00833         text << "\t uniform float4 mspos_view,\n";
00834       } else {
00835         text << "\t uniform float4 row1_view_to_model,\n";
00836       }
00837     }
00838   }
00839   if (_map_index_height >= 0) {
00840     text << "\t float3 l_eyevec,\n";
00841   }
00842   if (_out_aux_any) {
00843     text << "\t out float4 o_aux : COLOR1,\n";
00844   }
00845   text << "\t out float4 o_color : COLOR0,\n";
00846   if (_vertex_colors) {
00847     text << "\t in float4 l_color : COLOR,\n";
00848   } else {
00849     text << "\t uniform float4 attr_color,\n";
00850   }
00851   for (int i=0; i<_num_clip_planes; ++i) {
00852     text << "\t uniform float4 clipplane_" << i << ",\n";
00853   }
00854   text << "\t uniform float4 attr_colorscale\n";
00855   text << ") {\n";
00856   // Clipping first!
00857   for (int i=0; i<_num_clip_planes; ++i) {
00858     text << "\t if (l_world_position.x * clipplane_" << i << ".x + l_world_position.y ";
00859     text << "* clipplane_" << i << ".y + l_world_position.z * clipplane_" << i << ".z + clipplane_" << i << ".w <= 0) {\n";
00860     text << "\t discard;\n";
00861     text << "\t }\n";
00862   }
00863   text << "\t float4 result;\n";
00864   if (_out_aux_any) {
00865     text << "\t o_aux = float4(0,0,0,0);\n";
00866   }
00867   // Now generate any texture coordinates according to TexGenAttrib. If it has a TexMatrixAttrib, also transform them.
00868   for (int i=0; i<_num_textures; i++) {
00869     TextureStage *stage = texture->get_on_stage(i);
00870     if (tex_gen != NULL && tex_gen->has_stage(stage)) {
00871       switch (tex_gen->get_mode(stage)) {
00872         case TexGenAttrib::M_world_position:
00873           text << "\t float4 l_texcoord" << i << " = l_world_position;\n";
00874           break;
00875         case TexGenAttrib::M_world_normal:
00876           text << "\t float4 l_texcoord" << i << " = l_world_normal;\n";
00877           break;
00878         case TexGenAttrib::M_eye_position:
00879           text << "\t float4 l_texcoord" << i << " = l_eye_position;\n";
00880           break;
00881         case TexGenAttrib::M_eye_normal:
00882           text << "\t float4 l_texcoord" << i << " = l_eye_normal;\n";
00883           text << "\t l_texcoord" << i << ".w = 1.0f;\n";
00884           break;
00885         default:
00886           pgraph_cat.error() << "Unsupported TexGenAttrib mode\n";
00887           text << "\t float4 l_texcoord" << i << " = float4(0, 0, 0, 0);\n";
00888       }
00889     }
00890     if (tex_matrix != NULL && tex_matrix->has_stage(stage)) {
00891       text << "\t l_texcoord" << i << " = mul(texmat_" << i << ", l_texcoord" << i << ");\n";
00892       text << "\t l_texcoord" << i << ".xyz /= l_texcoord" << i << ".w;\n";
00893     }
00894   }
00895   text << "\t // Fetch all textures.\n";
00896   if (_map_index_height >= 0 && parallax_mapping_samples > 0) {
00897     Texture *tex = texture->get_on_texture(texture->get_on_stage(_map_index_height));
00898     nassertr(tex != NULL, NULL);
00899     text << "\t float4 tex" << _map_index_height << " = tex" << texture_type_as_string(tex->get_texture_type());
00900     text << "(tex_" << _map_index_height << ", l_texcoord" << _map_index_height << ".";
00901     switch(tex->get_texture_type()) {
00902       case Texture::TT_cube_map:
00903       case Texture::TT_3d_texture: text << "xyz"; break;
00904       case Texture::TT_2d_texture: text << "xy";  break;
00905       case Texture::TT_1d_texture: text << "x";   break;
00906     }
00907     text << ");\n\t float3 parallax_offset = l_eyevec.xyz * (tex" << _map_index_height;
00908     if (_map_height_in_alpha) {
00909       text << ".aaa";
00910     } else {
00911       text << ".rgb";
00912     }
00913     text << " * 2.0 - 1.0) * " << parallax_mapping_scale << ";\n";
00914     // Additional samples
00915     for (int i=0; i<parallax_mapping_samples-1; i++) {
00916       text << "\t parallax_offset = l_eyevec.xyz * (parallax_offset + (tex" << _map_index_height;
00917       if (_map_height_in_alpha) {
00918         text << ".aaa";
00919       } else {
00920         text << ".rgb";
00921       }
00922       text << " * 2.0 - 1.0)) * " << 0.5 * parallax_mapping_scale << ";\n";
00923     }
00924   }
00925   for (int i=0; i<_num_textures; i++) {
00926     if (i != _map_index_height) {
00927       Texture *tex = texture->get_on_texture(texture->get_on_stage(i));
00928       nassertr(tex != NULL, NULL);
00929       // Parallax mapping pushes the texture coordinates of the other textures away from the camera.
00930       if (_map_index_height >= 0 && parallax_mapping_samples > 0) {
00931         text << "\t l_texcoord" << i << ".xyz -= parallax_offset;\n";
00932       }
00933       text << "\t float4 tex" << i << " = tex" << texture_type_as_string(tex->get_texture_type());
00934       text << "(tex_" << i << ", l_texcoord" << i << ".";
00935       switch(tex->get_texture_type()) {
00936         case Texture::TT_cube_map:
00937         case Texture::TT_3d_texture: text << "xyz"; break;
00938         case Texture::TT_2d_texture: text << "xy";  break;
00939         case Texture::TT_1d_texture: text << "x";   break;
00940       }
00941       text << ");\n";
00942     }
00943   }
00944   if (_lighting) {
00945     if (_map_index_normal >= 0) {
00946       text << "\t // Translate tangent-space normal in map to view-space.\n";
00947       text << "\t float3 tsnormal = ((float3)tex" << _map_index_normal << " * 2) - 1;\n";
00948       text << "\t l_eye_normal.xyz *= tsnormal.z;\n";
00949       text << "\t l_eye_normal.xyz += l_tangent * tsnormal.x;\n";
00950       text << "\t l_eye_normal.xyz += l_binormal * tsnormal.y;\n";
00951       text << "\t l_eye_normal.xyz  = normalize(l_eye_normal.xyz);\n";
00952     } else {
00953       text << "\t // Correct the surface normal for interpolation effects\n";
00954       text << "\t l_eye_normal.xyz = normalize(l_eye_normal.xyz);\n";
00955     }
00956   }
00957   if (_out_aux_normal) {
00958     text << "\t // Output the camera-space surface normal\n";
00959     text << "\t o_aux.rgb = (l_eye_normal.xyz*0.5) + float3(0.5,0.5,0.5);\n";
00960   }
00961   if (_lighting) {
00962     text << "\t // Begin view-space light calculations\n";
00963     text << "\t float ldist,lattenv,langle;\n";
00964     text << "\t float4 lcolor,lspec,lvec,lpoint,latten,ldir,leye,lhalf;";
00965     if (_shadows) {
00966       text << "\t float lshad;\n";
00967     }
00968     if (_separate_ambient_diffuse) {
00969       if (_have_ambient) {
00970         text << "\t float4 tot_ambient = float4(0,0,0,0);\n";
00971       }
00972       if (_have_diffuse) {
00973         text << "\t float4 tot_diffuse = float4(0,0,0,0);\n";
00974       }
00975     } else {
00976       if (_have_ambient || _have_diffuse) {
00977         text << "\t float4 tot_diffuse = float4(0,0,0,0);\n";
00978       }
00979     }
00980     if (_have_specular) {
00981       text << "\t float4 tot_specular = float4(0,0,0,0);\n";
00982       if (_material->has_specular()) {
00983         text << "\t float shininess = attr_material[3].w;\n";
00984       } else {
00985         text << "\t float shininess = 50; // no shininess specified, using default\n";
00986       }
00987     }
00988     for (int i=0; i<(int)_alights.size(); i++) {
00989       text << "\t // Ambient Light " << i << "\n";
00990       text << "\t lcolor = alight_alight" << i << ";\n";
00991       if (_separate_ambient_diffuse && _have_ambient) {
00992         text << "\t tot_ambient += lcolor;\n";
00993       } else if(_have_diffuse) {
00994         text << "\t tot_diffuse += lcolor;\n";
00995       }
00996     }
00997     for (int i=0; i<(int)_dlights.size(); i++) {
00998       text << "\t // Directional Light " << i << "\n";
00999       text << "\t lcolor = dlight_dlight" << i << "_rel_view[0];\n";
01000       text << "\t lspec  = dlight_dlight" << i << "_rel_view[1];\n";
01001       text << "\t lvec   = dlight_dlight" << i << "_rel_view[2];\n";
01002       text << "\t lcolor *= saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
01003       if (_shadows && _dlights[i]->_shadow_caster) {
01004         if (_use_shadow_filter) {
01005           text << "\t lshad = shadow2DProj(k_dlighttex" << i << ", l_dlightcoord" << i << ").r;\n";
01006         } else {
01007           text << "\t lshad = tex2Dproj(k_dlighttex" << i << ", l_dlightcoord" << i << ").r > l_dlightcoord" << i << ".z / l_dlightcoord" << i << ".w;\n";
01008         }
01009         text << "\t lcolor *= lshad;\n";
01010         text << "\t lspec *= lshad;\n";
01011       }
01012       if (_have_diffuse) {
01013         text << "\t tot_diffuse += lcolor;\n";
01014       }
01015       if (_have_specular) {
01016         if (_material->get_local()) {
01017           text << "\t lhalf  = normalize(lvec - normalize(l_eye_position));\n";
01018         } else {
01019           text << "\t lhalf = dlight_dlight" << i << "_rel_view[3];\n";
01020         }
01021         text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
01022         text << "\t tot_specular += lspec;\n";
01023       }
01024     }
01025     for (int i=0; i<(int)_plights.size(); i++) {
01026       text << "\t // Point Light " << i << "\n";
01027       text << "\t lcolor = plight_plight" << i << "_rel_view[0];\n";
01028       text << "\t lspec  = plight_plight" << i << "_rel_view[1];\n";
01029       text << "\t lpoint = plight_plight" << i << "_rel_view[2];\n";
01030       text << "\t latten = plight_plight" << i << "_rel_view[3];\n";
01031       text << "\t lvec   = lpoint - l_eye_position;\n";
01032       text << "\t ldist = length(float3(lvec));\n";
01033       text << "\t lvec /= ldist;\n";
01034       text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
01035       text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
01036       if (_have_diffuse) {
01037         text << "\t tot_diffuse += lcolor;\n";
01038       }
01039       if (_have_specular) {
01040         if (_material->get_local()) {
01041           text << "\t lhalf  = normalize(lvec - normalize(l_eye_position));\n";
01042         } else {
01043           text << "\t lhalf = normalize(lvec - float4(0,1,0,0));\n";
01044         }
01045         text << "\t lspec *= lattenv;\n";
01046         text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
01047         text << "\t tot_specular += lspec;\n";
01048       }
01049     }
01050     for (int i=0; i<(int)_slights.size(); i++) {
01051       text << "\t // Spot Light " << i << "\n";
01052       text << "\t lcolor = slight_slight" << i << "_rel_view[0];\n";
01053       text << "\t lspec  = slight_slight" << i << "_rel_view[1];\n";
01054       text << "\t lpoint = slight_slight" << i << "_rel_view[2];\n";
01055       text << "\t ldir   = slight_slight" << i << "_rel_view[3];\n";
01056       text << "\t latten = satten_slight" << i << ";\n";
01057       text << "\t lvec   = lpoint - l_eye_position;\n";
01058       text << "\t ldist  = length(float3(lvec));\n";
01059       text << "\t lvec /= ldist;\n";
01060       text << "\t langle = saturate(dot(ldir.xyz, lvec.xyz));\n";
01061       text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
01062       text << "\t lattenv *= pow(langle, latten.w);\n";
01063       text << "\t if (langle < ldir.w) lattenv = 0;\n";
01064       text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
01065       if (_shadows && _slights[i]->_shadow_caster) {
01066         if (_use_shadow_filter) {
01067           text << "\t lshad = shadow2DProj(k_slighttex" << i << ", l_slightcoord" << i << ").r;\n";
01068         } else {
01069           text << "\t lshad = tex2Dproj(k_slighttex" << i << ", l_slightcoord" << i << ").r > l_slightcoord" << i << ".z / l_slightcoord" << i << ".w;\n";
01070         }
01071         text << "\t lcolor *= lshad;\n";
01072         text << "\t lspec *= lshad;\n";
01073       }
01074 
01075       if (_have_diffuse) {
01076         text << "\t tot_diffuse += lcolor;\n";
01077       }
01078       if (_have_specular) {
01079         if (_material->get_local()) {
01080           text << "\t lhalf  = normalize(lvec - normalize(l_eye_position));\n";
01081         } else {
01082           text << "\t lhalf = normalize(lvec - float4(0,1,0,0));\n";
01083         }
01084         text << "\t lspec *= lattenv;\n";
01085         text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
01086         text << "\t tot_specular += lspec;\n";
01087       }
01088     }
01089 
01090     const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
01091     switch (light_ramp->get_mode()) {
01092     case LightRampAttrib::LRT_single_threshold:
01093       {
01094         float t = light_ramp->get_threshold(0);
01095         float l0 = light_ramp->get_level(0);
01096         text << "\t // Single-threshold light ramp\n";
01097         text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
01098         text << "\t float lr_scale = (lr_in < " << t << ") ? 0.0 : (" << l0 << "/lr_in);\n";
01099         text << "\t tot_diffuse = tot_diffuse * lr_scale;\n";
01100         break;
01101       }
01102     case LightRampAttrib::LRT_double_threshold:
01103       {
01104         float t0 = light_ramp->get_threshold(0);
01105         float t1 = light_ramp->get_threshold(1);
01106         float l0 = light_ramp->get_level(0);
01107         float l1 = light_ramp->get_level(1);
01108         float l2 = light_ramp->get_level(2);
01109         text << "\t // Double-threshold light ramp\n";
01110         text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
01111         text << "\t float lr_out = " << l0 << "\n";
01112         text << "\t if (lr_in > " << t0 << ") lr_out=" << l1 << ";\n";
01113         text << "\t if (lr_in > " << t1 << ") lr_out=" << l2 << ";\n";
01114         text << "\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n";
01115         break;
01116       }
01117     }
01118     text << "\t // Begin view-space light summation\n";
01119     if (_have_emission) {
01120       if (_map_index_glow >= 0) {
01121         text << "\t result = attr_material[2] * saturate(2 * (tex" << _map_index_glow << ".a - 0.5));\n";
01122       } else {
01123         text << "\t result = attr_material[2];\n";
01124       }
01125     } else {
01126       if (_map_index_glow >= 0) {
01127         text << "\t result = saturate(2 * (tex" << _map_index_glow << ".a - 0.5));\n";
01128       } else {
01129         text << "\t result = float4(0,0,0,0);\n";
01130       }
01131     }
01132     if ((_have_ambient)&&(_separate_ambient_diffuse)) {
01133       if (_material->has_ambient()) {
01134         text << "\t result += tot_ambient * attr_material[0];\n";
01135       } else if (_vertex_colors) {
01136         text << "\t result += tot_ambient * l_color;\n";
01137       } else if (_flat_colors) {
01138         text << "\t result += tot_ambient * attr_color;\n";
01139       } else {
01140         text << "\t result += tot_ambient;\n";
01141       }
01142     }
01143     if (_have_diffuse) {
01144       if (_material->has_diffuse()) {
01145         text << "\t result += tot_diffuse * attr_material[1];\n";
01146       } else if (_vertex_colors) {
01147         text << "\t result += tot_diffuse * l_color;\n";
01148       } else if (_flat_colors) {
01149         text << "\t result += tot_diffuse * attr_color;\n";
01150       } else {
01151         text << "\t result += tot_diffuse;\n";
01152       }
01153     }
01154     if (light_ramp->get_mode() == LightRampAttrib::LRT_default) {
01155       text << "\t result = saturate(result);\n";
01156     }
01157     text << "\t // End view-space light calculations\n";
01158 
01159     // Combine in alpha, which bypasses lighting calculations.
01160     // Use of lerp here is a workaround for a radeon driver bug.
01161     if (_calc_primary_alpha) {
01162       if (_vertex_colors) {
01163         text << "\t result.a = l_color.a;\n";
01164       } else if (_flat_colors) {
01165         text << "\t result.a = attr_color.a;\n";
01166       } else {
01167         text << "\t result.a = 1;\n";
01168       }
01169     }
01170   } else {
01171     if (_vertex_colors) {
01172       text << "\t result = l_color;\n";
01173     } else if (_flat_colors) {
01174       text << "\t result = attr_color;\n";
01175     } else {
01176       text << "\t result = float4(1,1,1,1);\n";
01177     }
01178   }
01179 
01180   // Loop first to see if something is using primary_color or last_saved_result.
01181   bool have_saved_result = false;
01182   bool have_primary_color = false;
01183   for (int i=0; i<_num_textures; i++) {
01184     TextureStage *stage = texture->get_on_stage(i);
01185     if (stage->get_mode() != TextureStage::M_combine) continue;
01186     if (stage->uses_primary_color() && !have_primary_color) {
01187       text << "\t float4 primary_color = result;\n";
01188       have_primary_color = true;
01189     }
01190     if (stage->uses_last_saved_result() && !have_saved_result) {
01191       text << "\t float4 last_saved_result = result;\n";
01192       have_saved_result = true;
01193     }
01194   }
01195 
01196   // Now loop through the textures to compose our magic blending formulas.
01197   for (int i=0; i<_num_textures; i++) {
01198     TextureStage *stage = texture->get_on_stage(i);
01199     switch (stage->get_mode()) {
01200     case TextureStage::M_modulate:
01201     case TextureStage::M_modulate_glow:
01202     case TextureStage::M_modulate_gloss:
01203       text << "\t result *= tex" << i << ";\n";
01204       break;
01205     case TextureStage::M_decal:
01206       text << "\t result.rgb = lerp(result, tex" << i << ", tex" << i << ".a).rgb;\n";
01207       break;
01208     case TextureStage::M_blend: {
01209       LVecBase4f c = stage->get_color();
01210       text << "\t result.rgb = lerp(result, tex" << i << " * float4("
01211            << c[0] << ", " << c[1] << ", " << c[2] << ", " << c[3] << "), tex" << i << ".r).rgb;\n";
01212       break; }
01213     case TextureStage::M_replace:
01214       text << "\t result = tex" << i << ";\n";
01215       break;
01216     case TextureStage::M_add:
01217       text << "\t result.rgb += tex" << i << ".rgb;\n";
01218       if (_calc_primary_alpha) {
01219         text << "\t result.a   *= tex" << i << ".a;\n";
01220       }
01221       break;
01222     case TextureStage::M_combine:
01223       text << "\t result.rgb = ";
01224       if (stage->get_combine_rgb_mode() != TextureStage::CM_undefined) {
01225         text << combine_mode_as_string(stage, stage->get_combine_rgb_mode(), false, i);
01226       } else {
01227         text << "tex" << i << ".rgb";
01228       }
01229       if (stage->get_rgb_scale() != 1) {
01230         text << " * " << stage->get_rgb_scale();
01231       }
01232       text << ";\n\t result.a = ";
01233       if (stage->get_combine_alpha_mode() != TextureStage::CM_undefined) {
01234         text << combine_mode_as_string(stage, stage->get_combine_alpha_mode(), true, i);
01235       } else {
01236         text << "tex" << i << ".a";
01237       }
01238       if (stage->get_alpha_scale() != 1) {
01239         text << " * " << stage->get_alpha_scale();
01240       }
01241       text << ";\n";
01242       break;
01243     case TextureStage::M_blend_color_scale:
01244       text << "\t result.rgb = lerp(result, tex" << i << " * attr_colorscale, tex" << i << ".r).rgb;\n";
01245       break;
01246     default:
01247       break;
01248     }
01249     if (stage->get_saved_result() && have_saved_result) {
01250       text << "\t last_saved_result = result;\n";
01251     }
01252   }
01253   // Apply the color scale.
01254   text << "\t result *= attr_colorscale;\n";
01255 
01256   if (_subsume_alpha_test) {
01257     const AlphaTestAttrib *alpha_test = DCAST(AlphaTestAttrib, rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
01258     text << "\t // Shader includes alpha test:\n";
01259     double ref = alpha_test->get_reference_alpha();
01260     switch (alpha_test->get_mode()) {
01261     case RenderAttrib::M_never:          text<<"\t discard;\n";
01262     case RenderAttrib::M_less:           text<<"\t if (result.a >= "<<ref<<") discard;\n";
01263     case RenderAttrib::M_equal:          text<<"\t if (result.a != "<<ref<<") discard;\n";
01264     case RenderAttrib::M_less_equal:     text<<"\t if (result.a >  "<<ref<<") discard;\n";
01265     case RenderAttrib::M_greater:        text<<"\t if (result.a <= "<<ref<<") discard;\n";
01266     case RenderAttrib::M_not_equal:      text<<"\t if (result.a == "<<ref<<") discard;\n";
01267     case RenderAttrib::M_greater_equal:  text<<"\t if (result.a <  "<<ref<<") discard;\n";
01268     }
01269   }
01270 
01271   if (_out_primary_glow) {
01272     if (_map_index_glow >= 0) {
01273       text << "\t result.a = tex" << _map_index_glow << ".a;\n";
01274     } else {
01275       text << "\t result.a = 0.5;\n";
01276     }
01277   }
01278   if (_out_aux_glow) {
01279     if (_map_index_glow >= 0) {
01280       text << "\t o_aux.a = tex" << _map_index_glow << ".a;\n";
01281     } else {
01282       text << "\t o_aux.a = 0.5;\n";
01283     }
01284   }
01285 
01286   if (_lighting) {
01287     if (_have_specular) {
01288       if (_material->has_specular()) {
01289         text << "\t tot_specular *= attr_material[3];\n";
01290       }
01291       if (_map_index_gloss >= 0) {
01292         text << "\t tot_specular *= tex" << _map_index_gloss << ".a;\n";
01293       }
01294       text << "\t result.rgb = result.rgb + tot_specular.rgb;\n";
01295     }
01296   }
01297 
01298   const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
01299   switch (light_ramp->get_mode()) {
01300   case LightRampAttrib::LRT_hdr0:
01301     text << "\t result.rgb = (result*result*result + result*result + result) / (result*result*result + result*result + result + 1);\n";
01302     break;
01303   case LightRampAttrib::LRT_hdr1:
01304     text << "\t result.rgb = (result*result + result) / (result*result + result + 1);\n";
01305     break;
01306   case LightRampAttrib::LRT_hdr2:
01307     text << "\t result.rgb = result / (result + 1);\n";
01308     break;
01309   default: break;
01310   }
01311 
01312   // The multiply is a workaround for a radeon driver bug.
01313   // It's annoying as heck, since it produces an extra instruction.
01314   text << "\t o_color = result * 1.000001;\n";
01315   if (_subsume_alpha_test) {
01316     text << "\t // Shader subsumes normal alpha test.\n";
01317   }
01318   if (_disable_alpha_write) {
01319     text << "\t // Shader disables alpha write.\n";
01320   }
01321   text << "}\n";
01322 
01323   // Insert the shader into the shader attrib.
01324   CPT(RenderAttrib) shattr = create_shader_attrib(text.str());
01325   if (_subsume_alpha_test) {
01326     shattr=DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_subsume_alpha_test, true);
01327   }
01328   if (_disable_alpha_write) {
01329     shattr=DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_disable_alpha_write, true);
01330   }
01331   clear_analysis();
01332   reset_register_allocator();
01333   return shattr;
01334 }
01335 
01336 ////////////////////////////////////////////////////////////////////
01337 //     Function: ShaderGenerator::combine_mode_as_string
01338 //       Access: Protected, Static
01339 //  Description: This 'synthesizes' a combine mode into a string.
01340 ////////////////////////////////////////////////////////////////////
01341 const string ShaderGenerator::
01342 combine_mode_as_string(CPT(TextureStage) stage, TextureStage::CombineMode c_mode, bool alpha, short texindex) {
01343   ostringstream text;
01344   switch (c_mode) {
01345     case TextureStage::CM_modulate:
01346       text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
01347       text << " * ";
01348       text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
01349       break;
01350     case TextureStage::CM_add:
01351       text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
01352       text << " + ";
01353       text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
01354       break;
01355     case TextureStage::CM_add_signed:
01356       pgraph_cat.error() << "TextureStage::CombineMode ADD_SIGNED not yet supported in per-pixel mode.\n";
01357       break;
01358     case TextureStage::CM_interpolate:
01359       text << "lerp(";
01360       text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
01361       text << ", ";
01362       text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
01363       text << ", ";
01364       text << combine_source_as_string(stage, 2, alpha, true, texindex);
01365       text << ")";
01366       break;
01367     case TextureStage::CM_subtract:
01368       text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
01369       text << " + ";
01370       text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
01371       break;
01372     case TextureStage::CM_dot3_rgb:
01373       pgraph_cat.error() << "TextureStage::CombineMode DOT3_RGB not yet supported in per-pixel mode.\n";
01374       break;
01375     case TextureStage::CM_dot3_rgba:
01376       pgraph_cat.error() << "TextureStage::CombineMode DOT3_RGBA not yet supported in per-pixel mode.\n";
01377       break;
01378     case TextureStage::CM_replace:
01379     default: // Not sure if this is correct as default value.
01380       text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
01381       break;
01382   }
01383   return text.str();
01384 }
01385 
01386 ////////////////////////////////////////////////////////////////////
01387 //     Function: ShaderGenerator::combine_source_as_string
01388 //       Access: Protected, Static
01389 //  Description: This 'synthesizes' a combine source into a string.
01390 ////////////////////////////////////////////////////////////////////
01391 const string ShaderGenerator::
01392 combine_source_as_string(CPT(TextureStage) stage, short num, bool alpha, bool single_value, short texindex) {
01393   TextureStage::CombineSource c_src = TextureStage::CS_undefined;
01394   TextureStage::CombineOperand c_op = TextureStage::CO_undefined;
01395   if (alpha) {
01396     switch (num) {
01397       case 0:
01398         c_src = stage->get_combine_alpha_source0();
01399         c_op = stage->get_combine_alpha_operand0();
01400         break;
01401       case 1:
01402         c_src = stage->get_combine_alpha_source1();
01403         c_op = stage->get_combine_alpha_operand1();
01404         break;
01405       case 2:
01406         c_src = stage->get_combine_alpha_source2();
01407         c_op = stage->get_combine_alpha_operand2();
01408         break;
01409     }
01410   } else {
01411     switch (num) {
01412       case 0:
01413         c_src = stage->get_combine_rgb_source0();
01414         c_op = stage->get_combine_rgb_operand0();
01415         break;
01416       case 1:
01417         c_src = stage->get_combine_rgb_source1();
01418         c_op = stage->get_combine_rgb_operand1();
01419         break;
01420       case 2:
01421         c_src = stage->get_combine_rgb_source2();
01422         c_op = stage->get_combine_rgb_operand2();
01423         break;
01424     }
01425   }
01426   ostringstream csource;
01427   if (c_op == TextureStage::CO_one_minus_src_color ||
01428       c_op == TextureStage::CO_one_minus_src_alpha) {
01429     csource << "1.0f - ";
01430   }
01431   switch (c_src) {
01432     case TextureStage::CS_texture:
01433       csource << "tex" << texindex;
01434       break;
01435     case TextureStage::CS_constant: {
01436       LVecBase4f c = stage->get_color();
01437       csource << "float4(" << c[0] << ", " << c[1] << ", " << c[2] << ", " << c[3] << ")";
01438       break; }
01439     case TextureStage::CS_primary_color:
01440       csource << "primary_color";
01441       break;
01442     case TextureStage::CS_previous:
01443       csource << "result";
01444       break;
01445     case TextureStage::CS_constant_color_scale:
01446       csource << "attr_colorscale";
01447       break;
01448     case TextureStage::CS_last_saved_result:
01449       csource << "last_saved_result";
01450       break;
01451   }
01452   if (c_op == TextureStage::CO_src_color || c_op == TextureStage::CO_one_minus_src_color) {
01453     if (single_value) {
01454       // Let's take the red channel.
01455       csource << ".r";
01456     } else {
01457       csource << ".rgb";
01458     }
01459   } else {
01460     csource << ".a";
01461     if (!single_value) {
01462       // Dunno if it's legal in the FPP at all, but let's just allow it.
01463       return "float3(" + csource.str() + ")";
01464     }
01465   }
01466   return csource.str();
01467 }
01468 
01469 ////////////////////////////////////////////////////////////////////
01470 //     Function: ShaderGenerator::texture_type_as_string
01471 //       Access: Protected, Static
01472 //  Description: Returns 1D, 2D, 3D or CUBE, depending on the given
01473 //               texture type.
01474 ////////////////////////////////////////////////////////////////////
01475 const string ShaderGenerator::
01476 texture_type_as_string(Texture::TextureType ttype) {
01477   switch (ttype) {
01478     case Texture::TT_1d_texture:
01479       return "1D";
01480       break;
01481     case Texture::TT_2d_texture:
01482       return "2D";
01483       break;
01484     case Texture::TT_3d_texture:
01485       return "3D";
01486       break;
01487     case Texture::TT_cube_map:
01488       return "CUBE";
01489       break;
01490     default:
01491       pgraph_cat.error() << "Unsupported texture type!\n";
01492       return "2D";
01493   }
01494 }
01495 
 All Classes Functions Variables Enumerations