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 { 00045 csVector3 attenuationConsts; 00047 csVector3 posObject; 00052 csVector3 dirObject; 00054 csColor color; 00056 float spotFalloffInner; 00058 float spotFalloffOuter; 00060 csLightType type; 00062 csLightAttenuationMode attenuationMode; 00064 csColor specular; 00065 00066 csLightProperties () : spotFalloffInner(0.0f), spotFalloffOuter(0.0f), 00067 type(CS_LIGHT_POINTLIGHT) {} 00072 csLightProperties (size_t lightNum, csLightShaderVarCache& svcache, 00073 const iShaderVarStack* Stacks) 00074 { 00075 csStringID id; 00076 csShaderVariable* sv; 00077 const iArrayReadOnly<csShaderVariable*>* stacks = Stacks; 00078 00079 id = svcache.GetLightSVId (lightNum, 00080 csLightShaderVarCache::lightAttenuation); 00081 if ((stacks->GetSize() > id) && ((sv = stacks->Get (id)) != 0)) 00082 sv->GetValue (attenuationConsts); 00083 00084 id = svcache.GetLightSVId (lightNum, 00085 csLightShaderVarCache::lightPosition); 00086 if ((stacks->GetSize() > id) && ((sv = stacks->Get (id)) != 0)) 00087 sv->GetValue (posObject); 00088 00089 id = svcache.GetLightSVId (lightNum, 00090 csLightShaderVarCache::lightDirection); 00091 if ((stacks->GetSize() > id) && ((sv = stacks->Get (id)) != 0)) 00092 sv->GetValue (dirObject); 00093 00094 id = svcache.GetLightSVId (lightNum, 00095 csLightShaderVarCache::lightDiffuse); 00096 if ((stacks->GetSize() > id) && ((sv = stacks->Get (id)) != 0)) 00097 sv->GetValue (color); 00098 00099 id = svcache.GetLightSVId (lightNum, 00100 csLightShaderVarCache::lightInnerFalloff); 00101 if ((stacks->GetSize() > id) && ((sv = stacks->Get (id)) != 0)) 00102 sv->GetValue (spotFalloffInner); 00103 00104 id = svcache.GetLightSVId (lightNum, 00105 csLightShaderVarCache::lightOuterFalloff); 00106 if ((stacks->GetSize() > id) && ((sv = stacks->Get (id)) != 0)) 00107 sv->GetValue (spotFalloffOuter); 00108 00109 int t = CS_LIGHT_POINTLIGHT; 00110 id = svcache.GetLightSVId (lightNum, 00111 csLightShaderVarCache::lightType); 00112 if ((stacks->GetSize() > id) && ((sv = stacks->Get (id)) != 0)) 00113 sv->GetValue (t); 00114 type = (csLightType)t; 00115 00116 t = CS_ATTN_NONE; 00117 id = svcache.GetLightSVId (lightNum, 00118 csLightShaderVarCache::lightAttenuationMode); 00119 if ((stacks->GetSize() > id) && ((sv = stacks->Get (id)) != 0)) 00120 sv->GetValue (t); 00121 attenuationMode = (csLightAttenuationMode)t; 00122 00123 id = svcache.GetLightSVId (lightNum, 00124 csLightShaderVarCache::lightSpecular); 00125 if ((stacks->GetSize() > id) && ((sv = stacks->Get (id)) != 0)) 00126 sv->GetValue (specular); 00127 } 00128 }; 00129 00133 struct csNoAttenuation 00134 { 00135 csNoAttenuation (const csLightProperties& /*light*/) 00136 {} 00137 00138 CS_FORCEINLINE_TEMPLATEMETHOD 00139 void operator() (float /*distance*/, float & /*dp*/) const 00140 {} 00141 }; 00142 00147 struct csLinearAttenuation 00148 { 00149 csLinearAttenuation (const csLightProperties& light) 00150 { 00151 invrad = 1/light.attenuationConsts.x; 00152 } 00153 00154 CS_FORCEINLINE_TEMPLATEMETHOD 00155 void operator() (float distance, float& dp) const 00156 { 00157 dp = csMax (dp * (1 - distance * invrad), 0.0f); 00158 } 00159 00160 float invrad; 00161 }; 00162 00167 struct csInverseAttenuation 00168 { 00169 csInverseAttenuation (const csLightProperties& /*light*/) 00170 {} 00171 00172 CS_FORCEINLINE_TEMPLATEMETHOD 00173 void operator() (float distance, float& dp) const 00174 { 00175 dp = dp / distance; 00176 } 00177 }; 00178 00179 00184 struct csRealisticAttenuation 00185 { 00186 csRealisticAttenuation (const csLightProperties& /*light*/) 00187 {} 00188 00189 CS_FORCEINLINE_TEMPLATEMETHOD 00190 void operator() (float distance, float& dp) const 00191 { 00192 dp = dp / (distance*distance); 00193 } 00194 }; 00195 00200 struct csCLQAttenuation 00201 { 00202 csCLQAttenuation (const csLightProperties& light) 00203 : attnVec (light.attenuationConsts) 00204 {} 00205 00206 CS_FORCEINLINE_TEMPLATEMETHOD 00207 void operator() (float distance, float& dp) const 00208 { 00209 dp = dp/(csVector3 (1.0, distance, distance*distance)*attnVec); 00210 } 00211 00212 csVector3 attnVec; 00213 }; 00214 00215 00221 template<class AttenuationProc> 00222 class csPointLightProc 00223 { 00224 public: 00225 csPointLightProc (const csLightProperties& light, float blackLimit = 0.0001f) 00226 : attn (light), blackLimit (blackLimit) 00227 { 00228 lightPos = light.posObject; 00229 } 00230 class PerVertex 00231 { 00232 csVector3 direction; 00233 float invDistance; 00234 float a; 00235 float dp; 00236 bool vertexLit; 00237 public: 00238 CS_FORCEINLINE_TEMPLATEMETHOD 00239 PerVertex (const csPointLightProc& parent, const csVector3 &v, 00240 const csVector3 &n) 00241 { 00242 direction = parent.lightPos-v; 00243 float distance = csQsqrt (direction.SquaredNorm ()); 00244 invDistance = 1.0f/distance; 00245 dp = (direction*n) * invDistance; 00246 if ((vertexLit = (dp > parent.blackLimit))) 00247 { 00248 a = 1.0f; 00249 parent.attn (distance, a); 00250 } 00251 else 00252 a = 0.0f; 00253 } 00254 bool IsLit() const { return vertexLit; } 00255 float Attenuation() const { return a; } 00256 float DiffuseAttenuated() const { return a*dp; } 00257 const csVector3& LightDirection() const { return direction; } 00258 const float LightInvDistance() const { return invDistance; } 00259 }; 00260 private: 00261 AttenuationProc attn; 00262 csVector3 lightPos; //localspace 00263 float blackLimit; 00264 }; 00265 00271 template<class AttenuationProc> 00272 class csDirectionalLightProc 00273 { 00274 public: 00275 csDirectionalLightProc (const csLightProperties& light, 00276 float blackLimit = 0.0001f) : attn (light), 00277 blackLimit (blackLimit) 00278 { 00279 lightPos = light.posObject; 00280 lightDir = light.dirObject; 00281 } 00282 class PerVertex 00283 { 00284 csVector3 direction; 00285 float invDistance; 00286 float a; 00287 float dp; 00288 bool vertexLit; 00289 public: 00290 CS_FORCEINLINE_TEMPLATEMETHOD 00291 PerVertex (const csDirectionalLightProc& parent, const csVector3 &v, 00292 const csVector3 &n) 00293 { 00294 //compute gouraud shading.. 00295 dp = -parent.lightDir*n; 00296 if ((vertexLit = (dp > parent.blackLimit))) 00297 { 00298 csVector3 direction = parent.lightPos-v; 00299 a = 1.0f; 00300 float distance = csQsqrt(direction.SquaredNorm ()); 00301 invDistance = 1.0f/distance; 00302 parent.attn (distance, a); 00303 } 00304 else 00305 { 00306 invDistance = 0.0f; 00307 a = 0.0f; 00308 } 00309 } 00310 bool IsLit() const { return vertexLit; } 00311 float Attenuation() const { return a; } 00312 float DiffuseAttenuated() const { return a*dp; } 00313 const csVector3& LightDirection() const { return direction; } 00314 const float LightInvDistance() const { return invDistance; } 00315 }; 00316 private: 00317 AttenuationProc attn; 00318 csVector3 lightPos; //localspace 00319 csVector3 lightDir; //localspace 00320 float blackLimit; 00321 }; 00322 00328 template<class AttenuationProc> 00329 class csSpotLightProc 00330 { 00331 public: 00332 csSpotLightProc (const csLightProperties& light, 00333 float blackLimit = 0.0001f) : attn (light), 00334 blackLimit (blackLimit) 00335 { 00336 lightPos = light.posObject; 00337 lightDir = light.dirObject; 00338 00339 falloffInner = light.spotFalloffInner; 00340 falloffOuter = light.spotFalloffOuter; 00341 } 00342 00343 class PerVertex 00344 { 00345 csVector3 direction; 00346 float invDistance; 00347 float a; 00348 float cosfact; 00349 bool vertexLit; 00350 public: 00351 CS_FORCEINLINE_TEMPLATEMETHOD 00352 PerVertex (const csSpotLightProc& parent, const csVector3 &v, 00353 const csVector3 &n) 00354 { 00355 //compute gouraud shading.. 00356 direction = parent.lightPos-v; 00357 csVector3 dirUnit (direction.Unit ()); 00358 00359 //compute gouraud shading.. 00360 float dp = dirUnit*n; 00361 if (dp > parent.blackLimit) 00362 { 00363 cosfact = 00364 csSmoothStep (-(dirUnit*parent.lightDir), 00365 parent.falloffInner, parent.falloffOuter); 00366 if ((vertexLit = (cosfact > 0))) 00367 { 00368 cosfact *= dp; 00369 float distance = csQsqrt(direction.SquaredNorm ()); 00370 invDistance = 1.0f/distance; 00371 a = 1.0f; 00372 parent.attn (distance, a); 00373 } 00374 else 00375 { 00376 invDistance = 0.0f; 00377 a = 0.0f; 00378 } 00379 } 00380 else 00381 { 00382 invDistance = 0.0f; 00383 a = 0.0f; 00384 cosfact = 0.0f; 00385 vertexLit = false; 00386 } 00387 } 00388 bool IsLit() const { return vertexLit; } 00389 float Attenuation() const { return a; } 00390 float DiffuseAttenuated() const { return a*cosfact; } 00391 const csVector3& LightDirection() const { return direction; } 00392 const float LightInvDistance() const { return invDistance; } 00393 }; 00394 private: 00395 AttenuationProc attn; 00396 csVector3 lightPos; //localspace 00397 csVector3 lightDir; //localspace 00398 float blackLimit; 00399 float falloffInner, falloffOuter; 00400 }; 00401 00405 struct iVertexLightCalculator 00406 { 00407 public: 00408 virtual ~iVertexLightCalculator() {} 00409 00421 virtual void CalculateLighting (const csLightProperties& light, 00422 const csVector3& eyePos, float shininess, 00423 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00424 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const = 0; 00425 00430 virtual void CalculateLightingAdd (const csLightProperties& light, 00431 const csVector3& eyePos, float shininess, 00432 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00433 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const = 0; 00434 00439 virtual void CalculateLightingMul (const csLightProperties& light, 00440 const csVector3& eyePos, float shininess, 00441 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00442 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const = 0; 00443 }; 00444 00450 template<class LightProc> 00451 class csVertexLightCalculator : public iVertexLightCalculator 00452 { 00453 struct OpAssign 00454 { 00455 OpAssign (csColor& d, const csColor& x) { d = x; } 00456 }; 00457 struct OpAdd 00458 { 00459 OpAdd (csColor& d, const csColor& x) { d += x; } 00460 }; 00461 struct OpMul 00462 { 00463 OpMul (csColor& d, const csColor& x) { d *= x; } 00464 }; 00465 template<typename Op, int zeroDest, int diffuse, int specular> 00466 void CalculateLightingODS (const csLightProperties& light, 00467 const csVector3& eyePos, float shininess, 00468 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00469 iRenderBuffer* litColor, iRenderBuffer* specColor) const 00470 { 00471 if (!diffuse && !specular) return; 00472 00473 // setup the light calculator 00474 LightProc lighter (light); 00475 csVertexListWalker<float, csVector3> vbLock (vb, 3); 00476 csVertexListWalker<float, csVector3> nbLock (nb, 3); 00477 csRenderBufferLock<csColor, iRenderBuffer*> color (litColor); 00478 csRenderBufferLock<csColor, iRenderBuffer*> spec (specColor); 00479 00480 for (size_t i = 0; i < numvert; i++) 00481 { 00482 const csVector3 v (*vbLock); 00483 const csVector3 n (*nbLock); 00484 typename LightProc::PerVertex pv (lighter, v, n); 00485 if (pv.IsLit()) 00486 { 00487 if (diffuse) 00488 { 00489 Op op (color[i], pv.DiffuseAttenuated() * light.color); 00490 } 00491 if (specular) 00492 { 00493 csVector3 vertToEye = eyePos - v; 00494 csVector3 halfvec = pv.LightDirection() * pv.LightInvDistance(); 00495 halfvec += vertToEye.Unit(); 00496 float specDP = halfvec.Unit() * n; 00497 Op op (spec[i], pow (specDP, shininess) * light.specular * pv.Attenuation()); 00498 } 00499 } 00500 else if (zeroDest) 00501 { 00502 csColor nullColor (0.0f, 0.0f, 0.0f); 00503 if (diffuse) 00504 { 00505 Op op (color[i], nullColor); 00506 } 00507 if (specular) 00508 { 00509 Op op (spec[i], nullColor); 00510 } 00511 } 00512 ++vbLock; ++nbLock; 00513 } 00514 } 00515 template<typename Op, int zeroDest, int diffuse> 00516 void CalculateLightingOD (const csLightProperties& light, 00517 const csVector3& eyePos, float shininess, 00518 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00519 iRenderBuffer* litColor, iRenderBuffer* specColor) const 00520 { 00521 if (specColor != 0) 00522 CalculateLightingODS<Op, zeroDest, diffuse, 1> (light, eyePos, shininess, 00523 numvert, vb, nb, litColor, specColor); 00524 else 00525 CalculateLightingODS<Op, zeroDest, diffuse, 0> (light, eyePos, shininess, 00526 numvert, vb, nb, litColor, specColor); 00527 } 00528 template<typename Op, int zeroDest> 00529 void CalculateLightingO (const csLightProperties& light, 00530 const csVector3& eyePos, float shininess, 00531 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00532 iRenderBuffer* litColor, iRenderBuffer* specColor) const 00533 { 00534 if (litColor != 0) 00535 CalculateLightingOD<Op, zeroDest, 1> (light, eyePos, shininess, numvert, 00536 vb, nb, litColor, specColor); 00537 else 00538 CalculateLightingOD<Op, zeroDest, 0> (light, eyePos, shininess, numvert, 00539 vb, nb, litColor, specColor); 00540 } 00541 public: 00542 virtual void CalculateLighting (const csLightProperties& light, 00543 const csVector3& eyePos, float shininess, 00544 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00545 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const 00546 { 00547 CalculateLightingO<OpAssign, 1> (light, eyePos, shininess, 00548 numvert, vb, nb, litColor, specColor); 00549 } 00550 00551 virtual void CalculateLightingAdd (const csLightProperties& light, 00552 const csVector3& eyePos, float shininess, 00553 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00554 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const 00555 { 00556 CalculateLightingO<OpAdd, 0> (light, eyePos, shininess, numvert, vb, nb, 00557 litColor, specColor); 00558 } 00559 00560 virtual void CalculateLightingMul (const csLightProperties& light, 00561 const csVector3& eyePos, float shininess, 00562 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00563 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const 00564 { 00565 CalculateLightingO<OpMul, 0> (light, eyePos, shininess, numvert, vb, nb, 00566 litColor, specColor); 00567 } 00568 }; 00569 00570 #endif //__CS_VERTEXLIGHT_H__
Generated for Crystal Space 1.4.0 by doxygen 1.5.8