00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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& )
00152 {}
00153
00154 CS_FORCEINLINE_TEMPLATEMETHOD
00155 void operator() (float , float & ) 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& )
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& )
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;
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
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;
00336 csVector3 lightDir;
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
00373 direction = parent.lightPos-v;
00374 csVector3 dirUnit (direction.Unit ());
00375
00376
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;
00414 csVector3 lightDir;
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
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__