## Public API Reference

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

- File List
- File Members

# 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__