Panda3D

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 << "void vshader(\n";
00666   const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot()));
00667   const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, rs->get_attrib_def(TexGenAttrib::get_class_slot()));
00668   for (int i=0; i<_num_textures; i++) {
00669     texcoord_vreg.push_back(alloc_vreg());
00670     texcoord_freg.push_back(alloc_freg());
00671     text << "\t in float4 vtx_texcoord" << i << " : " << texcoord_vreg[i] << ",\n";
00672     text << "\t out float4 l_texcoord" << i << " : " << texcoord_freg[i] << ",\n";
00673   }
00674   if (_vertex_colors) {
00675     text << "\t in float4 vtx_color : COLOR,\n";
00676     text << "\t out float4 l_color : COLOR,\n";
00677   }
00678   if (_need_world_position || _need_world_normal) {
00679     text << "\t uniform float4x4 trans_model_to_world,\n";
00680   }
00681   if (_need_world_position) {
00682     world_position_freg = alloc_freg();
00683     text << "\t out float4 l_world_position : " << world_position_freg << ",\n";
00684   }
00685   if (_need_world_normal) {
00686     world_normal_freg = alloc_freg();
00687     text << "\t out float4 l_world_normal : " << world_normal_freg << ",\n";
00688   }
00689   if (_need_eye_position) {
00690     text << "\t uniform float4x4 trans_model_to_view,\n";
00691     eye_position_freg = alloc_freg();
00692     text << "\t out float4 l_eye_position : " << eye_position_freg << ",\n";
00693   }
00694   if (_need_eye_normal) {
00695     eye_normal_freg = alloc_freg();
00696     text << "\t uniform float4x4 tpose_view_to_model,\n";
00697     text << "\t out float4 l_eye_normal : " << eye_normal_freg << ",\n";
00698   }
00699   if (_map_index_height >= 0 || _need_world_normal || _need_eye_normal) {
00700     normal_vreg = alloc_vreg();
00701     text << "\t in float4 vtx_normal : " << normal_vreg << ",\n";
00702   }
00703   if (_map_index_height >= 0) {
00704     htangent_vreg = alloc_vreg();
00705     hbinormal_vreg = alloc_vreg();
00706     if (_map_index_normal == _map_index_height) {
00707       ntangent_vreg = htangent_vreg;
00708       nbinormal_vreg = hbinormal_vreg;
00709     }
00710     text << "\t in float4 vtx_tangent" << _map_index_height << " : " << htangent_vreg << ",\n";
00711     text << "\t in float4 vtx_binormal" << _map_index_height << " : " << hbinormal_vreg << ",\n";
00712     text << "\t uniform float4 mspos_view,\n";
00713     text << "\t out float3 l_eyevec,\n";
00714   }
00715   if (_lighting) {
00716     if (_map_index_normal >= 0 && _auto_normal_on) {
00717       // If we had a height map and it used the same stage, that means we already have those inputs.
00718       if (_map_index_normal != _map_index_height) {
00719         ntangent_vreg = alloc_vreg();
00720         nbinormal_vreg = alloc_vreg();
00721         text << "\t in float4 vtx_tangent" << _map_index_normal << " : " << ntangent_vreg << ",\n";
00722         text << "\t in float4 vtx_binormal" << _map_index_normal << " : " << nbinormal_vreg << ",\n";
00723       }
00724       ntangent_freg = alloc_freg();
00725       nbinormal_freg = alloc_freg();
00726       text << "\t out float4 l_tangent : " << ntangent_freg << ",\n";
00727       text << "\t out float4 l_binormal : " << nbinormal_freg << ",\n";
00728     }
00729     if (_shadows && _auto_shadow_on) {
00730       for (int i=0; i<(int)_dlights.size(); i++) {
00731         if (_dlights[i]->_shadow_caster) {
00732           dlightcoord_freg.push_back(alloc_freg());
00733           text << "\t uniform float4x4 trans_model_to_clip_of_dlight" << i << ",\n";
00734           text << "\t out float4 l_dlightcoord" << i << " : " << dlightcoord_freg[i] << ",\n";
00735         } else {
00736           dlightcoord_freg.push_back(NULL);
00737         }
00738       }
00739       for (int i=0; i<(int)_slights.size(); i++) {
00740         if (_slights[i]->_shadow_caster) {
00741           slightcoord_freg.push_back(alloc_freg());
00742           text << "\t uniform float4x4 trans_model_to_clip_of_slight" << i << ",\n";
00743           text << "\t out float4 l_slightcoord" << i << " : " << slightcoord_freg[i] << ",\n";
00744         } else {
00745           slightcoord_freg.push_back(NULL);
00746         }
00747       }
00748     }
00749   }
00750   if (_fog) {
00751     hpos_freg = alloc_freg();
00752     text << "\t out float4 l_hpos : " << hpos_freg << ",\n";
00753   }
00754   text << "\t float4 vtx_position : POSITION,\n";
00755   text << "\t out float4 l_position : POSITION,\n";
00756   text << "\t uniform float4x4 mat_modelproj\n";
00757   text << ") {\n";
00758 
00759   text << "\t l_position = mul(mat_modelproj, vtx_position);\n";
00760   if (_fog) {
00761     text << "\t l_hpos = l_position;\n";
00762   }
00763   if (_need_world_position) {
00764     text << "\t l_world_position = mul(trans_model_to_world, vtx_position);\n";
00765   }
00766   if (_need_world_normal) {
00767     text << "\t l_world_normal = mul(trans_model_to_world, vtx_normal);\n";
00768   }
00769   if (_need_eye_position) {
00770     text << "\t l_eye_position = mul(trans_model_to_view, vtx_position);\n";
00771   }
00772   if (_need_eye_normal) {
00773     text << "\t l_eye_normal.xyz = mul((float3x3)tpose_view_to_model, vtx_normal.xyz);\n";
00774     text << "\t l_eye_normal.w = 0;\n";
00775   }
00776   for (int i=0; i<_num_textures; i++) {
00777     if (!tex_gen->has_stage(texture->get_on_stage(i))) {
00778       text << "\t l_texcoord" << i << " = vtx_texcoord" << i << ";\n";
00779     }
00780   }
00781   if (_vertex_colors) {
00782     text << "\t l_color = vtx_color;\n";
00783   }
00784   if (_lighting && (_map_index_normal >= 0 && _auto_normal_on)) {
00785     text << "\t l_tangent.xyz = mul((float3x3)tpose_view_to_model, vtx_tangent" << _map_index_normal << ".xyz);\n";
00786     text << "\t l_tangent.w = 0;\n";
00787     text << "\t l_binormal.xyz = mul((float3x3)tpose_view_to_model, -vtx_binormal" << _map_index_normal << ".xyz);\n";
00788     text << "\t l_binormal.w = 0;\n";
00789   }
00790   if (_shadows && _auto_shadow_on) {
00791     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";
00792     for (int i=0; i<(int)_dlights.size(); i++) {
00793       if (_dlights[i]->_shadow_caster) {
00794         text << "\t l_dlightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_dlight" << i << ", vtx_position));\n";
00795       }
00796     }
00797     for (int i=0; i<(int)_slights.size(); i++) {
00798       if (_slights[i]->_shadow_caster) {
00799         text << "\t l_slightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_slight" << i << ", vtx_position));\n";
00800       }
00801     }
00802   }
00803   if (_map_index_height >= 0) {
00804     text << "\t float3 eyedir = mspos_view.xyz - vtx_position.xyz;\n";
00805     text << "\t l_eyevec.x = dot(vtx_tangent" << _map_index_height << ".xyz, eyedir);\n";
00806     text << "\t l_eyevec.y = dot(vtx_binormal" << _map_index_height << ".xyz, eyedir);\n";
00807     text << "\t l_eyevec.z = dot(vtx_normal.xyz, eyedir);\n";
00808     text << "\t l_eyevec = normalize(l_eyevec);\n";
00809   }
00810   text << "}\n\n";
00811 
00812   // Fragment shader
00813 
00814   text << "void fshader(\n";
00815   if (_fog) {
00816     text << "\t in float4 l_hpos : " << hpos_freg << ",\n";
00817     text << "\t in uniform float4 attr_fog,\n";
00818     text << "\t in uniform float4 attr_fogcolor,\n";
00819   }
00820   if (_need_world_position) {
00821     text << "\t in float4 l_world_position : " << world_position_freg << ",\n";
00822   }
00823   if (_need_world_normal) {
00824     text << "\t in float4 l_world_normal : " << world_normal_freg << ",\n";
00825   }
00826   if (_need_eye_position) { 
00827     text << "\t in float4 l_eye_position : " << eye_position_freg << ",\n";
00828   }
00829   if (_need_eye_normal) {
00830     text << "\t in float4 l_eye_normal : " << eye_normal_freg << ",\n";
00831   }
00832   const TexMatrixAttrib *tex_matrix = DCAST(TexMatrixAttrib, rs->get_attrib_def(TexMatrixAttrib::get_class_slot()));
00833   for (int i=0; i<_num_textures; i++) {
00834     TextureStage *stage = texture->get_on_stage(i);
00835     Texture *tex = texture->get_on_texture(stage);
00836     nassertr(tex != NULL, NULL);
00837     text << "\t uniform sampler" << texture_type_as_string(tex->get_texture_type()) << " tex_" << i << ",\n";
00838     if (!tex_gen->has_stage(stage)) {
00839       text << "\t in float4 l_texcoord" << i << " : " << texcoord_freg[i] << ",\n";
00840     }
00841     if (tex_matrix->has_stage(stage)) {
00842       text << "\t uniform float4x4 texmat_" << i << ",\n";
00843     }
00844   }
00845   if (_lighting && (_map_index_normal >= 0 && _auto_normal_on)) {
00846     text << "\t in float3 l_tangent : " << ntangent_freg << ",\n";
00847     text << "\t in float3 l_binormal : " << nbinormal_freg << ",\n";
00848   }
00849   if (_lighting) {
00850     for (int i=0; i<(int)_alights.size(); i++) {
00851       text << "\t uniform float4 alight_alight" << i << ",\n";
00852     }
00853     for (int i=0; i<(int)_dlights.size(); i++) {
00854       text << "\t uniform float4x4 dlight_dlight" << i << "_rel_view,\n";
00855       if (_shadows && _dlights[i]->_shadow_caster && _auto_shadow_on) {
00856         if (_use_shadow_filter) {
00857           text << "\t uniform sampler2DShadow k_dlighttex" << i << ",\n";
00858         } else {
00859           text << "\t uniform sampler2D k_dlighttex" << i << ",\n";
00860         }
00861         text << "\t in float4 l_dlightcoord" << i << " : " << dlightcoord_freg[i] << ",\n";
00862       }
00863     }
00864     for (int i=0; i<(int)_plights.size(); i++) {
00865       text << "\t uniform float4x4 plight_plight" << i << "_rel_view,\n";
00866     }
00867     for (int i=0; i<(int)_slights.size(); i++) {
00868       text << "\t uniform float4x4 slight_slight" << i << "_rel_view,\n";
00869       text << "\t uniform float4   satten_slight" << i << ",\n";
00870       if (_shadows && _slights[i]->_shadow_caster && _auto_shadow_on) {
00871         if (_use_shadow_filter) {
00872           text << "\t uniform sampler2DShadow k_slighttex" << i << ",\n";
00873         } else {
00874           text << "\t uniform sampler2D k_slighttex" << i << ",\n";
00875         }
00876         text << "\t in float4 l_slightcoord" << i << " : " << slightcoord_freg[i] << ",\n";
00877       }
00878     }
00879     if (_need_material_props) {
00880       text << "\t uniform float4x4 attr_material,\n";
00881     }
00882     if (_have_specular) {
00883       if (_material->get_local()) {
00884         text << "\t uniform float4 mspos_view,\n";
00885       } else {
00886         text << "\t uniform float4 row1_view_to_model,\n";
00887       }
00888     }
00889   }
00890   if (_map_index_height >= 0) {
00891     text << "\t float3 l_eyevec,\n";
00892   }
00893   if (_out_aux_any) {
00894     text << "\t out float4 o_aux : COLOR1,\n";
00895   }
00896   text << "\t out float4 o_color : COLOR0,\n";
00897   if (_vertex_colors) {
00898     text << "\t in float4 l_color : COLOR,\n";
00899   } else {
00900     text << "\t uniform float4 attr_color,\n";
00901   }
00902   for (int i=0; i<_num_clip_planes; ++i) {
00903     text << "\t uniform float4 clipplane_" << i << ",\n";
00904   }
00905   text << "\t uniform float4 attr_colorscale\n";
00906   text << ") {\n";
00907   // Clipping first!
00908   for (int i=0; i<_num_clip_planes; ++i) {
00909     text << "\t if (l_world_position.x * clipplane_" << i << ".x + l_world_position.y ";
00910     text << "* clipplane_" << i << ".y + l_world_position.z * clipplane_" << i << ".z + clipplane_" << i << ".w <= 0) {\n";
00911     text << "\t discard;\n";
00912     text << "\t }\n";
00913   }
00914   text << "\t float4 result;\n";
00915   if (_out_aux_any) {
00916     text << "\t o_aux = float4(0,0,0,0);\n";
00917   }
00918   // Now generate any texture coordinates according to TexGenAttrib. If it has a TexMatrixAttrib, also transform them.
00919   for (int i=0; i<_num_textures; i++) {
00920     TextureStage *stage = texture->get_on_stage(i);
00921     if (tex_gen != NULL && tex_gen->has_stage(stage)) {
00922       switch (tex_gen->get_mode(stage)) {
00923         case TexGenAttrib::M_world_position:
00924           text << "\t float4 l_texcoord" << i << " = l_world_position;\n";
00925           break;
00926         case TexGenAttrib::M_world_normal:
00927           text << "\t float4 l_texcoord" << i << " = l_world_normal;\n";
00928           break;
00929         case TexGenAttrib::M_eye_position:
00930           text << "\t float4 l_texcoord" << i << " = l_eye_position;\n";
00931           break;
00932         case TexGenAttrib::M_eye_normal:
00933           text << "\t float4 l_texcoord" << i << " = l_eye_normal;\n";
00934           text << "\t l_texcoord" << i << ".w = 1.0f;\n";
00935           break;
00936         default:
00937           pgraph_cat.error() << "Unsupported TexGenAttrib mode\n";
00938           text << "\t float4 l_texcoord" << i << " = float4(0, 0, 0, 0);\n";
00939       }
00940     }
00941     if (tex_matrix != NULL && tex_matrix->has_stage(stage)) {
00942       text << "\t l_texcoord" << i << " = mul(texmat_" << i << ", l_texcoord" << i << ");\n";
00943       text << "\t l_texcoord" << i << ".xyz /= l_texcoord" << i << ".w;\n";
00944     }
00945   }
00946   text << "\t // Fetch all textures.\n";
00947   if (_map_index_height >= 0 && parallax_mapping_samples > 0) {
00948     Texture *tex = texture->get_on_texture(texture->get_on_stage(_map_index_height));
00949     nassertr(tex != NULL, NULL);
00950     text << "\t float4 tex" << _map_index_height << " = tex" << texture_type_as_string(tex->get_texture_type());
00951     text << "(tex_" << _map_index_height << ", l_texcoord" << _map_index_height << ".";
00952     switch (tex->get_texture_type()) {
00953     case Texture::TT_cube_map:
00954     case Texture::TT_3d_texture: 
00955       text << "xyz";
00956       break;
00957     case Texture::TT_2d_texture: 
00958       text << "xy";  
00959       break;
00960     case Texture::TT_1d_texture:
00961       text << "x";   
00962       break;
00963     default:
00964       break;
00965     }
00966     text << ");\n\t float3 parallax_offset = l_eyevec.xyz * (tex" << _map_index_height;
00967     if (_map_height_in_alpha) {
00968       text << ".aaa";
00969     } else {
00970       text << ".rgb";
00971     }
00972     text << " * 2.0 - 1.0) * " << parallax_mapping_scale << ";\n";
00973     // Additional samples
00974     for (int i=0; i<parallax_mapping_samples-1; i++) {
00975       text << "\t parallax_offset = l_eyevec.xyz * (parallax_offset + (tex" << _map_index_height;
00976       if (_map_height_in_alpha) {
00977         text << ".aaa";
00978       } else {
00979         text << ".rgb";
00980       }
00981       text << " * 2.0 - 1.0)) * " << 0.5 * parallax_mapping_scale << ";\n";
00982     }
00983   }
00984   for (int i=0; i<_num_textures; i++) {
00985     if (i != _map_index_height) {
00986       Texture *tex = texture->get_on_texture(texture->get_on_stage(i));
00987       nassertr(tex != NULL, NULL);
00988       // Parallax mapping pushes the texture coordinates of the other textures away from the camera.
00989       if (_map_index_height >= 0 && parallax_mapping_samples > 0) {
00990         text << "\t l_texcoord" << i << ".xyz -= parallax_offset;\n";
00991       }
00992       text << "\t float4 tex" << i << " = tex" << texture_type_as_string(tex->get_texture_type());
00993       text << "(tex_" << i << ", l_texcoord" << i << ".";
00994       switch(tex->get_texture_type()) {
00995       case Texture::TT_cube_map:
00996       case Texture::TT_3d_texture: 
00997         text << "xyz"; 
00998         break;
00999       case Texture::TT_2d_texture: 
01000         text << "xy";
01001         break;
01002       case Texture::TT_1d_texture: 
01003         text << "x";   
01004         break;
01005       default:
01006         break;
01007       }
01008       text << ");\n";
01009     }
01010   }
01011   if (_lighting) {
01012     if (_map_index_normal >= 0 && _auto_normal_on) {
01013       text << "\t // Translate tangent-space normal in map to view-space.\n";
01014       text << "\t float3 tsnormal = ((float3)tex" << _map_index_normal << " * 2) - 1;\n";
01015       text << "\t l_eye_normal.xyz *= tsnormal.z;\n";
01016       text << "\t l_eye_normal.xyz += l_tangent * tsnormal.x;\n";
01017       text << "\t l_eye_normal.xyz += l_binormal * tsnormal.y;\n";
01018       text << "\t l_eye_normal.xyz  = normalize(l_eye_normal.xyz);\n";
01019     } else {
01020       text << "\t // Correct the surface normal for interpolation effects\n";
01021       text << "\t l_eye_normal.xyz = normalize(l_eye_normal.xyz);\n";
01022     }
01023   }
01024   if (_out_aux_normal) {
01025     text << "\t // Output the camera-space surface normal\n";
01026     text << "\t o_aux.rgb = (l_eye_normal.xyz*0.5) + float3(0.5,0.5,0.5);\n";
01027   }
01028   if (_lighting) {
01029     text << "\t // Begin view-space light calculations\n";
01030     text << "\t float ldist,lattenv,langle;\n";
01031     text << "\t float4 lcolor,lspec,lvec,lpoint,latten,ldir,leye,lhalf;\n";
01032     if (_shadows && _auto_shadow_on) {
01033       text << "\t float lshad;\n";
01034     }
01035     if (_separate_ambient_diffuse) {
01036       if (_have_ambient) {
01037         text << "\t float4 tot_ambient = float4(0,0,0,0);\n";
01038       }
01039       if (_have_diffuse) {
01040         text << "\t float4 tot_diffuse = float4(0,0,0,0);\n";
01041       }
01042     } else {
01043       if (_have_ambient || _have_diffuse) {
01044         text << "\t float4 tot_diffuse = float4(0,0,0,0);\n";
01045       }
01046     }
01047     if (_have_specular) {
01048       text << "\t float4 tot_specular = float4(0,0,0,0);\n";
01049       if (_material->has_specular()) {
01050         text << "\t float shininess = attr_material[3].w;\n";
01051       } else {
01052         text << "\t float shininess = 50; // no shininess specified, using default\n";
01053       }
01054     }
01055     for (int i=0; i<(int)_alights.size(); i++) {
01056       text << "\t // Ambient Light " << i << "\n";
01057       text << "\t lcolor = alight_alight" << i << ";\n";
01058       if (_separate_ambient_diffuse && _have_ambient) {
01059         text << "\t tot_ambient += lcolor;\n";
01060       } else if(_have_diffuse) {
01061         text << "\t tot_diffuse += lcolor;\n";
01062       }
01063     }
01064     for (int i=0; i<(int)_dlights.size(); i++) {
01065       text << "\t // Directional Light " << i << "\n";
01066       text << "\t lcolor = dlight_dlight" << i << "_rel_view[0];\n";
01067       text << "\t lspec  = dlight_dlight" << i << "_rel_view[1];\n";
01068       text << "\t lvec   = dlight_dlight" << i << "_rel_view[2];\n";
01069       text << "\t lcolor *= saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
01070       if (_shadows && _dlights[i]->_shadow_caster && _auto_shadow_on) {
01071         if (_use_shadow_filter) {
01072           text << "\t lshad = shadow2DProj(k_dlighttex" << i << ", l_dlightcoord" << i << ").r;\n";
01073         } else {
01074           text << "\t lshad = tex2Dproj(k_dlighttex" << i << ", l_dlightcoord" << i << ").r > l_dlightcoord" << i << ".z / l_dlightcoord" << i << ".w;\n";
01075         }
01076         text << "\t lcolor *= lshad;\n";
01077         text << "\t lspec *= lshad;\n";
01078       }
01079       if (_have_diffuse) {
01080         text << "\t tot_diffuse += lcolor;\n";
01081       }
01082       if (_have_specular) {
01083         if (_material->get_local()) {
01084           text << "\t lhalf  = normalize(lvec - normalize(l_eye_position));\n";
01085         } else {
01086           text << "\t lhalf = dlight_dlight" << i << "_rel_view[3];\n";
01087         }
01088         text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
01089         text << "\t tot_specular += lspec;\n";
01090       }
01091     }
01092     for (int i=0; i<(int)_plights.size(); i++) {
01093       text << "\t // Point Light " << i << "\n";
01094       text << "\t lcolor = plight_plight" << i << "_rel_view[0];\n";
01095       text << "\t lspec  = plight_plight" << i << "_rel_view[1];\n";
01096       text << "\t lpoint = plight_plight" << i << "_rel_view[2];\n";
01097       text << "\t latten = plight_plight" << i << "_rel_view[3];\n";
01098       text << "\t lvec   = lpoint - l_eye_position;\n";
01099       text << "\t ldist = length(float3(lvec));\n";
01100       text << "\t lvec /= ldist;\n";
01101       text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
01102       text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
01103       if (_have_diffuse) {
01104         text << "\t tot_diffuse += lcolor;\n";
01105       }
01106       if (_have_specular) {
01107         if (_material->get_local()) {
01108           text << "\t lhalf  = normalize(lvec - normalize(l_eye_position));\n";
01109         } else {
01110           text << "\t lhalf = normalize(lvec - float4(0,1,0,0));\n";
01111         }
01112         text << "\t lspec *= lattenv;\n";
01113         text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
01114         text << "\t tot_specular += lspec;\n";
01115       }
01116     }
01117     for (int i=0; i<(int)_slights.size(); i++) {
01118       text << "\t // Spot Light " << i << "\n";
01119       text << "\t lcolor = slight_slight" << i << "_rel_view[0];\n";
01120       text << "\t lspec  = slight_slight" << i << "_rel_view[1];\n";
01121       text << "\t lpoint = slight_slight" << i << "_rel_view[2];\n";
01122       text << "\t ldir   = slight_slight" << i << "_rel_view[3];\n";
01123       text << "\t latten = satten_slight" << i << ";\n";
01124       text << "\t lvec   = lpoint - l_eye_position;\n";
01125       text << "\t ldist  = length(float3(lvec));\n";
01126       text << "\t lvec /= ldist;\n";
01127       text << "\t langle = saturate(dot(ldir.xyz, lvec.xyz));\n";
01128       text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
01129       text << "\t lattenv *= pow(langle, latten.w);\n";
01130       text << "\t if (langle < ldir.w) lattenv = 0;\n";
01131       text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
01132       if (_shadows && _slights[i]->_shadow_caster && _auto_shadow_on) {
01133         if (_use_shadow_filter) {
01134           text << "\t lshad = shadow2DProj(k_slighttex" << i << ", l_slightcoord" << i << ").r;\n";
01135         } else {
01136           text << "\t lshad = tex2Dproj(k_slighttex" << i << ", l_slightcoord" << i << ").r > l_slightcoord" << i << ".z / l_slightcoord" << i << ".w;\n";
01137         }
01138         text << "\t lcolor *= lshad;\n";
01139         text << "\t lspec *= lshad;\n";
01140       }
01141 
01142       if (_have_diffuse) {
01143         text << "\t tot_diffuse += lcolor;\n";
01144       }
01145       if (_have_specular) {
01146         if (_material->get_local()) {
01147           text << "\t lhalf  = normalize(lvec - normalize(l_eye_position));\n";
01148         } else {
01149           text << "\t lhalf = normalize(lvec - float4(0,1,0,0));\n";
01150         }
01151         text << "\t lspec *= lattenv;\n";
01152         text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
01153         text << "\t tot_specular += lspec;\n";
01154       }
01155     }
01156     const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
01157     if(_auto_ramp_on) {
01158       switch (light_ramp->get_mode()) {
01159       case LightRampAttrib::LRT_single_threshold:
01160         {
01161           PN_stdfloat t = light_ramp->get_threshold(0);
01162           PN_stdfloat l0 = light_ramp->get_level(0);
01163           text << "\t // Single-threshold light ramp\n";
01164           text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
01165           text << "\t float lr_scale = (lr_in < " << t << ") ? 0.0 : (" << l0 << "/lr_in);\n";
01166           text << "\t tot_diffuse = tot_diffuse * lr_scale;\n";
01167           break;
01168         }
01169       case LightRampAttrib::LRT_double_threshold:
01170         {
01171           PN_stdfloat t0 = light_ramp->get_threshold(0);
01172           PN_stdfloat t1 = light_ramp->get_threshold(1);
01173           PN_stdfloat l0 = light_ramp->get_level(0);
01174           PN_stdfloat l1 = light_ramp->get_level(1);
01175           PN_stdfloat l2 = light_ramp->get_level(2);
01176           text << "\t // Double-threshold light ramp\n";
01177           text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
01178           text << "\t float lr_out = " << l0 << "\n";
01179           text << "\t if (lr_in > " << t0 << ") lr_out=" << l1 << ";\n";
01180           text << "\t if (lr_in > " << t1 << ") lr_out=" << l2 << ";\n";
01181           text << "\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n";
01182           break;
01183         }
01184       default:
01185         break;
01186       }
01187     }
01188     text << "\t // Begin view-space light summation\n";
01189     if (_have_emission) {
01190       if (_map_index_glow >= 0 && _auto_glow_on) {
01191         text << "\t result = attr_material[2] * saturate(2 * (tex" << _map_index_glow << ".a - 0.5));\n";
01192       } else {
01193         text << "\t result = attr_material[2];\n";
01194       }
01195     } else {
01196       if (_map_index_glow >= 0 && _auto_glow_on) {
01197         text << "\t result = saturate(2 * (tex" << _map_index_glow << ".a - 0.5));\n";
01198       } else {
01199         text << "\t result = float4(0,0,0,0);\n";
01200       }
01201     }
01202     if ((_have_ambient)&&(_separate_ambient_diffuse)) {
01203       if (_material->has_ambient()) {
01204         text << "\t result += tot_ambient * attr_material[0];\n";
01205       } else if (_vertex_colors) {
01206         text << "\t result += tot_ambient * l_color;\n";
01207       } else if (_flat_colors) {
01208         text << "\t result += tot_ambient * attr_color;\n";
01209       } else {
01210         text << "\t result += tot_ambient;\n";
01211       }
01212     }
01213     if (_have_diffuse) {
01214       if (_material->has_diffuse()) {
01215         text << "\t result += tot_diffuse * attr_material[1];\n";
01216       } else if (_vertex_colors) {
01217         text << "\t result += tot_diffuse * l_color;\n";
01218       } else if (_flat_colors) {
01219         text << "\t result += tot_diffuse * attr_color;\n";
01220       } else {
01221         text << "\t result += tot_diffuse;\n";
01222       }
01223     }
01224     if (light_ramp->get_mode() == LightRampAttrib::LRT_default) {
01225       text << "\t result = saturate(result);\n";
01226     }
01227     text << "\t // End view-space light calculations\n";
01228 
01229     // Combine in alpha, which bypasses lighting calculations.
01230     // Use of lerp here is a workaround for a radeon driver bug.
01231     if (_calc_primary_alpha) {
01232       if (_vertex_colors) {
01233         text << "\t result.a = l_color.a;\n";
01234       } else if (_flat_colors) {
01235         text << "\t result.a = attr_color.a;\n";
01236       } else {
01237         text << "\t result.a = 1;\n";
01238       }
01239     }
01240   } else {
01241     if (_vertex_colors) {
01242       text << "\t result = l_color;\n";
01243     } else if (_flat_colors) {
01244       text << "\t result = attr_color;\n";
01245     } else {
01246       text << "\t result = float4(1,1,1,1);\n";
01247     }
01248   }
01249 
01250   // Loop first to see if something is using primary_color or last_saved_result.
01251   bool have_saved_result = false;
01252   bool have_primary_color = false;
01253   for (int i=0; i<_num_textures; i++) {
01254     TextureStage *stage = texture->get_on_stage(i);
01255     if (stage->get_mode() != TextureStage::M_combine) continue;
01256     if (stage->uses_primary_color() && !have_primary_color) {
01257       text << "\t float4 primary_color = result;\n";
01258       have_primary_color = true;
01259     }
01260     if (stage->uses_last_saved_result() && !have_saved_result) {
01261       text << "\t float4 last_saved_result = result;\n";
01262       have_saved_result = true;
01263     }
01264   }
01265 
01266   // Now loop through the textures to compose our magic blending formulas.
01267   for (int i=0; i<_num_textures; i++) {
01268     TextureStage *stage = texture->get_on_stage(i);
01269     switch (stage->get_mode()) {
01270     case TextureStage::M_modulate:
01271       //if the format of the texture is RGB, we simply multiply results
01272       //RGB by the texture's RGB
01273       if (texture->get_on_texture(texture->get_on_stage(i))->get_format() == Texture::F_rgb){
01274         text << "\t result.rgb *= tex" << i << ";\n";
01275       }
01276       //if it's an RGBA texture...multiply by the whole set of values (R,G,B,A) together
01277       //NOTE: if you want an RGBA map as an additional transparency map then this
01278       //will not work correctly. You must store the transparency information either in the alpha channel
01279       //of the color map, or use a separate alpha may with no color info at all (thus it gets treated as
01280       //as F_alpha, not F_RGBA). Also, you can store the alpha map file inside a standard RGB map by
01281       //using the same prefix for both textures.  This is equivalent to RGBA.
01282       else if (texture->get_on_texture(texture->get_on_stage(i))->get_format() == Texture::F_rgba){
01283         text << "\t result.rgba *= tex" << i << ";\n";
01284       }
01285       //if it's an alpha formatted texture (ie. an alpha or mask in a separate texture Ref) then 
01286       //multiply the alpha channels only. That way color of the result is preserved
01287       else if (texture->get_on_texture(texture->get_on_stage(i))->get_format() == Texture::F_alpha){
01288         text << "\t result.a *= tex" << i << ".a;\n";
01289       }
01290       break;
01291     case TextureStage::M_modulate_glow:
01292     case TextureStage::M_modulate_gloss:
01293       //in the case of glow or spec we currently see the specularity evenly across the surface
01294       //even if transparency or masking is present
01295       //not sure if this is desired behavior or not.
01296       //*MOST* would construct a spec map based off of
01297       //what is/isn't seen based on the mask/transparency
01298       //this may have to be left alone for now
01299       //agartner
01300       text << "\t result.rgb *= tex" << i << ";\n";
01301       break;
01302     case TextureStage::M_decal:
01303       text << "\t result.rgb = lerp(result, tex" << i << ", tex" << i << ".a).rgb;\n";
01304       break;
01305     case TextureStage::M_blend: {
01306       LVecBase4 c = stage->get_color();
01307       text << "\t result.rgb = lerp(result, tex" << i << " * float4("
01308            << c[0] << ", " << c[1] << ", " << c[2] << ", " << c[3] << "), tex" << i << ".r).rgb;\n";
01309       break; }
01310     case TextureStage::M_replace:
01311       text << "\t result = tex" << i << ";\n";
01312       break;
01313     case TextureStage::M_add:
01314       text << "\t result.rgb += tex" << i << ".rgb;\n";
01315       if (_calc_primary_alpha) {
01316         text << "\t result.a   *= tex" << i << ".a;\n";
01317       }
01318       break;
01319     case TextureStage::M_combine:
01320       text << "\t result.rgb = ";
01321       if (stage->get_combine_rgb_mode() != TextureStage::CM_undefined) {
01322         text << combine_mode_as_string(stage, stage->get_combine_rgb_mode(), false, i);
01323       } else {
01324         text << "tex" << i << ".rgb";
01325       }
01326       if (stage->get_rgb_scale() != 1) {
01327         text << " * " << stage->get_rgb_scale();
01328       }
01329       text << ";\n\t result.a = ";
01330       if (stage->get_combine_alpha_mode() != TextureStage::CM_undefined) {
01331         text << combine_mode_as_string(stage, stage->get_combine_alpha_mode(), true, i);
01332       } else {
01333         text << "tex" << i << ".a";
01334       }
01335       if (stage->get_alpha_scale() != 1) {
01336         text << " * " << stage->get_alpha_scale();
01337       }
01338       text << ";\n";
01339       break;
01340     case TextureStage::M_blend_color_scale:
01341       text << "\t result.rgb = lerp(result, tex" << i << " * attr_colorscale, tex" << i << ".r).rgb;\n";
01342       break;
01343     default:
01344       break;
01345     }
01346     if (stage->get_saved_result() && have_saved_result) {
01347       text << "\t last_saved_result = result;\n";
01348     }
01349   }
01350   // Apply the color scale.
01351   text << "\t result *= attr_colorscale;\n";
01352 
01353   if (_subsume_alpha_test) {
01354     const AlphaTestAttrib *alpha_test = DCAST(AlphaTestAttrib, rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
01355     text << "\t // Shader includes alpha test:\n";
01356     double ref = alpha_test->get_reference_alpha();
01357     switch (alpha_test->get_mode()) {
01358     case RenderAttrib::M_never:          text<<"\t discard;\n";
01359     case RenderAttrib::M_less:           text<<"\t if (result.a >= "<<ref<<") discard;\n";
01360     case RenderAttrib::M_equal:          text<<"\t if (result.a != "<<ref<<") discard;\n";
01361     case RenderAttrib::M_less_equal:     text<<"\t if (result.a >  "<<ref<<") discard;\n";
01362     case RenderAttrib::M_greater:        text<<"\t if (result.a <= "<<ref<<") discard;\n";
01363     case RenderAttrib::M_not_equal:      text<<"\t if (result.a == "<<ref<<") discard;\n";
01364     case RenderAttrib::M_greater_equal:  text<<"\t if (result.a <  "<<ref<<") discard;\n";
01365     case RenderAttrib::M_none: break;
01366     case RenderAttrib::M_always: break;
01367     }
01368   }
01369 
01370   if (_out_primary_glow) {
01371     if (_map_index_glow >= 0 && _auto_glow_on) {
01372       text << "\t result.a = tex" << _map_index_glow << ".a;\n";
01373     } else {
01374       text << "\t result.a = 0.5;\n";
01375     }
01376   }
01377   if (_out_aux_glow) {
01378     if (_map_index_glow >= 0 && _auto_glow_on) {
01379       text << "\t o_aux.a = tex" << _map_index_glow << ".a;\n";
01380     } else {
01381       text << "\t o_aux.a = 0.5;\n";
01382     }
01383   }
01384 
01385   if (_lighting) {
01386     if (_have_specular) {
01387       if (_material->has_specular()) {
01388         text << "\t tot_specular *= attr_material[3];\n";
01389       }
01390       if (_map_index_gloss >= 0 && _auto_gloss_on) {
01391         text << "\t tot_specular *= tex" << _map_index_gloss << ".a;\n";
01392       }
01393       text << "\t result.rgb = result.rgb + tot_specular.rgb;\n";
01394     }
01395   }
01396   if(_auto_ramp_on) {
01397     const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
01398     switch (light_ramp->get_mode()) {
01399     case LightRampAttrib::LRT_hdr0:
01400       text << "\t result.rgb = (result*result*result + result*result + result) / (result*result*result + result*result + result + 1);\n";
01401       break;
01402     case LightRampAttrib::LRT_hdr1:
01403       text << "\t result.rgb = (result*result + result) / (result*result + result + 1);\n";
01404       break;
01405     case LightRampAttrib::LRT_hdr2:
01406       text << "\t result.rgb = result / (result + 1);\n";
01407       break;
01408     default: break;
01409     }
01410   }
01411 
01412   // Apply fog.
01413   if (_fog) {
01414     const FogAttrib *fog_attr = DCAST(FogAttrib, rs->get_attrib_def(FogAttrib::get_class_slot()));
01415     Fog *fog = fog_attr->get_fog();
01416 
01417     switch (fog->get_mode()) {
01418     case Fog::M_linear:
01419       text << "\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate((attr_fog.z - l_hpos.z) * attr_fog.w));\n";
01420       break;
01421     case Fog::M_exponential:
01422       text << "\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate(exp2(attr_fog.x * l_hpos.z * -1.442695f)));\n";
01423       break;
01424     case Fog::M_exponential_squared:
01425       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";
01426       break;
01427     }
01428   }
01429 
01430   // The multiply is a workaround for a radeon driver bug.
01431   // It's annoying as heck, since it produces an extra instruction.
01432   text << "\t o_color = result * 1.000001;\n";
01433   if (_subsume_alpha_test) {
01434     text << "\t // Shader subsumes normal alpha test.\n";
01435   }
01436   if (_disable_alpha_write) {
01437     text << "\t // Shader disables alpha write.\n";
01438   }
01439   text << "}\n";
01440 
01441   // Insert the shader into the shader attrib.
01442   CPT(RenderAttrib) shattr = create_shader_attrib(text.str());
01443   if (_subsume_alpha_test) {
01444     shattr=DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_subsume_alpha_test, true);
01445   }
01446   if (_disable_alpha_write) {
01447     shattr=DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_disable_alpha_write, true);
01448   }
01449   clear_analysis();
01450   reset_register_allocator();
01451   return shattr;
01452 }
01453 
01454 ////////////////////////////////////////////////////////////////////
01455 //     Function: ShaderGenerator::combine_mode_as_string
01456 //       Access: Protected, Static
01457 //  Description: This 'synthesizes' a combine mode into a string.
01458 ////////////////////////////////////////////////////////////////////
01459 const string ShaderGenerator::
01460 combine_mode_as_string(CPT(TextureStage) stage, TextureStage::CombineMode c_mode, bool alpha, short texindex) {
01461   ostringstream text;
01462   switch (c_mode) {
01463     case TextureStage::CM_modulate:
01464       text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
01465       text << " * ";
01466       text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
01467       break;
01468     case TextureStage::CM_add:
01469       text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
01470       text << " + ";
01471       text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
01472       break;
01473     case TextureStage::CM_add_signed:
01474       pgraph_cat.error() << "TextureStage::CombineMode ADD_SIGNED not yet supported in per-pixel mode.\n";
01475       break;
01476     case TextureStage::CM_interpolate:
01477       text << "lerp(";
01478       text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
01479       text << ", ";
01480       text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
01481       text << ", ";
01482       text << combine_source_as_string(stage, 2, alpha, true, texindex);
01483       text << ")";
01484       break;
01485     case TextureStage::CM_subtract:
01486       text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
01487       text << " + ";
01488       text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
01489       break;
01490     case TextureStage::CM_dot3_rgb:
01491       pgraph_cat.error() << "TextureStage::CombineMode DOT3_RGB not yet supported in per-pixel mode.\n";
01492       break;
01493     case TextureStage::CM_dot3_rgba:
01494       pgraph_cat.error() << "TextureStage::CombineMode DOT3_RGBA not yet supported in per-pixel mode.\n";
01495       break;
01496     case TextureStage::CM_replace:
01497     default: // Not sure if this is correct as default value.
01498       text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
01499       break;
01500   }
01501   return text.str();
01502 }
01503 
01504 ////////////////////////////////////////////////////////////////////
01505 //     Function: ShaderGenerator::combine_source_as_string
01506 //       Access: Protected, Static
01507 //  Description: This 'synthesizes' a combine source into a string.
01508 ////////////////////////////////////////////////////////////////////
01509 const string ShaderGenerator::
01510 combine_source_as_string(CPT(TextureStage) stage, short num, bool alpha, bool single_value, short texindex) {
01511   TextureStage::CombineSource c_src = TextureStage::CS_undefined;
01512   TextureStage::CombineOperand c_op = TextureStage::CO_undefined;
01513   if (alpha) {
01514     switch (num) {
01515       case 0:
01516         c_src = stage->get_combine_alpha_source0();
01517         c_op = stage->get_combine_alpha_operand0();
01518         break;
01519       case 1:
01520         c_src = stage->get_combine_alpha_source1();
01521         c_op = stage->get_combine_alpha_operand1();
01522         break;
01523       case 2:
01524         c_src = stage->get_combine_alpha_source2();
01525         c_op = stage->get_combine_alpha_operand2();
01526         break;
01527     }
01528   } else {
01529     switch (num) {
01530       case 0:
01531         c_src = stage->get_combine_rgb_source0();
01532         c_op = stage->get_combine_rgb_operand0();
01533         break;
01534       case 1:
01535         c_src = stage->get_combine_rgb_source1();
01536         c_op = stage->get_combine_rgb_operand1();
01537         break;
01538       case 2:
01539         c_src = stage->get_combine_rgb_source2();
01540         c_op = stage->get_combine_rgb_operand2();
01541         break;
01542     }
01543   }
01544   ostringstream csource;
01545   if (c_op == TextureStage::CO_one_minus_src_color ||
01546       c_op == TextureStage::CO_one_minus_src_alpha) {
01547     csource << "1.0f - ";
01548   }
01549   switch (c_src) {
01550     case TextureStage::CS_texture:
01551       csource << "tex" << texindex;
01552       break;
01553     case TextureStage::CS_constant: {
01554       LVecBase4 c = stage->get_color();
01555       csource << "float4(" << c[0] << ", " << c[1] << ", " << c[2] << ", " << c[3] << ")";
01556       break; }
01557     case TextureStage::CS_primary_color:
01558       csource << "primary_color";
01559       break;
01560     case TextureStage::CS_previous:
01561       csource << "result";
01562       break;
01563     case TextureStage::CS_constant_color_scale:
01564       csource << "attr_colorscale";
01565       break;
01566     case TextureStage::CS_last_saved_result:
01567       csource << "last_saved_result";
01568       break;
01569     case TextureStage::CS_undefined:
01570       break;
01571   }
01572   if (c_op == TextureStage::CO_src_color || c_op == TextureStage::CO_one_minus_src_color) {
01573     if (single_value) {
01574       // Let's take the red channel.
01575       csource << ".r";
01576     } else {
01577       csource << ".rgb";
01578     }
01579   } else {
01580     csource << ".a";
01581     if (!single_value) {
01582       // Dunno if it's legal in the FPP at all, but let's just allow it.
01583       return "float3(" + csource.str() + ")";
01584     }
01585   }
01586   return csource.str();
01587 }
01588 
01589 ////////////////////////////////////////////////////////////////////
01590 //     Function: ShaderGenerator::texture_type_as_string
01591 //       Access: Protected, Static
01592 //  Description: Returns 1D, 2D, 3D or CUBE, depending on the given
01593 //               texture type.
01594 ////////////////////////////////////////////////////////////////////
01595 const string ShaderGenerator::
01596 texture_type_as_string(Texture::TextureType ttype) {
01597   switch (ttype) {
01598     case Texture::TT_1d_texture:
01599       return "1D";
01600       break;
01601     case Texture::TT_2d_texture:
01602       return "2D";
01603       break;
01604     case Texture::TT_3d_texture:
01605       return "3D";
01606       break;
01607     case Texture::TT_cube_map:
01608       return "CUBE";
01609       break;
01610     default:
01611       pgraph_cat.error() << "Unsupported texture type!\n";
01612       return "2D";
01613   }
01614 }
01615 
 All Classes Functions Variables Enumerations