csplugincommon/rendermanager/shadow_pssm.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

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__