csgfx/vertexlight.h Source File (Crystal Space 2.0 Public API Reference)

| ## Public API Reference

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

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