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       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.2.1 by doxygen 1.5.3