Panda3D
|
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