CrystalSpace

Public API Reference

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