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 {
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& /*light*/)
00152   {}
00153 
00154   CS_FORCEINLINE_TEMPLATEMETHOD 
00155   void operator() (float /*distance*/, float & /*dp*/) 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& /*light*/)
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& /*light*/)
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; //localspace
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       //compute gouraud shading..
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; //localspace
00336   csVector3 lightDir; //localspace
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       //compute gouraud shading..
00373       direction = parent.lightPos-v;
00374       csVector3 dirUnit (direction.Unit ());
00375   
00376       //compute gouraud shading..
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; //localspace
00414   csVector3 lightDir; //localspace
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     // setup the light calculator
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__

Generated for Crystal Space 2.0 by doxygen 1.7.6.1