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 } 00252 bool IsLit() const { return vertexLit; } 00253 float Attenuation() const { return a; } 00254 float DiffuseAttenuated() const { return a*dp; } 00255 const csVector3& LightDirection() const { return direction; } 00256 const float LightInvDistance() const { return invDistance; } 00257 }; 00258 private: 00259 AttenuationProc attn; 00260 csVector3 lightPos; //localspace 00261 float blackLimit; 00262 }; 00263 00269 template<class AttenuationProc> 00270 class csDirectionalLightProc 00271 { 00272 public: 00273 csDirectionalLightProc (const csLightProperties& light, 00274 float blackLimit = 0.0001f) : attn (light), 00275 blackLimit (blackLimit) 00276 { 00277 lightPos = light.posObject; 00278 lightDir = light.dirObject; 00279 } 00280 class PerVertex 00281 { 00282 csVector3 direction; 00283 float invDistance; 00284 float a; 00285 float dp; 00286 bool vertexLit; 00287 public: 00288 CS_FORCEINLINE_TEMPLATEMETHOD 00289 PerVertex (const csDirectionalLightProc& parent, const csVector3 &v, 00290 const csVector3 &n) 00291 { 00292 //compute gouraud shading.. 00293 dp = -parent.lightDir*n; 00294 if ((vertexLit = (dp > parent.blackLimit))) 00295 { 00296 csVector3 direction = parent.lightPos-v; 00297 a = 1.0f; 00298 float distance = csQsqrt(direction.SquaredNorm ()); 00299 invDistance = 1.0f/distance; 00300 parent.attn (distance, a); 00301 } 00302 } 00303 bool IsLit() const { return vertexLit; } 00304 float Attenuation() const { return a; } 00305 float DiffuseAttenuated() const { return a*dp; } 00306 const csVector3& LightDirection() const { return direction; } 00307 const float LightInvDistance() const { return invDistance; } 00308 }; 00309 private: 00310 AttenuationProc attn; 00311 csVector3 lightPos; //localspace 00312 csVector3 lightDir; //localspace 00313 float blackLimit; 00314 }; 00315 00321 template<class AttenuationProc> 00322 class csSpotLightProc 00323 { 00324 public: 00325 csSpotLightProc (const csLightProperties& light, 00326 float blackLimit = 0.0001f) : attn (light), 00327 blackLimit (blackLimit) 00328 { 00329 lightPos = light.posObject; 00330 lightDir = light.dirObject; 00331 00332 falloffInner = light.spotFalloffInner; 00333 falloffOuter = light.spotFalloffOuter; 00334 } 00335 00336 class PerVertex 00337 { 00338 csVector3 direction; 00339 float invDistance; 00340 float a; 00341 float cosfact; 00342 bool vertexLit; 00343 public: 00344 CS_FORCEINLINE_TEMPLATEMETHOD 00345 PerVertex (const csSpotLightProc& parent, const csVector3 &v, 00346 const csVector3 &n) 00347 { 00348 //compute gouraud shading.. 00349 direction = parent.lightPos-v; 00350 csVector3 dirUnit (direction.Unit ()); 00351 00352 //compute gouraud shading.. 00353 float dp = dirUnit*n; 00354 if (dp > parent.blackLimit) 00355 { 00356 cosfact = 00357 csSmoothStep (-(dirUnit*parent.lightDir), 00358 parent.falloffInner, parent.falloffOuter); 00359 if ((vertexLit = (cosfact > 0))) 00360 { 00361 cosfact *= dp; 00362 float distance = csQsqrt(direction.SquaredNorm ()); 00363 invDistance = 1.0f/distance; 00364 a = 1.0f; 00365 parent.attn (distance, a); 00366 } 00367 } 00368 else 00369 vertexLit = false; 00370 } 00371 bool IsLit() const { return vertexLit; } 00372 float Attenuation() const { return a; } 00373 float DiffuseAttenuated() const { return a*cosfact; } 00374 const csVector3& LightDirection() const { return direction; } 00375 const float LightInvDistance() const { return invDistance; } 00376 }; 00377 private: 00378 AttenuationProc attn; 00379 csVector3 lightPos; //localspace 00380 csVector3 lightDir; //localspace 00381 float blackLimit; 00382 float falloffInner, falloffOuter; 00383 }; 00384 00388 struct iVertexLightCalculator 00389 { 00390 public: 00391 virtual ~iVertexLightCalculator() {} 00392 00404 virtual void CalculateLighting (const csLightProperties& light, 00405 const csVector3& eyePos, float shininess, 00406 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00407 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const = 0; 00408 00413 virtual void CalculateLightingAdd (const csLightProperties& light, 00414 const csVector3& eyePos, float shininess, 00415 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00416 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const = 0; 00417 00422 virtual void CalculateLightingMul (const csLightProperties& light, 00423 const csVector3& eyePos, float shininess, 00424 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00425 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const = 0; 00426 }; 00427 00433 template<class LightProc> 00434 class csVertexLightCalculator : public iVertexLightCalculator 00435 { 00436 struct OpAssign 00437 { 00438 OpAssign (csColor& d, const csColor& x) { d = x; } 00439 }; 00440 struct OpAdd 00441 { 00442 OpAdd (csColor& d, const csColor& x) { d += x; } 00443 }; 00444 struct OpMul 00445 { 00446 OpMul (csColor& d, const csColor& x) { d *= x; } 00447 }; 00448 template<typename Op, int zeroDest, int diffuse, int specular> 00449 void CalculateLightingODS (const csLightProperties& light, 00450 const csVector3& eyePos, float shininess, 00451 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00452 iRenderBuffer* litColor, iRenderBuffer* specColor) const 00453 { 00454 if (!diffuse && !specular) return; 00455 00456 // setup the light calculator 00457 LightProc lighter (light); 00458 csVertexListWalker<float, csVector3> vbLock (vb, 3); 00459 csVertexListWalker<float, csVector3> nbLock (nb, 3); 00460 csRenderBufferLock<csColor, iRenderBuffer*> color (litColor); 00461 csRenderBufferLock<csColor, iRenderBuffer*> spec (specColor); 00462 00463 for (size_t i = 0; i < numvert; i++) 00464 { 00465 const csVector3 v (*vbLock); 00466 const csVector3 n (*nbLock); 00467 typename LightProc::PerVertex pv (lighter, v, n); 00468 if (pv.IsLit()) 00469 { 00470 if (diffuse) 00471 { 00472 Op op (color[i], pv.DiffuseAttenuated() * light.color); 00473 } 00474 if (specular) 00475 { 00476 csVector3 vertToEye = eyePos - v; 00477 csVector3 halfvec = pv.LightDirection() * pv.LightInvDistance(); 00478 halfvec += vertToEye.Unit(); 00479 float specDP = halfvec.Unit() * n; 00480 Op op (spec[i], pow (specDP, shininess) * light.specular * pv.Attenuation()); 00481 } 00482 } 00483 else if (zeroDest) 00484 { 00485 csColor nullColor (0.0f, 0.0f, 0.0f); 00486 if (diffuse) 00487 { 00488 Op op (color[i], nullColor); 00489 } 00490 if (specular) 00491 { 00492 Op op (spec[i], nullColor); 00493 } 00494 } 00495 ++vbLock; ++nbLock; 00496 } 00497 } 00498 template<typename Op, int zeroDest, int diffuse> 00499 void CalculateLightingOD (const csLightProperties& light, 00500 const csVector3& eyePos, float shininess, 00501 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00502 iRenderBuffer* litColor, iRenderBuffer* specColor) const 00503 { 00504 if (specColor != 0) 00505 CalculateLightingODS<Op, zeroDest, diffuse, 1> (light, eyePos, shininess, 00506 numvert, vb, nb, litColor, specColor); 00507 else 00508 CalculateLightingODS<Op, zeroDest, diffuse, 0> (light, eyePos, shininess, 00509 numvert, vb, nb, litColor, specColor); 00510 } 00511 template<typename Op, int zeroDest> 00512 void CalculateLightingO (const csLightProperties& light, 00513 const csVector3& eyePos, float shininess, 00514 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00515 iRenderBuffer* litColor, iRenderBuffer* specColor) const 00516 { 00517 if (litColor != 0) 00518 CalculateLightingOD<Op, zeroDest, 1> (light, eyePos, shininess, numvert, 00519 vb, nb, litColor, specColor); 00520 else 00521 CalculateLightingOD<Op, zeroDest, 0> (light, eyePos, shininess, numvert, 00522 vb, nb, litColor, specColor); 00523 } 00524 public: 00525 virtual void CalculateLighting (const csLightProperties& light, 00526 const csVector3& eyePos, float shininess, 00527 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00528 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const 00529 { 00530 CalculateLightingO<OpAssign, 1> (light, eyePos, shininess, 00531 numvert, vb, nb, litColor, specColor); 00532 } 00533 00534 virtual void CalculateLightingAdd (const csLightProperties& light, 00535 const csVector3& eyePos, float shininess, 00536 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00537 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const 00538 { 00539 CalculateLightingO<OpAdd, 0> (light, eyePos, shininess, numvert, vb, nb, 00540 litColor, specColor); 00541 } 00542 00543 virtual void CalculateLightingMul (const csLightProperties& light, 00544 const csVector3& eyePos, float shininess, 00545 size_t numvert, iRenderBuffer* vb, iRenderBuffer* nb, 00546 iRenderBuffer* litColor, iRenderBuffer* specColor = 0) const 00547 { 00548 CalculateLightingO<OpMul, 0> (light, eyePos, shininess, numvert, vb, nb, 00549 litColor, specColor); 00550 } 00551 }; 00552 00553 #endif //__CS_VERTEXLIGHT_H__
Generated for Crystal Space by doxygen 1.4.7