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