csgfx/vertexlight.h
Go to the documentation of this file.00001 /* 00002 Copyright (C) 2005 by Marten Svanfeldt 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public 00015 License along with this library; if not, write to the Free 00016 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 */ 00018 00019 #ifndef __CS_CSGFX_VERTEXLIGHT_H__ 00020 #define __CS_CSGFX_VERTEXLIGHT_H__ 00021 00022 #include "csqsqrt.h" 00023 #include "csgeom/math.h" 00024 #include "csgeom/transfrm.h" 00025 #include "csgeom/vector3.h" 00026 #include "csgfx/lightsvcache.h" 00027 #include "csgfx/vertexlistwalker.h" 00028 #include "csutil/cscolor.h" 00029 #include "cstool/rbuflock.h" 00030 00031 #include "iengine/light.h" 00032 #include "iengine/movable.h" 00033 #include "ivideo/shader/shader.h" 00034 00042 struct csLightProperties 00043 { 00044 protected: 00045 csShaderVariable* LookupSVArrayItem (const csShaderVariableStack& stack, 00046 CS::ShaderVarStringID id, size_t index) 00047 { 00048 csShaderVariable* sv; 00049 if ((stack.GetSize () > id) && ((sv = stack[id]) != 0)) 00050 return sv->GetArrayElement (index); 00051 return 0; 00052 } 00053 csShaderVariable* LookupSV (const csShaderVariableStack& stack, 00054 CS::ShaderVarStringID id) 00055 { 00056 csShaderVariable* sv = 0; 00057 if (stack.GetSize () > id) 00058 sv = stack[id]; 00059 return sv; 00060 } 00061 public: 00063 csVector3 attenuationConsts; 00065 csVector3 posObject; 00070 csVector3 dirObject; 00072 csColor color; 00074 float spotFalloffInner; 00076 float spotFalloffOuter; 00078 csLightType type; 00080 csLightAttenuationMode attenuationMode; 00082 csColor specular; 00083 00084 csLightProperties () : spotFalloffInner(0.0f), spotFalloffOuter(0.0f), 00085 type(CS_LIGHT_POINTLIGHT) {} 00090 csLightProperties (size_t lightNum, csLightShaderVarCache& svcache, 00091 const csShaderVariableStack& stack, 00092 const csReversibleTransform& objectToWorld = csReversibleTransform ()) 00093 { 00094 CS::ShaderVarStringID id; 00095 csShaderVariable* sv; 00096 csVector3 tmp; 00097 00098 id = svcache.GetLightSVId (csLightShaderVarCache::lightAttenuation); 00099 if (((sv = LookupSVArrayItem (stack, id, lightNum)) != 0)) 00100 sv->GetValue (attenuationConsts); 00101 00102 id = svcache.GetLightSVId (csLightShaderVarCache::lightPositionWorld); 00103 if (((sv = LookupSVArrayItem (stack, id, lightNum)) != 0)) 00104 { 00105 sv->GetValue (tmp); 00106 posObject = objectToWorld.Other2This (tmp); 00107 } 00108 00109 id = svcache.GetLightSVId (csLightShaderVarCache::lightDirectionWorld); 00110 if (((sv = LookupSVArrayItem (stack, id, lightNum)) != 0)) 00111 { 00112 sv->GetValue (tmp); 00113 dirObject = objectToWorld.Other2ThisRelative (tmp); 00114 } 00115 00116 id = svcache.GetLightSVId (csLightShaderVarCache::lightDiffuse); 00117 if (((sv = LookupSVArrayItem (stack, id, lightNum)) != 0)) 00118 sv->GetValue (color); 00119 00120 id = svcache.GetLightSVId (csLightShaderVarCache::lightInnerFalloff); 00121 if (((sv = LookupSVArrayItem (stack, id, lightNum)) != 0)) 00122 sv->GetValue (spotFalloffInner); 00123 00124 id = svcache.GetLightSVId (csLightShaderVarCache::lightOuterFalloff); 00125 if (((sv = LookupSVArrayItem (stack, id, lightNum)) != 0)) 00126 sv->GetValue (spotFalloffOuter); 00127 00128 int t = CS_LIGHT_POINTLIGHT; 00129 id = svcache.GetLightSVId (csLightShaderVarCache::lightType); 00130 if (((sv = LookupSV (stack, id)) != 0)) 00131 sv->GetValue (t); 00132 type = (csLightType)t; 00133 00134 t = CS_ATTN_NONE; 00135 id = svcache.GetLightSVId (csLightShaderVarCache::lightAttenuationMode); 00136 if (((sv = LookupSVArrayItem (stack, id, lightNum)) != 0)) 00137 sv->GetValue (t); 00138 attenuationMode = (csLightAttenuationMode)t; 00139 00140 id = svcache.GetLightSVId (csLightShaderVarCache::lightSpecular); 00141 if (((sv = LookupSVArrayItem (stack, id, lightNum)) != 0)) 00142 sv->GetValue (specular); 00143 } 00144 }; 00145 00149 struct csNoAttenuation 00150 { 00151 csNoAttenuation (const csLightProperties& /*light*/) 00152 {} 00153 00154 CS_FORCEINLINE_TEMPLATEMETHOD 00155 void operator() (float /*distance*/, float & /*dp*/) const 00156 {} 00157 }; 00158 00163 struct csLinearAttenuation 00164 { 00165 csLinearAttenuation (const csLightProperties& light) 00166 { 00167 invrad = 1/light.attenuationConsts.x; 00168 } 00169 00170 CS_FORCEINLINE_TEMPLATEMETHOD 00171 void operator() (float distance, float& dp) const 00172 { 00173 dp = csMax (dp * (1 - distance * invrad), 0.0f); 00174 } 00175 00176 float invrad; 00177 }; 00178 00183 struct csInverseAttenuation 00184 { 00185 csInverseAttenuation (const csLightProperties& /*light*/) 00186 {} 00187 00188 CS_FORCEINLINE_TEMPLATEMETHOD 00189 void operator() (float distance, float& dp) const 00190 { 00191 dp = dp / distance; 00192 } 00193 }; 00194 00195 00200 struct csRealisticAttenuation 00201 { 00202 csRealisticAttenuation (const csLightProperties& /*light*/) 00203 {} 00204 00205 CS_FORCEINLINE_TEMPLATEMETHOD 00206 void operator() (float distance, float& dp) const 00207 { 00208 dp = dp / (distance*distance); 00209 } 00210 }; 00211 00216 struct csCLQAttenuation 00217 { 00218 csCLQAttenuation (const csLightProperties& light) 00219 : attnVec (light.attenuationConsts) 00220 {} 00221 00222 CS_FORCEINLINE_TEMPLATEMETHOD 00223 void operator() (float distance, float& dp) const 00224 { 00225 dp = dp/(csVector3 (1.0, distance, distance*distance)*attnVec); 00226 } 00227 00228 csVector3 attnVec; 00229 }; 00230 00231 00237 template<class AttenuationProc> 00238 class csPointLightProc 00239 { 00240 public: 00241 csPointLightProc (const csLightProperties& light, float blackLimit = 0.0001f) 00242 : attn (light), blackLimit (blackLimit) 00243 { 00244 lightPos = light.posObject; 00245 } 00246 class PerVertex 00247 { 00248 csVector3 direction; 00249 float invDistance; 00250 float a; 00251 float dp; 00252 bool vertexLit; 00253 public: 00254 CS_FORCEINLINE_TEMPLATEMETHOD 00255 PerVertex (const csPointLightProc& parent, const csVector3 &v, 00256 const csVector3 &n) 00257 { 00258 direction = parent.lightPos-v; 00259 float distance = csQsqrt (direction.SquaredNorm ()); 00260 invDistance = 1.0f/distance; 00261 dp = (direction*n) * invDistance; 00262 if ((vertexLit = (dp > parent.blackLimit))) 00263 { 00264 a = 1.0f; 00265 parent.attn (distance, a); 00266 } 00267 else 00268 a = 0.0f; 00269 } 00270 bool IsLit() const { return vertexLit; } 00271 float Attenuation() const { return a; } 00272 float DiffuseAttenuated() const { return a*dp; } 00273 const csVector3& LightDirection() const { return direction; } 00274 const float LightInvDistance() const { return invDistance; } 00275 }; 00276 private: 00277 AttenuationProc attn; 00278 csVector3 lightPos; //localspace 00279 float blackLimit; 00280 }; 00281 00287 template<class AttenuationProc> 00288 class csDirectionalLightProc 00289 { 00290 public: 00291 csDirectionalLightProc (const csLightProperties& light, 00292 float blackLimit = 0.0001f) : attn (light), 00293 blackLimit (blackLimit) 00294 { 00295 lightPos = light.posObject; 00296 lightDir = light.dirObject; 00297 } 00298 class PerVertex 00299 { 00300 csVector3 direction; 00301 float invDistance; 00302 float a; 00303 float dp; 00304 bool vertexLit; 00305 public: 00306 CS_FORCEINLINE_TEMPLATEMETHOD 00307 PerVertex (const csDirectionalLightProc& parent, const csVector3 &v, 00308 const csVector3 &n) 00309 { 00310 //compute gouraud shading.. 00311 dp = -parent.lightDir*n; 00312 if ((vertexLit = (dp > parent.blackLimit))) 00313 { 00314 csVector3 direction = parent.lightPos-v; 00315 a = 1.0f; 00316 float distance = csQsqrt(direction.SquaredNorm ()); 00317 invDistance = 1.0f/distance; 00318 parent.attn (distance, a); 00319 } 00320 else 00321 { 00322 direction = csVector3 (0); 00323 invDistance = 0.0f; 00324 a = 0.0f; 00325 } 00326 } 00327 bool IsLit() const { return vertexLit; } 00328 float Attenuation() const { return a; } 00329 float DiffuseAttenuated() const { return a*dp; } 00330 const csVector3& LightDirection() const { return direction; } 00331 const float LightInvDistance() const { return invDistance; } 00332 }; 00333 private: 00334 AttenuationProc attn; 00335 csVector3 lightPos; //localspace 00336 csVector3 lightDir; //localspace 00337 float blackLimit; 00338 }; 00339 00345 template<class AttenuationProc> 00346 class csSpotLightProc 00347 { 00348 public: 00349 csSpotLightProc (const csLightProperties& light, 00350 float blackLimit = 0.0001f) : attn (light), 00351 blackLimit (blackLimit) 00352 { 00353 lightPos = light.posObject; 00354 lightDir = light.dirObject; 00355 00356 falloffInner = light.spotFalloffInner; 00357 falloffOuter = light.spotFalloffOuter; 00358 } 00359 00360 class PerVertex 00361 { 00362 csVector3 direction; 00363 float invDistance; 00364 float a; 00365 float cosfact; 00366 bool vertexLit; 00367 public: 00368 CS_FORCEINLINE_TEMPLATEMETHOD 00369 PerVertex (const csSpotLightProc& parent, const csVector3 &v, 00370 const csVector3 &n) 00371 { 00372 //compute gouraud shading.. 00373 direction = parent.lightPos-v; 00374 csVector3 dirUnit (direction.Unit ()); 00375 00376 //compute gouraud shading.. 00377 float dp = dirUnit*n; 00378 if (dp > parent.blackLimit) 00379 { 00380 cosfact = 00381 csSmoothStep (-(dirUnit*parent.lightDir), 00382 parent.falloffInner, parent.falloffOuter); 00383 if ((vertexLit = (cosfact > 0))) 00384 { 00385 cosfact *= dp; 00386 float distance = csQsqrt(direction.SquaredNorm ()); 00387 invDistance = 1.0f/distance; 00388 a = 1.0f; 00389 parent.attn (distance, a); 00390 } 00391 else 00392 { 00393 invDistance = 0.0f; 00394 a = 0.0f; 00395 } 00396 } 00397 else 00398 { 00399 invDistance = 0.0f; 00400 a = 0.0f; 00401 cosfact = 0.0f; 00402 vertexLit = false; 00403 } 00404 } 00405 bool IsLit() const { return vertexLit; } 00406 float Attenuation() const { return a; } 00407 float DiffuseAttenuated() const { return a*cosfact; } 00408 const csVector3& LightDirection() const { return direction; } 00409 const float LightInvDistance() const { return invDistance; } 00410 }; 00411 private: 00412 AttenuationProc attn; 00413 csVector3 lightPos; //localspace 00414 csVector3 lightDir; //localspace 00415 float blackLimit; 00416 float falloffInner, falloffOuter; 00417 }; 00418 00422 struct iVertexLightCalculator 00423 { 00424 public: 00425 virtual ~iVertexLightCalculator() {} 00426 00438 virtual void CalculateLighting (const csLightProperties& light, 00439 const csVector3& eyePos, float shininess, 00440 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00441 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const = 0; 00442 00447 virtual void CalculateLightingAdd (const csLightProperties& light, 00448 const csVector3& eyePos, float shininess, 00449 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00450 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const = 0; 00451 00456 virtual void CalculateLightingMul (const csLightProperties& light, 00457 const csVector3& eyePos, float shininess, 00458 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00459 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const = 0; 00460 }; 00461 00467 template<class LightProc> 00468 class csVertexLightCalculator : public iVertexLightCalculator 00469 { 00470 struct OpAssign 00471 { 00472 OpAssign (csColor& d, const csColor& x) { d = x; } 00473 }; 00474 struct OpAdd 00475 { 00476 OpAdd (csColor& d, const csColor& x) { d += x; } 00477 }; 00478 struct OpMul 00479 { 00480 OpMul (csColor& d, const csColor& x) { d *= x; } 00481 }; 00482 00483 #include "csutil/custom_new_disable.h" 00484 00485 template<typename T, bool B> 00486 class ConditionalAlloc 00487 { 00488 char _data[(sizeof(T) + sizeof(void*) - 1) / sizeof(char)]; 00489 CS_FORCEINLINE_TEMPLATEMETHOD char* Data() 00490 { 00491 uintptr_t p = reinterpret_cast<uintptr_t> (_data); 00492 const int align = sizeof(void*); 00493 p = (p + align - 1) & ~(align - 1); 00494 return reinterpret_cast<char*> (p); 00495 } 00496 public: 00497 template<typename P1> 00498 ConditionalAlloc (const P1& a) 00499 { 00500 if (B) new (Data()) T (a); 00501 } 00502 ~ConditionalAlloc() 00503 { 00504 if (B) GetObject().~T(); 00505 } 00506 00507 T& GetObject() 00508 { 00509 CS_ASSERT(B); 00510 return *(reinterpret_cast<T*> (Data())); 00511 } 00512 }; 00513 00514 #include "csutil/custom_new_enable.h" 00515 00516 template<typename Op, bool zeroDest, bool diffuse, bool specular> 00517 void CalculateLightingODS (const csLightProperties& light, 00518 const csVector3& eyePos, float shininess, 00519 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00520 iRenderBuffer* litColor, iRenderBuffer* specColor) const 00521 { 00522 if (!diffuse && !specular) return; 00523 00524 // setup the light calculator 00525 LightProc lighter (light); 00526 csVertexListWalker<float, csVector3> vbLock (vb, 3); 00527 csVertexListWalker<float, csVector3> nbLock (nb, 3); 00528 ConditionalAlloc<csRenderBufferLock<csColor, iRenderBuffer*>, 00529 diffuse> color (litColor); 00530 ConditionalAlloc<csRenderBufferLock<csColor, iRenderBuffer*>, 00531 specular> spec (specColor); 00532 00533 for (size_t i = 0; i < numvert; i++) 00534 { 00535 const csVector3 v (*vbLock); 00536 const csVector3 n (*nbLock); 00537 typename LightProc::PerVertex pv (lighter, v, n); 00538 if (pv.IsLit()) 00539 { 00540 if (diffuse) 00541 { 00542 Op op (color.GetObject()[i], pv.DiffuseAttenuated() * light.color); 00543 } 00544 if (specular) 00545 { 00546 csVector3 vertToEye = eyePos - v; 00547 csVector3 halfvec = pv.LightDirection() * pv.LightInvDistance(); 00548 halfvec += vertToEye.Unit(); 00549 float specDP = halfvec.Unit() * n; 00550 Op op (spec.GetObject()[i], pow (specDP, shininess) * light.specular * pv.Attenuation()); 00551 } 00552 } 00553 else if (zeroDest) 00554 { 00555 csColor nullColor (0.0f, 0.0f, 0.0f); 00556 if (diffuse) 00557 { 00558 Op op (color.GetObject()[i], nullColor); 00559 } 00560 if (specular) 00561 { 00562 Op op (spec.GetObject()[i], nullColor); 00563 } 00564 } 00565 ++vbLock; ++nbLock; 00566 } 00567 } 00568 template<typename Op, bool zeroDest, bool diffuse> 00569 void CalculateLightingOD (const csLightProperties& light, 00570 const csVector3& eyePos, float shininess, 00571 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00572 iRenderBuffer* litColor, iRenderBuffer* specColor) const 00573 { 00574 if (specColor != 0) 00575 CalculateLightingODS<Op, zeroDest, diffuse, true> (light, eyePos, 00576 shininess, numvert, vb, nb, litColor, specColor); 00577 else 00578 CalculateLightingODS<Op, zeroDest, diffuse, false> (light, eyePos, 00579 shininess, numvert, vb, nb, litColor, specColor); 00580 } 00581 template<typename Op, bool zeroDest> 00582 void CalculateLightingO (const csLightProperties& light, 00583 const csVector3& eyePos, float shininess, 00584 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00585 iRenderBuffer* litColor, iRenderBuffer* specColor) const 00586 { 00587 if (litColor != 0) 00588 CalculateLightingOD<Op, zeroDest, true> (light, eyePos, shininess, 00589 numvert, vb, nb, litColor, specColor); 00590 else 00591 CalculateLightingOD<Op, zeroDest, false> (light, eyePos, shininess, 00592 numvert, vb, nb, litColor, specColor); 00593 } 00594 public: 00595 virtual void CalculateLighting (const csLightProperties& light, 00596 const csVector3& eyePos, float shininess, 00597 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00598 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const 00599 { 00600 CalculateLightingO<OpAssign, true> (light, eyePos, shininess, 00601 numvert, vb, nb, litColor, specColor); 00602 } 00603 00604 virtual void CalculateLightingAdd (const csLightProperties& light, 00605 const csVector3& eyePos, float shininess, 00606 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00607 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const 00608 { 00609 CalculateLightingO<OpAdd, false> (light, eyePos, shininess, numvert, 00610 vb, nb, litColor, specColor); 00611 } 00612 00613 virtual void CalculateLightingMul (const csLightProperties& light, 00614 const csVector3& eyePos, float shininess, 00615 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00616 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const 00617 { 00618 CalculateLightingO<OpMul, false> (light, eyePos, shininess, numvert, 00619 vb, nb, litColor, specColor); 00620 } 00621 }; 00622 00623 #endif //__CS_VERTEXLIGHT_H__
Generated for Crystal Space 2.0 by doxygen 1.6.1
