CrystalSpace

Public API Reference

csplugincommon/rendermanager/shadow_pssm.h
Go to the documentation of this file.
00001 /*
00002     Copyright (C) 2008 by Frank Richter
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_CSPLUGINCOMMON_RENDERMANAGER_SHADOW_PSSM_H__
00020 #define __CS_CSPLUGINCOMMON_RENDERMANAGER_SHADOW_PSSM_H__
00021 
00026 #include "ivideo/shader/shader.h"
00027 
00028 #include "csutil/cfgacc.h"
00029 
00030 #include "cstool/meshfilter.h"
00031 
00032 #include "csplugincommon/rendermanager/operations.h"
00033 #include "csplugincommon/rendermanager/rendertree.h"
00034 #include "csplugincommon/rendermanager/shadow_common.h"
00035 #include "csplugincommon/rendermanager/standardsorter.h"
00036 #include "csplugincommon/rendermanager/viscull.h"
00037 
00038 #include "csgeom/matrix4.h"
00039 #include "csgeom/projections.h"
00040 
00041 class csShaderVariable;
00042 
00043 namespace CS
00044 {
00045 namespace RenderManager
00046 {
00047 
00048   struct ShadowPSSMExtraMeshData
00049   {
00050     csRef<csShaderVariable> svMeshID;
00051   };
00052 
00067   template<typename RenderTree, typename LayerConfigType>
00068   class ShadowPSSM
00069   {
00070   public:
00071     struct PersistentData;
00072     
00094     class ViewSetup
00095     {
00096     public:
00097       PersistentData& persist;
00098       
00099       CS::RenderManager::RenderView* rview;
00100       int numParts;
00101       float* splitDists;
00102       float lx, rx, ty, by;
00103       bool doFixedCloseShadow;
00104       
00105       SingleRenderLayer depthRenderLayer;
00106       uint lastMeshID;
00107       csHash<csRef<csShaderVariable>, csPtrKey<iShaderVariableContext> > meshIDs;
00108       
00109       ViewSetup (PersistentData& persist, CS::RenderManager::RenderView* rview)
00110        : persist (persist), rview (rview),
00111          doFixedCloseShadow (persist.fixedCloseShadow > 0),
00112          depthRenderLayer (persist.settings.shadowShaderType, 
00113            persist.settings.shadowDefaultShader),
00114          lastMeshID (0)
00115       {
00116         // PSSM: split layers
00117         
00118         float _near = SMALL_Z;
00119         float _far = persist.farZ;
00120         
00121         int firstPart = 0;
00122         numParts = persist.numSplits + 1;
00123         if (doFixedCloseShadow)
00124         {
00125           numParts++;
00126         }
00127         splitDists = new float[numParts+1];
00128         if (doFixedCloseShadow)
00129         {
00130           firstPart = 1;
00131           splitDists[0] = _near;
00132           _near = persist.fixedCloseShadow;
00133         }
00134       
00135         splitDists[firstPart] = _near;
00136         for (int i = firstPart; i <= numParts; i++)
00137         {
00138           const float n = _near, f = _far;
00139           const float iFrac = (float)(i-firstPart)/(float)(numParts-firstPart);
00140           splitDists[i] = (n * pow (f/n, iFrac) + n + (f-n)*iFrac)*0.5f;
00141         }
00142         // Get visible frustum in to lx/ty,rx/by
00143         {
00144           int frameWidth = rview->GetGraphics3D()->GetWidth ();
00145           int frameHeight = rview->GetGraphics3D()->GetHeight ();
00146           lx = 0;
00147           rx = frameWidth;
00148           ty = frameHeight;
00149           by = 0;
00150         }
00151       }
00152       
00153       ~ViewSetup() { delete[] splitDists; }
00154     };
00155     
00156     struct CachedLightData :
00157       public CS::Memory::CustomAllocated
00158     {
00159       uint lastSetupFrame;
00160       bool lightProjectSetup;
00161       // Transform light space to post-project light space
00162       CS::Math::Matrix4 lightProject;
00163       struct SuperFrustum : public CS::Utility::FastRefCount<SuperFrustum>
00164       {
00165         int actualNumParts;
00166         // Transform world space to light space
00167         csReversibleTransform world2light_base;
00168         csReversibleTransform world2light_rotated;
00169         csMatrix3 frustumRotation;
00170         
00171         csBox3 lightBBoxLS;
00172         /* @@@ TODO: Would be nice to get bbox of actual shadow casting
00173          * objects ...  All meshes in the superFrustum would have to be
00174          * collected, and not just visible ones intersecting it */
00175         csBox3 castingObjectsBBoxPP;
00176         csBox3 lightBBoxPP;
00177 
00178         CS::Utility::MeshFilter meshFilter;
00179           
00180         struct Frustum
00181         {
00182           bool draw;
00183           // Volume (in post-project light space)
00184           csBox3 volumePP;
00185           /* @@@ FIXME: res thinks: shouldn't be csRef<>s - pointers should
00186              suffice as cached Frustums are supposedly cleaned up between
00187              frames (and hence no SV pointers should dangle) */
00188           csRef<csShaderVariable> shadowMapProjectSV;
00189           csRef<csShaderVariable> shadowMapUnscaleSV;
00190           csRef<csShaderVariable> shadowMapDimSV;
00191           csRef<csShaderVariable> shadowClipSV;
00192           csRef<csShaderVariable> textureSVs[rtaNumAttachments];
00193           
00194           // Object bboxes in post-project light space
00195           csBox3 receivingObjectsBBoxPP;
00196           
00197           Frustum() : draw (true) {}
00198         };
00199         Frustum* frustums;
00200         
00201         ~SuperFrustum() { delete[] frustums; }
00202       };
00203       typedef csRefArray<SuperFrustum> LightFrustumsArray;
00204       struct LightFrustums
00205       {
00206         uint frustumsSetupFrame;
00207         uint setupFrame;
00208         LightFrustumsArray frustums;
00209         
00210         LightFrustums() : frustumsSetupFrame (~0), setupFrame (~0) {}
00211       };
00212       csHash<LightFrustums, csRef<iCamera> > lightFrustumsHash;
00213       uint sublightNum;
00214       
00215       CachedLightData() : lastSetupFrame (~0), lightProjectSetup (false),
00216         sublightNum (0) {}
00217       
00218       uint GetSublightNum() const { return (uint)sublightNum; }
00219 
00220       void SetupFrame (RenderTree& tree, ShadowPSSM& shadows, iLight* light)
00221       {
00222         if (light->GetFlags().Check (CS_LIGHT_NOSHADOWS)) return;
00223         
00224         ViewSetup& viewSetup = shadows.viewSetup;
00225         uint currentFrame = viewSetup.rview->GetCurrentFrameNumber();
00226         if (lastSetupFrame != currentFrame)
00227         {
00228           lightFrustumsHash.DeleteAll();
00229           lastSetupFrame = currentFrame;
00230         }
00231         
00232         csRef<iCamera> camera (viewSetup.rview->GetCamera());
00233         
00234         LightFrustums& lightFrustumsSettings =
00235           lightFrustumsHash.GetOrCreate (
00236             camera, LightFrustums());
00237         
00238         if (lightFrustumsSettings.frustumsSetupFrame != currentFrame)
00239         {
00240           float lightCutoff = light->GetCutoffDistance();
00241           if (!lightProjectSetup)
00242           {
00243             float lightNear = SMALL_Z;
00244             CS::Math::Matrix4 lightProject;
00245             csLightType ltype = light->GetType();
00246             int numFrustums = 1;
00247             switch (ltype)
00248             {
00249               case CS_LIGHT_DIRECTIONAL:
00250                 numFrustums = 1;
00251                 {
00252                   lightProject = CS::Math::Projections::Ortho (
00253                     lightCutoff, -lightCutoff, lightCutoff, -lightCutoff,
00254                     -lightCutoff, -lightNear);
00255                 }
00256                 break;
00257               case CS_LIGHT_POINTLIGHT:
00258               case CS_LIGHT_SPOTLIGHT:
00259                 if (ltype == CS_LIGHT_POINTLIGHT)
00260                   numFrustums = 6;
00261                 else
00262                   numFrustums = 1;
00263                 {
00264                   CS::Math::Matrix4 flipZW (
00265                     1, 0, 0, 0,
00266                     0, 1, 0, 0,
00267                     0, 0, -1, 0,
00268                     0, 0, 0, -1);
00269                   //lightProject = flipZW * CS::Math::Projections::Frustum (
00270                   //  -lightNear, lightNear, -lightNear, lightNear, // @@@ TODO: use spot angle
00271                   //  lightNear, lightCutoff, true);
00272                   lightProject = flipZW * CS::Math::Projections::Frustum (
00273                     lightCutoff, -lightCutoff, lightCutoff, -lightCutoff, // @@@ TODO: use spot angle
00274                     -lightCutoff, -lightNear);
00275                 }
00276                 break;
00277             }
00278             this->sublightNum = numFrustums;
00279             this->lightProject = lightProject;
00280             lightProjectSetup = true;
00281           }
00282           /*csPrintf ("lightProject = %s\n", lightProject.Description().GetData());
00283           {
00284             csVector4 a (0, 0, -lightNear, 1);
00285             csVector4 b = lightProject * a;
00286             csPrintf ("%s -> %s  ", a.Description().GetData(), b.Description().GetData());
00287           }
00288           {
00289             csVector4 a (0, 0, lightNear, 1);
00290             csVector4 b = lightProject * a;
00291             csPrintf ("%s -> %s  ", a.Description().GetData(), b.Description().GetData());
00292           }
00293           {
00294             csVector4 a (0, 0, lightCutoff, 1);
00295             csVector4 b = lightProject * a;
00296             csPrintf ("%s -> %s  ", a.Description().GetData(), b.Description().GetData());
00297           }
00298           {
00299             csVector4 a (0, 0, -lightCutoff, 1);
00300             csVector4 b = lightProject * a;
00301             csPrintf ("%s -> %s  ", a.Description().GetData(), b.Description().GetData());
00302           }
00303           csPrintf ("\n");*/
00304           const csReversibleTransform& world2light_base (
00305             light->GetMovable()->GetFullTransform());
00306             
00307           const csBox3& lightBBox = light->GetLocalBBox();
00308           if (tree.IsDebugFlagEnabled (shadows.persist.dbgLightBBox))
00309           {
00310             tree.AddDebugBBox (lightBBox,
00311               world2light_base.GetInverse(),
00312               csColor (1, 1, 1));
00313           }
00314 
00315           static const csMatrix3 frustRotationMatrices[6] =
00316           {
00317             csMatrix3 (), // must be identity
00318             csMatrix3 (1, 0, 0,  0, 0, 1,  0, -1, 0),
00319             csMatrix3 (1, 0, 0,  0, 0, -1,  0, 1, 0),
00320             csMatrix3 (0, 0, -1,  0, 1, 0,  1, 0, 0),
00321             csMatrix3 (0, 0, 1,  0, 1, 0,  -1, 0, 0),
00322             csMatrix3 (1, 0, 0,  0, -1, 0,  0, 0, -1) // last must be 180 deg into other direction
00323           };
00324           csVector2 corner2D[4] = {
00325             csVector2 (viewSetup.lx, viewSetup.ty),
00326             csVector2 (viewSetup.lx, viewSetup.by),
00327             csVector2 (viewSetup.rx, viewSetup.ty),
00328             csVector2 (viewSetup.rx, viewSetup.by)
00329           };
00330           
00331           LightFrustumsArray& lightFrustums =
00332            lightFrustumsSettings.frustums;
00333 
00334           LightingVariablesHelper lightVarsHelper (viewSetup.persist.lightVarsPersist);
00335           for (uint f = 0; f < sublightNum; f++)
00336           {
00337             /* Compute intersection of light frustum with view frustums:
00338                 1. Compute corners of split frustums
00339                 2. Translate corners to light space
00340                 3. Compute bounding box from corners
00341               */
00342             csRef<SuperFrustum> newFrust;
00343             newFrust.AttachNew (new SuperFrustum);
00344             SuperFrustum& superFrustum = *(lightFrustums[lightFrustums.Push (
00345               newFrust)]);
00346             superFrustum.world2light_base = world2light_base;
00347             superFrustum.world2light_rotated = world2light_base;
00348             superFrustum.frustumRotation = frustRotationMatrices[f];
00349             superFrustum.world2light_rotated.SetO2T (
00350               superFrustum.world2light_rotated.GetO2T()
00351               * frustRotationMatrices[f]);
00352             if (shadows.persist.limitedShadow)
00353               superFrustum.meshFilter.SetFilterMode (CS::Utility::MESH_FILTER_INCLUDE);
00354               
00355            
00356             csBox3 frustBBox (
00357               csVector3 (-FLT_MAX, -FLT_MAX, 0),
00358               csVector3 (FLT_MAX, FLT_MAX, FLT_MAX));
00359             /*{
00360               csTransform boxTF (frustRotationMatrices[f], csVector3 (0));
00361               frustBBox = boxTF.Other2This (frustBBox);
00362             }*/
00363             frustBBox *= lightBBox; // @@@ lightBBox should prolly be rotated
00364                 /*tree.AddDebugBBox (frustBBox,
00365                   superFrustum.world2light_rotated.GetInverse(),
00366                   csColor (0.8, 0.8, 0.8));*/
00367             superFrustum.lightBBoxLS = frustBBox;
00368             superFrustum.lightBBoxPP.StartBoundingBox();
00369             for (int c = 0; c < 7; c++)
00370             {
00371               csVector3 cornerLight = frustBBox.GetCorner (c);
00372               csVector4 cornerUndiv = lightProject * csVector4 (cornerLight);
00373               csVector3 cornerDiv =
00374                 csVector3 (cornerUndiv.x, cornerUndiv.y, cornerUndiv.z);
00375               //cornerDiv /= cornerUndiv.w;
00376               superFrustum.lightBBoxPP.AddBoundingVertex (cornerDiv);
00377             }
00378 
00379             superFrustum.actualNumParts = 0;
00380             for (int i = 0; i < viewSetup.numParts; i++)
00381             {
00382               if (lightCutoff < viewSetup.splitDists[i]) break;
00383               superFrustum.actualNumParts++;
00384             }
00385             superFrustum.frustums =
00386               new typename SuperFrustum::Frustum[superFrustum.actualNumParts];
00387         
00388             for (int i = 0; i < superFrustum.actualNumParts; i++)
00389             {
00390               bool partFixed = viewSetup.doFixedCloseShadow && (i == 0);
00391               
00392               typename SuperFrustum::Frustum& lightFrustum =
00393                 superFrustum.frustums[i];
00394               
00395               // Frustum corner, camera space
00396               csVector3 cornerCam;
00397               // Frustum corner, world space
00398               csVector3 cornerWorld;
00399               // Frustum corner, light space
00400               csVector3 cornerLight;
00401               // Frustum slice bbox, light space
00402               csBox3 frustumLight;
00403               csBox3 frustumCam;
00404               frustumLight.StartBoundingBox();
00405               frustumCam.StartBoundingBox();
00406               for (int c = 0; c < 4; c++)
00407               {
00408                 cornerCam = camera->InvPerspective (
00409                   corner2D[c], viewSetup.splitDists[i]);
00410                 frustumCam.AddBoundingVertex (cornerCam);
00411                 cornerWorld = camera->GetTransform().This2Other (
00412                   cornerCam);
00413                 cornerLight = superFrustum.world2light_rotated.Other2This (cornerWorld);
00414                 frustumLight.AddBoundingVertex (cornerLight);
00415                 
00416                 cornerCam = camera->InvPerspective (
00417                   corner2D[c], viewSetup.splitDists[i+1]);
00418                 frustumCam.AddBoundingVertex (cornerCam);
00419                 cornerWorld = camera->GetTransform().This2Other (
00420                   cornerCam);
00421                 cornerLight = superFrustum.world2light_rotated.Other2This (cornerWorld);
00422                 frustumLight.AddBoundingVertex (cornerLight);
00423               }
00424               if (tree.IsDebugFlagEnabled (shadows.persist.dbgSplitFrustumCam))
00425               {
00426                 tree.AddDebugBBox (frustumCam,
00427                   camera->GetTransform().GetInverse(),
00428                   csColor (1, 0, 1));
00429               }
00430               if (tree.IsDebugFlagEnabled (shadows.persist.dbgSplitFrustumLight))
00431               {
00432                 tree.AddDebugBBox (frustumLight,
00433                   superFrustum.world2light_rotated.GetInverse(),
00434                   csColor (0, 1, 0));
00435               }
00436               if (!partFixed) frustumLight *= frustBBox;
00437               if (tree.IsDebugFlagEnabled (shadows.persist.dbgSplitFrustumLight))
00438               {
00439                 tree.AddDebugBBox (frustumLight,
00440                   superFrustum.world2light_rotated.GetInverse(),
00441                   csColor (0, 1, 1));
00442               }
00443             
00444               lightFrustum.shadowMapProjectSV = lightVarsHelper.CreateTempSV (
00445                 viewSetup.persist.svNames.GetLightSVId (
00446                   csLightShaderVarCache::lightShadowMapProjection));
00447               lightFrustum.shadowMapProjectSV->SetArraySize (4);
00448               for (int j = 0; j < 4; j++)
00449               {
00450                 csShaderVariable* item = lightVarsHelper.CreateTempSV (
00451                   CS::InvalidShaderVarStringID);
00452                 lightFrustum.shadowMapProjectSV->SetArrayElement (j, item);
00453               }
00454               lightFrustum.shadowMapUnscaleSV = lightVarsHelper.CreateTempSV (
00455                 viewSetup.persist.unscaleSVName);
00456               lightFrustum.shadowMapDimSV = lightVarsHelper.CreateTempSV (
00457                 viewSetup.persist.svNames.GetLightSVId (
00458                   csLightShaderVarCache::lightShadowMapPixelSize));
00459                   
00460               lightFrustum.shadowClipSV = lightVarsHelper.CreateTempSV (
00461                 viewSetup.persist.shadowClipSVName);
00462               lightFrustum.shadowClipSV->SetValue (csVector2 (
00463                 viewSetup.splitDists[i], 
00464                 (i+1 == superFrustum.actualNumParts) ? FLT_MAX : viewSetup.splitDists[i+1]));
00465                   
00466               size_t numTex = viewSetup.persist.settings.targets.GetSize();
00467               for (size_t t = 0; t < numTex; t++)
00468               {
00469                 const ShadowSettings::Target* target =
00470                   viewSetup.persist.settings.targets[t];
00471                 lightFrustum.textureSVs[target->attachment] =
00472                   lightVarsHelper.CreateTempSV (target->svName);
00473               }
00474 
00475               if (frustumLight.Empty())
00476               {
00477                 lightFrustum.draw = false;
00478                 continue;
00479               }
00480       
00481               
00482               // Frustum slice corner, light space before W divide
00483               csVector4 cornerUndiv;
00484               // Frustum slice corner, light space after W divide
00485               csVector3 cornerDiv;
00486               
00487               lightFrustum.volumePP.StartBoundingBox();
00488               for (int c = 0; c < 7; c++)
00489               {
00490                 cornerLight = frustumLight.GetCorner (c);
00491                 cornerUndiv = lightProject * csVector4 (cornerLight);
00492                 cornerDiv =
00493                   csVector3 (cornerUndiv.x, cornerUndiv.y, cornerUndiv.z);
00494                 //cornerDiv /= cornerUndiv.w;
00495                 lightFrustum.volumePP.AddBoundingVertex (cornerDiv);
00496               }
00497               //superFrustum.lightBBoxLS += frustumLight;
00498             }
00499           }
00500         
00501           lightFrustumsSettings.frustumsSetupFrame = currentFrame;
00502         }
00503       }
00504       
00505       void AddShadowMapTarget (typename RenderTree::MeshNode* meshNode,
00506         PersistentData& persist, const SingleRenderLayer& layerConfig,
00507         RenderTree& renderTree, iLight* light, ViewSetup& viewSetup)
00508       {
00509         if (light->GetFlags().Check (CS_LIGHT_NOSHADOWS)) return;
00510         
00511         LightFrustums* lightFrustumsPtr =
00512           lightFrustumsHash.GetElementPointer (
00513             viewSetup.rview->GetCamera());
00514         if (lightFrustumsPtr == 0)
00515           return; // @@@ FIXME: when does that happen?
00516         
00517         LightFrustums& lightFrustums = *lightFrustumsPtr;
00518         
00519         uint currentFrame = viewSetup.rview->GetCurrentFrameNumber();
00520         if (lightFrustums.setupFrame
00521             == currentFrame)
00522           return;
00523         lightFrustums.setupFrame = currentFrame;
00524         
00525         csBox3 clipToView;
00526         clipToView = csBox3 (csVector3 (-1, -1, 0),
00527           csVector3 (1, 1, FLT_MAX));
00528 
00529         typename RenderTree::ContextNode& context = meshNode->GetOwner();
00530       
00531         CS_ALLOC_STACK_ARRAY(iTextureHandle*, texHandles,
00532           persist.settings.targets.GetSize());
00533         for (size_t l = 0; l < lightFrustums.frustums.GetSize(); l++)
00534         {
00535           const SuperFrustum& superFrust = *(lightFrustums.frustums[l]);
00536           const csBox3& allCastersBoxPP = superFrust.castingObjectsBBoxPP;
00537             //superFrust.lightBBoxPP;
00538           csBox3 allVolumes;
00539           for (int frustNum = 0; frustNum < superFrust.actualNumParts; frustNum++)
00540           {
00541             const typename SuperFrustum::Frustum& lightFrust = superFrust.frustums[frustNum];
00542             //if (lightFrust.containedObjectsPP.GetSize() == 0) continue;
00543             
00544             bool partFixed = viewSetup.doFixedCloseShadow && (frustNum == 0);
00545             
00546             allVolumes += lightFrust.volumePP;
00547             csBox3 castersBox = allCastersBoxPP;
00548             //castersBox *= allVolumes; // ***
00549             //csPrintf ("casters: %s\n", castersBox.Description().GetData());
00550             /* Fit map to the bounding box of all shadowed(received) objects.
00551               - If the shadowed objects are smaller than the light frustum in some
00552                 dimension makes sure the shadow map is used optimally.
00553                - Likewise, we only need to expend enough shadow map to cover
00554                  all casters. */
00555             csBox3 receiversBox;
00556             if (!partFixed)
00557             {
00558               receiversBox = lightFrust.receivingObjectsBBoxPP;
00559               // @@@ FIXME: causes light frustum clipping errors somewhere down below...
00560               //receiversBox *= lightFrust.volumePP;
00561               //receiversBox *= castersBox;
00562             }
00563             else
00564             {
00565               castersBox = receiversBox = lightFrust.volumePP;
00566             }
00567             receiversBox *= clipToView; // @@@ Redundant?
00568             //csPrintf ("receivers: %s\n", receiversBox.Description().GetData());
00569             bool noCasters = (castersBox.Empty());
00570             
00571             CS::RenderManager::RenderView* rview = context.renderView;
00572       csRef<CS::RenderManager::RenderView> newRenderView;
00573       newRenderView = renderTree.GetPersistentData().renderViews.CreateRenderView ();
00574             newRenderView->SetEngine (rview->GetEngine ());
00575             newRenderView->SetThisSector (rview->GetThisSector ());
00576             
00577             /* The minimum Z over all parts is used to avoid clipping shadows of 
00578               casters closer to the light than the split plane.
00579               Ideally, allObjsBoxPP.MinZ() would be mapped to depth -1, and depths
00580               below clamped */
00581             // FIXME, again: should better be allCastersBoxPP.MinZ();
00582             float n = superFrust.lightBBoxPP.MinZ();
00583             float f = csMin (castersBox.MaxZ(), receiversBox.MaxZ()) + EPSILON;
00584             /* Sometimes n==f which would result in an invalid matrix w/o EPSILON */
00585             
00586             CS::Math::Matrix4 crop;
00587             if (!lightFrust.draw)
00588             {
00589               /* Case: a frustum slice does not intersect with the light
00590                  frustum: Just make sure the frustum is clipped correctly, 
00591                  actual SM or SM transform doesn't matter much */
00592               crop = CS::Math::Matrix4 (
00593                 0, 0, 0, 10,
00594                 0, 0, 0, 10,
00595                 0, 0, 1, 0,
00596                 0, 0, 0, 1);
00597                 
00598               lightFrust.shadowMapUnscaleSV->SetValue (csVector4 (
00599                 0, 0, -10, -10));
00600             }
00601             else if (noCasters)
00602             {
00603               /* Case: a frustum slice doesn't have any shadow casters.
00604                  All shadow receivers are unshadowed (the empty SM is used
00605                  for that), but also the frustum must be clipped correctly. */
00606               crop = CS::Math::Matrix4 (
00607                 1, 0, 0, 0,
00608                 0, 1, 0, 0,
00609                 0, 0, 1, 0,
00610                 0, 0, 0, 1);
00611                 
00612               lightFrust.shadowMapUnscaleSV->SetValue (csVector4 (
00613                 1, 1, 0, 0));
00614 
00615               f = 1.0f;
00616               n = f - EPSILON;
00617             }
00618             else
00619             {
00620               const float focusMinX = csMax (receiversBox.MinX(), castersBox.MinX());
00621               const float focusMinY = csMax (receiversBox.MinY(), castersBox.MinY());
00622               const float focusMaxX = csMin (receiversBox.MaxX(), castersBox.MaxX());
00623               const float focusMaxY = csMin (receiversBox.MaxY(), castersBox.MaxY());
00624               const float frustW = focusMaxX - focusMinX;
00625               const float frustH = focusMaxY - focusMinY;
00626               const float cropScaleX = 2.0f/frustW;
00627               const float cropScaleY = 2.0f/frustH;
00628               const float cropShiftX =
00629                 (-1.0f * (focusMaxX + focusMinX))/frustW;
00630               const float cropShiftY =
00631                 (-1.0f * (focusMaxY + focusMinY))/frustH;
00632               crop = CS::Math::Matrix4 (
00633                 cropScaleX, 0, 0, cropShiftX,
00634                 0, cropScaleY, 0, cropShiftY,
00635                 0, 0, 1, 0,
00636                 0, 0, 0, 1);
00637                 
00638               const float uncropScaleX = 1.0f/cropScaleX;
00639               const float uncropScaleY = 1.0f/cropScaleY;
00640               const float uncropShiftX = -cropShiftX/cropScaleX;
00641               const float uncropShiftY = -cropShiftY/cropScaleY;
00642               lightFrust.shadowMapUnscaleSV->SetValue (csVector4 (
00643                 uncropScaleX, uncropScaleY, uncropShiftX, uncropShiftY));
00644             }
00645             
00646             CS::Math::Matrix4 Mortho = CS::Math::Projections::Ortho (-1, 1, 1, -1, 
00647               f, n);
00648             CS::Math::Matrix4 matrix = ((Mortho * crop) * lightProject)
00649              * CS::Math::Matrix4 (superFrust.frustumRotation);
00650 
00651             for (int i = 0; i < 4; i++)
00652             {
00653               csShaderVariable* item = lightFrust.shadowMapProjectSV->GetArrayElement (i);
00654               item->SetValue (matrix.Row (i));
00655             }
00656                 
00657             int shadowMapSize;
00658             if (partFixed)
00659               shadowMapSize = persist.shadowMapResClose;
00660             else
00661             {
00662               switch (light->GetType())
00663               {
00664                 default:
00665                 case CS_LIGHT_DIRECTIONAL:
00666                   shadowMapSize = persist.shadowMapResD;
00667                   break;
00668                 case CS_LIGHT_POINTLIGHT:
00669                   shadowMapSize = persist.shadowMapResP;
00670                   break;
00671                 case CS_LIGHT_SPOTLIGHT:
00672                   shadowMapSize = persist.shadowMapResS;
00673                   break;
00674               }
00675             }
00676             lightFrust.shadowMapDimSV->SetValue (csVector4 (1.0f/shadowMapSize,
00677               1.0f/shadowMapSize, shadowMapSize, shadowMapSize));
00678               
00679             if (!lightFrust.draw)
00680             {
00681               for (size_t t = 0; t < persist.settings.targets.GetSize(); t++)
00682               {
00683                 // Should not be used anyway
00684                 const ShadowSettings::Target* target =
00685                   viewSetup.persist.settings.targets[t];
00686                 lightFrust.textureSVs[target->attachment]->SetValue (0);
00687               }
00688               continue;
00689             }
00690             else if (noCasters)
00691             {
00692               for (size_t t = 0; t < persist.settings.targets.GetSize(); t++)
00693               {
00694                 // Can be 0 when using 1 light max
00695                 const ShadowSettings::Target* target =
00696                   viewSetup.persist.settings.targets[t];
00697                 lightFrust.textureSVs[target->attachment]->SetValue (
00698                   GetEmptyShadowMap (persist, t, context));
00699               }
00700               continue;
00701             }
00702     
00703             csReversibleTransform view = superFrust.world2light_base;
00704             
00705             csRef<iCustomMatrixCamera> shadowViewCam =
00706               newRenderView->GetEngine()->CreateCustomMatrixCamera();
00707             newRenderView->SetCamera (shadowViewCam->GetCamera());
00708             shadowViewCam->SetProjectionMatrix (matrix);
00709             shadowViewCam->GetCamera()->SetTransform (view);
00710             
00711             for (size_t t = 0; t < persist.settings.targets.GetSize(); t++)
00712             {
00713               ShadowSettings::Target* target =
00714                 viewSetup.persist.settings.targets[t];
00715               iTextureHandle* tex = target->texCache.QueryUnusedTexture (
00716                 shadowMapSize, shadowMapSize);
00717               lightFrust.textureSVs[target->attachment]->SetValue (tex);
00718               if (renderTree.IsDebugFlagEnabled (persist.dbgShadowTex))
00719                 renderTree.AddDebugTexture (tex);
00720               texHandles[target->attachment] = tex;
00721             }
00722             
00723             newRenderView->SetViewDimensions (shadowMapSize, shadowMapSize);
00724             csBox2 clipBox (0, 0, shadowMapSize, shadowMapSize);
00725             csRef<iClipper2D> newView;
00726             newView.AttachNew (new csBoxClipper (clipBox));
00727             newRenderView->SetClipper (newView);
00728             newRenderView->SetMeshFilter(superFrust.meshFilter);
00729     
00730             // Create a new context for shadow map w/ computed view
00731             typename RenderTree::ContextNode* shadowMapCtx = 
00732               renderTree.CreateContext (newRenderView);
00733             for (size_t t = 0; t < persist.settings.targets.GetSize(); t++)
00734             {
00735               shadowMapCtx->renderTargets[
00736                 persist.settings.targets[t]->attachment].texHandle = 
00737                   texHandles[t];
00738             }
00739             shadowMapCtx->drawFlags = CSDRAW_CLEARSCREEN | CSDRAW_CLEARZBUFFER;
00740             shadowMapCtx->postEffects = persist.settings.postEffects;
00741             
00742             /* @@@ FIXME: This will break as soon as the shadowmaps have
00743               different resolutions!
00744               Probably the post effects manager should be changed to handle
00745               changing resolutions well */
00746             if (shadowMapCtx->postEffects.IsValid())
00747             {
00748               CS::Math::Matrix4 perspectiveFixup;
00749               shadowMapCtx->postEffects->SetupView (shadowMapSize, shadowMapSize,
00750                 perspectiveFixup);
00751               shadowMapCtx->perspectiveFixup = perspectiveFixup;
00752             }
00753     
00754             // Setup the new context
00755             ShadowmapContextSetup contextFunction (layerConfig,
00756               persist.shaderManager, viewSetup, persist.settings.provideIDs);
00757             contextFunction (*shadowMapCtx);
00758           }
00759         }
00760       }
00761 
00762       void ClearFrameData()
00763       {
00764         //frustumsSetup = false;
00765         //lightFrustums.Empty();
00766         lightProjectSetup = false;
00767       }
00768 
00769       iTextureHandle* GetEmptyShadowMap (PersistentData& persist, size_t target,
00770                                          typename RenderTree::ContextNode& context)
00771       {
00772         if (persist.emptySMs.GetSize() == 0)
00773         {
00774           CS::RenderManager::RenderView* rview = context.renderView;
00775     csRef<CS::RenderManager::RenderView> newRenderView;
00776     newRenderView = context.owner.GetPersistentData().renderViews.CreateRenderView ();
00777           newRenderView->SetEngine (rview->GetEngine ());
00778           newRenderView->SetViewDimensions (1, 1);
00779           
00780           csRef<iCustomMatrixCamera> shadowViewCam =
00781             newRenderView->GetEngine()->CreateCustomMatrixCamera();
00782           newRenderView->SetCamera (shadowViewCam->GetCamera());
00783           
00784           csBox2 clipBox (0, 0, 1, 1);
00785           csRef<iClipper2D> newView;
00786           newView.AttachNew (new csBoxClipper (clipBox));
00787           newRenderView->SetClipper (newView);
00788 
00789           persist.emptySMs.SetSize (persist.settings.targets.GetSize());
00790 
00791           typename RenderTree::ContextNode* shadowMapCtx = 
00792             context.owner.CreateContext (newRenderView);
00793           for (size_t t = 0; t < persist.settings.targets.GetSize(); t++)
00794           {
00795             csRef<iTextureHandle> tex = persist.g3d->GetTextureManager()
00796               ->CreateTexture (1, 1, csimg2D, 
00797                 persist.settings.targets[t]->texCache.GetFormat(),
00798                 persist.settings.targets[t]->texCache.GetFlags ());
00799             persist.emptySMs.Put (t, tex);
00800             shadowMapCtx->renderTargets[
00801               persist.settings.targets[t]->attachment].texHandle = tex;
00802           }
00803           shadowMapCtx->drawFlags = CSDRAW_CLEARSCREEN | CSDRAW_CLEARZBUFFER;
00804         }
00805         return persist.emptySMs[target];
00806       }
00807     };
00808 private:
00809     class ShadowmapContextSetup
00810     {
00811       class MeshIDSVSetup
00812       {
00813       public:    
00814         MeshIDSVSetup (SVArrayHolder& svArrays, ViewSetup& viewSetup) 
00815          : svArrays (svArrays), viewSetup (viewSetup)
00816         {
00817           tempStack.Setup (svArrays.GetNumSVNames ());
00818         }
00819     
00820         void operator() (typename RenderTree::MeshNode* node)
00821         {
00822           for (size_t i = 0; i < node->meshes.GetSize (); ++i)
00823           {
00824             typename RenderTree::MeshNode::SingleMesh& mesh = node->meshes[i];
00825             csShaderVariable* svMeshID = viewSetup.meshIDs.Get (mesh.meshObjSVs, 0);
00826             if (!svMeshID) continue;
00827             
00828             tempStack[svMeshID->GetName()] = svMeshID;
00829             
00830             for (size_t layer = 0; layer < svArrays.GetNumLayers(); ++layer)
00831             {
00832               // Back-merge it onto the real one
00833               csShaderVariableStack localStack;
00834               svArrays.SetupSVStack (localStack, layer, mesh.contextLocalId);
00835               localStack.MergeFront (tempStack);
00836             }
00837           }
00838         }
00839     
00840       private:
00841         SVArrayHolder& svArrays; 
00842         csShaderVariableStack tempStack;
00843         ViewSetup& viewSetup;
00844       };
00845     public:
00846       ShadowmapContextSetup (const SingleRenderLayer& layerConfig,
00847         iShaderManager* shaderManager, ViewSetup& viewSetup,
00848         bool doIDTexture)
00849         : layerConfig (layerConfig), shaderManager (shaderManager),
00850           viewSetup (viewSetup), doIDTexture (doIDTexture)
00851       {
00852     
00853       }
00854     
00855       void operator() (typename RenderTree::ContextNode& context)
00856       {
00857         CS::RenderManager::RenderView* rview = context.renderView;
00858         iSector* sector = rview->GetThisSector ();
00859     
00860         // @@@ This is somewhat "boilerplate" sector/rview setup.
00861         rview->SetThisSector (sector);
00862         sector->CallSectorCallbacks (rview);
00863         // Make sure the clip-planes are ok
00864         CS::RenderViewClipper::SetupClipPlanes (rview->GetRenderContext ());
00865     
00866         if (context.owner.IsDebugFlagEnabled (
00867             viewSetup.persist.dbgSplitFrustumLight))
00868           context.owner.AddDebugClipPlanes (rview);
00869         
00870         // Do the culling
00871         iVisibilityCuller* culler = sector->GetVisibilityCuller ();
00872         Viscull<RenderTree> (context, rview, culler);
00873     
00874         // TODO: portals
00875         
00876         // Sort the mesh lists  
00877         {
00878           StandardMeshSorter<RenderTree> mySorter (rview->GetEngine ());
00879           mySorter.SetupCameraLocation (rview->GetCamera ()->GetTransform ().GetOrigin ());
00880           ForEachMeshNode (context, mySorter);
00881         }
00882     
00883         // After sorting, assign in-context per-mesh indices
00884         {
00885           SingleMeshContextNumbering<RenderTree> numbering;
00886           ForEachMeshNode (context, numbering);
00887         }
00888 
00889         // Setup the SV arrays
00890         // Push the default stuff
00891         SetupStandardSVs (context, layerConfig, shaderManager, sector);
00892     
00893         // Setup the material&mesh SVs
00894         {
00895           StandardSVSetup<RenderTree, SingleRenderLayer> svSetup (
00896             context.svArrays, layerConfig);
00897     
00898           ForEachMeshNode (context, svSetup);
00899         }
00900         // Set up mesh ID SVs
00901         if (doIDTexture)
00902         {
00903           MeshIDSVSetup svSetup (context.svArrays, viewSetup);
00904     
00905           ForEachMeshNode (context, svSetup);
00906         }
00907     
00908         SetupStandardShader (context, shaderManager, layerConfig);
00909     
00910         // Setup shaders and tickets
00911         SetupStandardTicket (context, shaderManager, layerConfig);
00912       }
00913     
00914     
00915     private:
00916       const SingleRenderLayer& layerConfig;
00917       iShaderManager* shaderManager;
00918       ViewSetup& viewSetup;
00919       bool doIDTexture;
00920     };
00921   public:
00922 
00927     struct PersistentData
00928     {
00929       uint dbgSplitFrustumCam;
00930       uint dbgSplitFrustumLight;
00931       uint dbgLightBBox;
00932       uint dbgShadowTex;
00933       uint dbgFlagShadowClipPlanes;
00934       csLightShaderVarCache svNames;
00935       CS::ShaderVarStringID unscaleSVName;
00936       CS::ShaderVarStringID shadowClipSVName;
00937       LightingSorter::PersistentData lightSorterPersist;
00938       LightingVariablesHelper::PersistentData lightVarsPersist;
00939       iShaderManager* shaderManager;
00940       csRefArray<iTextureHandle> emptySMs;
00941       iGraphics3D* g3d;
00942 
00943       csString configPrefix;
00944       ShadowSettings settings;
00945       
00946       bool limitedShadow;
00947       int shadowMapResD, shadowMapResP, shadowMapResS;
00948       int shadowMapResClose;
00949       int numSplits;
00950       float farZ;
00951       float fixedCloseShadow;
00952 
00953       PersistentData() : limitedShadow (false)
00954       {
00955       }
00956 
00957       ~PersistentData()
00958       {
00959       }
00960       
00962       void SetConfigPrefix (const char* configPrefix)
00963       {
00964         this->configPrefix = configPrefix;
00965       }
00966       
00967       void Initialize (iObjectRegistry* objectReg,
00968                        RenderTreeBase::DebugPersistent& dbgPersist)
00969       {
00970         csRef<iShaderManager> shaderManager =
00971           csQueryRegistry<iShaderManager> (objectReg);
00972         csRef<iGraphics3D> g3d =
00973           csQueryRegistry<iGraphics3D> (objectReg);
00974       
00975         this->shaderManager = shaderManager;
00976         this->g3d = g3d;
00977         iShaderVarStringSet* strings = shaderManager->GetSVNameStringset();
00978         svNames.SetStrings (strings);
00979         
00980         csConfigAccess cfg (objectReg);
00981         if (configPrefix.IsEmpty())
00982         {
00983           settings.ReadSettings (objectReg, "Depth");
00984         }
00985         else
00986         {
00987           settings.ReadSettings (objectReg, 
00988             cfg->GetStr (
00989               csString().Format ("%s.ShadowsType", configPrefix.GetData()), "Depth"));
00990           limitedShadow = cfg->GetBool (
00991             csString().Format ("%s.LimitedShadow", configPrefix.GetData()), false);
00992           numSplits = cfg->GetInt (
00993             csString().Format ("%s.NumSplits", configPrefix.GetData()), 2);
00994           farZ = cfg->GetFloat (
00995             csString().Format ("%s.FarZ", configPrefix.GetData()), 100);
00996           int shadowMapRes = cfg->GetInt (
00997             csString().Format ("%s.ShadowMapResolution", configPrefix.GetData()), 512);
00998           shadowMapResD = cfg->GetInt (
00999             csString().Format ("%s.ShadowMapResolution.Directional", configPrefix.GetData()),
01000             shadowMapRes);
01001           shadowMapResP = cfg->GetInt (
01002             csString().Format ("%s.ShadowMapResolution.Point", configPrefix.GetData()),
01003             shadowMapRes/2);
01004           shadowMapResS = cfg->GetInt (
01005             csString().Format ("%s.ShadowMapResolution.Spot", configPrefix.GetData()),
01006             shadowMapRes/2);
01007           shadowMapResClose = cfg->GetInt (
01008             csString().Format ("%s.CloseShadowMapResolution", configPrefix.GetData()),
01009             shadowMapRes);
01010           fixedCloseShadow = cfg->GetFloat (
01011             csString().Format ("%s.FixedCloseShadow", configPrefix.GetData()), 0);
01012         }
01013         
01014         unscaleSVName = strings->Request ("light shadow map unscale");
01015         shadowClipSVName = strings->Request ("light shadow clip");
01016         
01017         dbgSplitFrustumCam = dbgPersist.RegisterDebugFlag ("draw.pssm.split.frustum.cam");
01018         dbgSplitFrustumLight = dbgPersist.RegisterDebugFlag ("draw.pssm.split.frustum.light");
01019         dbgLightBBox = dbgPersist.RegisterDebugFlag ("draw.pssm.lightbbox");
01020         dbgShadowTex = dbgPersist.RegisterDebugFlag ("textures.shadow");
01021         dbgFlagShadowClipPlanes =
01022           dbgPersist.RegisterDebugFlag ("draw.clipplanes.shadow");
01023       }
01024       void UpdateNewFrame ()
01025       {
01026         csTicks time = csGetTicks ();
01027         settings.AdvanceFrame (time);
01028         lightVarsPersist.UpdateNewFrame();
01029       }
01030     };
01031     
01032     typedef ViewSetup ShadowParameters;
01033 
01034     ShadowPSSM (PersistentData& persist,
01035       const LayerConfigType& layerConfig,
01036       typename RenderTree::MeshNode* node, 
01037       ViewSetup& viewSetup) 
01038       : persist (persist), layerConfig (layerConfig), 
01039         renderTree (node->GetOwner().owner), meshNode (node),
01040         viewSetup (viewSetup)
01041     { }
01042         
01043     uint HandleOneLight (typename RenderTree::MeshNode::SingleMesh& singleMesh,
01044                          iLight* light, CachedLightData& lightData,
01045                          csShaderVariableStack* lightStacks,
01046                          uint lightNum, uint subLightNum)
01047     {
01048       LightingVariablesHelper lightVarsHelper (viewSetup.persist.lightVarsPersist);
01049       
01050       if (persist.settings.provideIDs && !singleMesh.svMeshID.IsValid())
01051       {
01052         singleMesh.svMeshID = lightVarsHelper.CreateTempSV (
01053           viewSetup.persist.settings.svMeshIDName);
01054         lightStacks[0][singleMesh.svMeshID->GetName()] = singleMesh.svMeshID;
01055         uint meshID = ++viewSetup.lastMeshID;
01056         singleMesh.svMeshID->SetValue ((int)meshID);
01057         viewSetup.meshIDs.Put (singleMesh.meshObjSVs, singleMesh.svMeshID);
01058       }
01059       
01060       typename CachedLightData::LightFrustumsArray& lightFrustums =
01061         lightData.lightFrustumsHash.GetElementPointer (
01062           viewSetup.rview->GetCamera())->frustums;
01063       typename CachedLightData::SuperFrustum& superFrust =
01064         *(lightFrustums[subLightNum]);
01065       
01066       csBox3 meshBboxLS;
01067       csVector3 vLight;
01068       csBox3 meshBboxWorld (singleMesh.renderMesh->object2world.This2Other (
01069         singleMesh.renderMesh->bbox));
01070       vLight = superFrust.world2light_rotated.Other2This (
01071         meshBboxWorld.GetCorner (0));
01072       meshBboxLS.StartBoundingBox (csVector3 (vLight.x,
01073         vLight.y, vLight.z));
01074       csBox3 meshBboxLightPP;
01075       csVector4 vLightPP;
01076       vLightPP = lightData.lightProject * csVector4 (vLight);
01077       //vLightPP /= vLightPP.w;
01078       meshBboxLightPP.StartBoundingBox (csVector3 (vLightPP.x,
01079         vLightPP.y, vLightPP.z));
01080       for (int c = 1; c < 8; c++)
01081       {
01082         vLight = superFrust.world2light_rotated.Other2This (
01083           meshBboxWorld.GetCorner (c));
01084         meshBboxLS.AddBoundingVertexSmart (csVector3 (vLight.x,
01085           vLight.y, vLight.z));
01086         vLightPP = lightData.lightProject * csVector4 (vLight);
01087         //vLightPP /= vLightPP.w;
01088         meshBboxLightPP.AddBoundingVertexSmart (csVector3 (vLightPP.x,
01089           vLightPP.y, vLightPP.z));
01090       }
01091       /*csPrintf ("%s -> %s\n",
01092         singleMesh.meshWrapper->QueryObject()->GetName(),
01093         meshBboxLightPP.Description().GetData());*/
01094 
01095       if (!superFrust.lightBBoxLS.TestIntersect (meshBboxLS))
01096       //if (!lightFrustum.volumePP.TestIntersect (meshBboxLightPP))
01097       {
01098         return 0;
01099       }
01100 
01101       if (persist.limitedShadow)
01102       {
01103         if (singleMesh.meshFlags.Check (CS_ENTITY_LIMITEDSHADOWCAST))
01104         {
01105           superFrust.meshFilter.AddFilterMesh (singleMesh.meshWrapper);
01106           superFrust.castingObjectsBBoxPP += meshBboxLightPP;
01107           /* Here's a stupid bug: limited shadow casters which are outside
01108              the view won't cast shadows */
01109         }
01110       }
01111       else
01112       {
01113         if (!singleMesh.meshFlags.Check (CS_ENTITY_NOSHADOWCAST))
01114         {
01115           // Mesh casts shadow
01116           superFrust.castingObjectsBBoxPP += meshBboxLightPP;
01117         }
01118         else
01119         {
01120           // Mesh does not cast shadow
01121           superFrust.meshFilter.AddFilterMesh (singleMesh.meshWrapper);
01122         }
01123       }
01124 
01125       
01126       uint spreadFlags = 0;
01127       if (!singleMesh.meshFlags.Check (CS_ENTITY_NOSHADOWRECEIVE))
01128       {
01129         csBox3 meshBBoxView =
01130           viewSetup.rview->GetCamera()->GetTransform().Other2This (
01131             meshBboxWorld);
01132         int s = 0;
01133         for (int f = 0; f < superFrust.actualNumParts; f++)
01134         {
01135           typename CachedLightData::SuperFrustum::Frustum& lightFrustum =
01136             superFrust.frustums[f];
01137           //if (lightFrustum.volumePP.Empty()) continue;
01138           // Clip mesh to view split ...
01139           if ((meshBBoxView.MaxZ() < viewSetup.splitDists[f])
01140               || (meshBBoxView.MinZ() > viewSetup.splitDists[f+1]))
01141             continue;
01142           // ... and light frustum in view split (might be a bit smaller)
01143           if (!lightFrustum.volumePP.Overlap (meshBboxLightPP)) continue;
01144         
01145           lightFrustum.receivingObjectsBBoxPP += meshBboxLightPP;
01146         
01147           // Add shadow map SVs
01148           lightVarsHelper.MergeAsArrayItem (lightStacks[s],
01149             lightFrustum.shadowMapProjectSV, lightNum);
01150           lightVarsHelper.MergeAsArrayItem (lightStacks[s],
01151             lightFrustum.shadowMapUnscaleSV, lightNum);
01152           lightVarsHelper.MergeAsArrayItem (lightStacks[s], 
01153             lightFrustum.shadowMapDimSV, lightNum);
01154           if (lightStacks[s].GetSize() > lightFrustum.shadowClipSV->GetName())
01155           {
01156             lightStacks[s][lightFrustum.shadowClipSV->GetName()] =
01157               lightFrustum.shadowClipSV;
01158           }
01159             
01160           for (size_t t = 0; t < persist.settings.targets.GetSize(); t++)
01161           {
01162             const ShadowSettings::Target* target =
01163               viewSetup.persist.settings.targets[t];
01164             lightVarsHelper.MergeAsArrayItem (lightStacks[s], 
01165               lightFrustum.textureSVs[target->attachment], lightNum);
01166           }
01167           spreadFlags |= (1 << s);
01168           s++;
01169         }
01170       }
01171       else
01172         spreadFlags = 1;
01173       return spreadFlags;
01174     }
01175     
01176     static bool NeedFinalHandleLight() { return true; }
01177     void FinalHandleLight (iLight* light, CachedLightData& lightData)
01178     {
01179       lightData.AddShadowMapTarget (meshNode, persist,
01180         viewSetup.depthRenderLayer, renderTree, light, viewSetup);
01181       
01182       lightData.ClearFrameData();
01183     }
01184 
01185     csFlags GetLightFlagsMask () const { return csFlags (0); }
01186     
01187     size_t GetLightLayerSpread() const { return viewSetup.numParts; }
01188   protected:
01189     PersistentData& persist;
01190     const LayerConfigType& layerConfig;
01191     RenderTree& renderTree;
01192     typename RenderTree::MeshNode* meshNode;
01193     ViewSetup& viewSetup;
01194   };
01195 
01196 }
01197 }
01198 
01199 #endif // __CS_CSPLUGINCOMMON_RENDERMANAGER_SHADOW_PSSM_H__

Generated for Crystal Space 2.0 by doxygen 1.7.6.1