csplugincommon/rendermanager/lightsetup.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/lightsetup.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_LIGHTSETUP_H__
    00020 #define __CS_CSPLUGINCOMMON_RENDERMANAGER_LIGHTSETUP_H__
    00021
    00026 #include "iengine/lightmgr.h"
    00027 #include "iutil/object.h"
    00028 #include "iutil/objreg.h"
    00029 #include "ivideo/shader/shader.h"
    00030
    00031 #include "csgfx/lightsvcache.h"
    00032 #include "csgfx/shadervarblockalloc.h"
    00033 #include "csplugincommon/rendermanager/operations.h"
    00034 #include "csplugincommon/rendermanager/rendertree.h"
    00035
    00036 class csShaderVariable;
    00037
    00038 namespace CS
    00039 {
    00040 namespace RenderManager
    00041 {
    00042   struct LayerHelperContextData
    00043   {
    00044     csArray<size_t> newLayerIndices;
    00045     csArray<size_t> newLayerCounts;
    00046   };
    00047
    00048   struct RenderTreeLightingTraits : public RenderTreeStandardTraits
    00049   {
    00050     struct ContextNodeExtraDataType
    00051     {
    00052       LayerHelperContextData layerHelperData;
    00053     };
    00054   };
    00055
    00062   template<typename RenderTree, typename LayerConfigType,
    00063     typename NewLayersType>
    00064   class LayerHelper
    00065   {
    00066   public:
    00073     LayerHelper (LayerHelperContextData& contextData,
    00074       const LayerConfigType& layerConfig,
    00075       NewLayersType& newLayers) : contextData (contextData),
    00076       layerConfig (layerConfig), newLayers (newLayers)
    00077     {
    00078       if (contextData.newLayerIndices.GetSize() == 0)
    00079       {
    00080         contextData.newLayerIndices.SetSize (layerConfig.GetLayerCount ());
    00081         contextData.newLayerCounts.SetSize (layerConfig.GetLayerCount ());
    00082         for (size_t l = 0; l < layerConfig.GetLayerCount (); l++)
    00083         {
    00084           contextData.newLayerIndices[l] = l;
    00085           contextData.newLayerCounts[l] = 1;
    00086         }
    00087       }
    00088     }
    00089
    00091     size_t GetNewLayerIndex (size_t layer, size_t subLayer) const
    00092     {
    00093       return contextData.newLayerIndices[layer] + subLayer;
    00094     }
    00095
    00097     size_t GetSubLayerCount (size_t layer) const
    00098     {
    00099       return contextData.newLayerCounts[layer];
    00100     }
    00101
    00107     void Ensure (size_t layer, size_t neededSubLayers,
    00108                  typename RenderTree::ContextNode& context)
    00109     {
    00110       if (neededSubLayers > contextData.newLayerCounts[layer])
    00111       {
    00112         // We need to insert new layers
    00113
    00114         // How many?
    00115         size_t insertLayerNum = neededSubLayers - contextData.newLayerCounts[layer];
    00116         // The actual insertion
    00117         for (size_t n = contextData.newLayerCounts[layer]; n < neededSubLayers; n++)
    00118         {
    00119           context.InsertLayer (contextData.newLayerIndices[layer] + n - 1);
    00120           newLayers.InsertLayer (contextData.newLayerIndices[layer] + n - 1, layer);
    00121         }
    00122         // Update indices for in new index table
    00123         for (size_t l = layer+1; l < layerConfig.GetLayerCount (); l++)
    00124           contextData.newLayerIndices[l] += insertLayerNum;
    00125         contextData.newLayerCounts[layer] += insertLayerNum;
    00126       }
    00127     }
    00128   protected:
    00129     LayerHelperContextData& contextData;
    00130     const LayerConfigType& layerConfig;
    00131     NewLayersType& newLayers;
    00132   };
    00133
    00139   struct LightSettings
    00140   {
    00142     csLightType type;
    00144     csFlags lightFlags;
    00145
    00147     bool operator== (const LightSettings& other) const
    00148     { return (type == other.type) && (lightFlags == other.lightFlags); }
    00150     bool operator!= (const LightSettings& other) const
    00151     { return (type != other.type) || (lightFlags != other.lightFlags); }
    00152   };
    00153
    00158   class CS_CRYSTALSPACE_EXPORT LightingSorter
    00159   {
    00160     size_t lightLimit;
    00161   public:
    00163     struct LightInfo
    00164     {
    00166       iLight* light;
    00168       bool isStatic;
    00173       uint numSubLights;
    00175       uint* subLights;
    00177       LightSettings settings;
    00178     };
    00179
    00185     struct PersistentData
    00186     {
    00187       csArray<LightInfo> lightTypeScratch;
    00188       csArray<LightInfo> putBackLights;
    00189       csMemoryPool sublightNumMem;
    00190
    00195       void UpdateNewFrame()
    00196       {
    00197         lightTypeScratch.DeleteAll();
    00198       }
    00199     };
    00200
    00205     LightingSorter (PersistentData& persist, size_t numLights);
    00206
    00214     void AddLight (const csLightInfluence& influence,
    00215       uint numSubLights, const csFlags& lightFlagsMask);
    00216
    00218     size_t GetSize ()
    00219     {
    00220       csArray<LightInfo>& putBackLights = persist.putBackLights;
    00221       return lightLimit + putBackLights.GetSize();
    00222     }
    00223
    00225     void SetNumLights (size_t numLights);
    00226
    00228     void SetLightsLimit (size_t limit)
    00229     {
    00230       lightLimit = csMin (persist.lightTypeScratch.GetSize(), limit);
    00231     }
    00232
    00234     bool GetNextLight (LightInfo& out);
    00239     bool GetNextLight (const LightSettings& settings, LightInfo& out);
    00240
    00242     void PutInFront (LightInfo* lights, size_t num);
    00243   protected:
    00244     PersistentData& persist;
    00245   };
    00246
    00250   class CS_CRYSTALSPACE_EXPORT LightingVariablesHelper
    00251   {
    00252   public:
    00258     struct PersistentData
    00259     {
    00260       csShaderVarBlockAlloc<csBlockAllocatorDisposeLeaky<csShaderVariable> >
    00261           svAlloc;
    00262       /* A number of SVs have to be kept alive even past the expiration
    00263       * of the actual step */
    00264       csRefArray<csShaderVariable> svKeeper;
    00265
    00266       PersistentData() : svAlloc (32*1024) {}
    00267
    00272       void UpdateNewFrame ()
    00273       {
    00274         svKeeper.Empty();
    00275       }
    00276     };
    00277
    00279     LightingVariablesHelper (PersistentData& persist) : persist (persist) {}
    00280
    00289     bool MergeAsArrayItem (csShaderVariableStack& dst,
    00290       csShaderVariable* sv, size_t index);
    00291
    00297     void MergeAsArrayItems (csShaderVariableStack& dst,
    00298       const csRefArray<csShaderVariable>& allVars, size_t index);
    00299
    00301     csShaderVariable* CreateTempSV (CS::ShaderVarStringID name =
    00302       CS::InvalidShaderVarStringID);
    00303
    00308     csShaderVariable* CreateVarOnStack (CS::ShaderVarStringID name,
    00309       csShaderVariableStack& stack);
    00310   protected:
    00311     PersistentData& persist;
    00312   };
    00313
    00315   template<typename RenderTree, typename LayerConfigType>
    00316   class ShadowNone
    00317   {
    00318   public:
    00320     struct CachedLightData
    00321     {
    00323       uint GetSublightNum() const { return 1; }
    00325       void SetupFrame (RenderTree&, ShadowNone&, iLight*) {}
    00327       void ClearFrameData() {}
    00328     };
    00332     struct PersistentData
    00333     {
    00337       void UpdateNewFrame () {}
    00339       void Initialize (iObjectRegistry*,
    00340         RenderTreeBase::DebugPersistent&) {}
    00341     };
    00343     struct ShadowParameters {};
    00344
    00345     ShadowNone() {}
    00346     ShadowNone (PersistentData& persist,
    00347       const LayerConfigType& layerConfig,
    00348       typename RenderTree::MeshNode* node,
    00349       ShadowParameters&) { }
    00350
    00352     template<typename _CachedLightData>
    00353     uint HandleOneLight (typename RenderTree::MeshNode::SingleMesh& singleMesh,
    00354                          iLight* light, _CachedLightData& lightData,
    00355                          csShaderVariableStack* lightStacks,
    00356                          uint lightNum, uint sublight)
    00357     { return 1; }
    00358
    00363     static bool NeedFinalHandleLight() { return false; }
    00365     void FinalHandleLight (iLight*, CachedLightData&) { }
    00366
    00371     csFlags GetLightFlagsMask () const { return csFlags (CS_LIGHT_NOSHADOWS); }
    00372
    00374     size_t GetLightLayerSpread() const { return 1; }
    00375   };
    00376
    00400   template<typename RenderTree, typename LayerConfigType,
    00401     typename ShadowHandler = ShadowNone<RenderTree, LayerConfigType> >
    00402   class LightSetup
    00403   {
    00404   public:
    00405     class PostLightingLayers;
    00406
    00407   protected:
    00409     struct CachedLightData : public ShadowHandler::CachedLightData
    00410     {
    00411       const csRefArray<csShaderVariable>* shaderVars;
    00412     };
    00413
    00419     template<typename _ShadowHandler>
    00420     size_t HandleLights (_ShadowHandler& shadows,
    00421       size_t overallPass, LightingSorter& sortedLights,
    00422       size_t layer, LayerHelper<RenderTree, LayerConfigType,
    00423         PostLightingLayers>& layers, const LayerConfigType& layerConfig,
    00424       typename RenderTree::MeshNode::SingleMesh& mesh,
    00425       typename RenderTree::MeshNode* node)
    00426     {
    00427       /* Get the shader since the number of passes for that layer depend
    00428         * on it */
    00429       iShader* shaderToUse =
    00430         node->GetOwner().shaderArray[layers.GetNewLayerIndex (layer, 0)
    00431           * node->GetOwner().totalRenderMeshes + mesh.contextLocalId];
    00432       if (!shaderToUse) return 0;
    00433
    00434       UpdateMetadata (layer, shaderToUse);
    00435       const csShaderMetadata& lastMetadata = metadataCache[layer].metadata;
    00436       if ((lastMetadata.numberOfLights == 0)
    00437         && !layerConfig.IsAmbientLayer (layer)) return 0;
    00438
    00439       LightingVariablesHelper lightVarsHelper (persist.varsHelperPersist);
    00440
    00441       size_t layerLights = csMin (sortedLights.GetSize (),
    00442         layerConfig.GetMaxLightNum (layer));
    00443       if (lastMetadata.numberOfLights == 0)
    00444         layerLights = 0;
    00445       if (layerLights == 0)
    00446       {
    00447         if (!layerConfig.IsAmbientLayer (layer)) return 0;
    00448
    00449         // Render 1 layer only, no lights
    00450         layers.Ensure (layer, 1, node->GetOwner());
    00451
    00452         csShaderVariableStack localStack;
    00453         node->GetOwner().svArrays.SetupSVStack (localStack,
    00454           layers.GetNewLayerIndex (layer, 0),
    00455           mesh.contextLocalId);
    00456
    00457         csShaderVariable* lightNum = lightVarsHelper.CreateVarOnStack (
    00458           persist.svNames.GetDefaultSVId (
    00459             csLightShaderVarCache::varLightCount), localStack);
    00460         lightNum->SetValue ((int)0);
    00461
    00462         csShaderVariable* passNum = lightVarsHelper.CreateVarOnStack (
    00463           persist.svPassNum, localStack);
    00464         passNum->SetValue ((int)0);
    00465
    00466         return 0;
    00467       }
    00468       else
    00469       {
    00470         bool meshIsStaticLit = mesh.meshFlags.Check (CS_ENTITY_STATICLIT);
    00471
    00472         // Assume at least 1 light
    00473         CS_ALLOC_STACK_ARRAY(LightingSorter::LightInfo, renderLights, layerLights);
    00474
    00475         /*
    00476           Applied limitations:
    00477           - Sublights are not considered for the 'maximum lights' limit.
    00478           - Sublights *are* considered for the 'maximum passes' limit.
    00479           - If not all sublights of a light can be drawn in the limits,
    00480             skip the light.
    00481          */
    00482
    00483         // First, select iLights, limited by the maximum lights layer limit
    00484         size_t remainingLights = layerLights;
    00485         size_t totalWithSublights = 0;
    00486         {
    00487           size_t firstLight = 0;
    00488           //size_t totalLayers = 0;
    00489           while (firstLight < layerLights)
    00490           {
    00491             if (!sortedLights.GetNextLight (renderLights[firstLight]))
    00492               break;
    00493             size_t realNum = 1;
    00494             LightSettings lightSettings;
    00495             lightSettings = renderLights[firstLight].settings;
    00496             totalWithSublights += renderLights[firstLight].numSubLights;
    00497             size_t maxPassLights = lastMetadata.numberOfLights *
    00498               layerConfig.GetMaxLightPasses (layer);
    00499             maxPassLights = csMin (maxPassLights, remainingLights);
    00500
    00501             for (; realNum < maxPassLights; realNum++)
    00502             {
    00503               // Note that GetNextLight already does a selection on light type
    00504               if (!sortedLights.GetNextLight (lightSettings,
    00505                   renderLights[firstLight + realNum]))
    00506                 break;
    00507              totalWithSublights += renderLights[firstLight + realNum].numSubLights;
    00508             }
    00509
    00510             firstLight += realNum;
    00511             remainingLights -= realNum;
    00512           }
    00513           remainingLights = firstLight;
    00514         }
    00515
    00516         // "Expand" iLights into sublights
    00517         CS_ALLOC_STACK_ARRAY(LightingSorter::LightInfo*, renderSublights,
    00518           totalWithSublights);
    00519         CS_ALLOC_STACK_ARRAY(uint, renderSublightNums, totalWithSublights);
    00520         {
    00521           size_t i = 0;
    00522           for (size_t l = 0; l < remainingLights; l++)
    00523           {
    00524             LightingSorter::LightInfo& li = renderLights[l];
    00525             for (uint s = 0; s < li.numSubLights; s++)
    00526             {
    00527               renderSublights[i] = &li;
    00528               renderSublightNums[i] = li.subLights[s];
    00529               i++;
    00530             }
    00531           }
    00532         }
    00533
    00534         // Below this point "lights" are actually sublights!
    00535
    00536         // Set up layers.
    00537         size_t firstLight = 0;
    00538         remainingLights = totalWithSublights;
    00539         size_t totalLayers = 0;
    00540         while (firstLight < totalWithSublights)
    00541         {
    00542           if (totalLayers >= layerConfig.GetMaxLightPasses (layer))
    00543             break;
    00544
    00545           // We can draw up to maxPassLights lights in this layer
    00546           size_t maxPassLights = lastMetadata.numberOfLights *
    00547             layerConfig.GetMaxLightPasses (layer);
    00548           maxPassLights = csMin (maxPassLights, remainingLights);
    00549
    00550           // Find out number of consecutive lights in the layer
    00551           size_t num = 1;
    00552           LightSettings lightSettings = renderSublights[firstLight]->settings;
    00553           for (; num < maxPassLights; num++)
    00554           {
    00555             if (renderSublights[firstLight + num]->settings != lightSettings)
    00556               break;
    00557           }
    00558           size_t thisPassLayers;
    00559           thisPassLayers = (num + lastMetadata.numberOfLights - 1)
    00560             / lastMetadata.numberOfLights;
    00561           thisPassLayers = csMin (totalLayers + thisPassLayers,
    00562             layerConfig.GetMaxLightPasses (layer)) - totalLayers;
    00563           if (thisPassLayers == 0)
    00564             // Reached layer pass limit
    00565             break;
    00566
    00567           firstLight += num;
    00568           remainingLights -= num;
    00569           totalLayers += thisPassLayers * shadows.GetLightLayerSpread();
    00570         }
    00571         layers.Ensure (layer, totalLayers, node->GetOwner());
    00572         if (remainingLights > 0)
    00573         {
    00574           renderSublights[firstLight]->subLights += renderSublightNums[firstLight];
    00575           renderSublights[firstLight]->numSubLights -= renderSublightNums[firstLight];
    00576           sortedLights.PutInFront (*(renderSublights + firstLight), 1);
    00577           size_t l = firstLight + renderSublights[firstLight]->numSubLights;
    00578           while (l < firstLight + remainingLights)
    00579           {
    00580             sortedLights.PutInFront (*(renderSublights + l), 1);
    00581             l += renderSublights[l]->numSubLights;
    00582           }
    00583         }
    00584
    00585         csShaderVariableStack* localStacks =
    00586           new csShaderVariableStack[shadows.GetLightLayerSpread()];
    00587
    00588         // Now render lights for each light type
    00589         remainingLights = firstLight;
    00590         firstLight = 0;
    00591         totalLayers = 0;
    00592         while (firstLight < layerLights)
    00593         {
    00594           if (totalLayers >= layerConfig.GetMaxLightPasses (layer))
    00595             break;
    00596
    00597           LightSettings lightSettings = renderSublights[firstLight]->settings;
    00598           size_t num = 1;
    00599           for (; num < remainingLights; num++)
    00600           {
    00601             if (renderSublights[firstLight+num]->settings != lightSettings)
    00602               break;
    00603           }
    00604           /* We have a subset of the lights that are of the same type.
    00605            * Check the size of it against the shader limit */
    00606           size_t thisPassLayers;
    00607           thisPassLayers = (num + lastMetadata.numberOfLights - 1)
    00608             / lastMetadata.numberOfLights;
    00609           thisPassLayers = csMin (totalLayers + thisPassLayers,
    00610             layerConfig.GetMaxLightPasses (layer)) - totalLayers;
    00611           if (thisPassLayers == 0)
    00612             // Reached layer pass limit
    00613             break;
    00614           size_t neededLayers = totalLayers
    00615             + thisPassLayers*shadows.GetLightLayerSpread();
    00616
    00617           //csShaderVariableStack localStack;
    00618           for (size_t n = 0; n < thisPassLayers; n++)
    00619           {
    00620             if ((totalLayers != 0) || (n > 0))
    00621             {
    00622               /* The first layer will have the shader to use set;
    00623                * subsequent ones don't */
    00624               node->GetOwner().CopyLayerShader (mesh.contextLocalId,
    00625                 layers.GetNewLayerIndex (layer, 0),
    00626                 layers.GetNewLayerIndex (layer, n*shadows.GetLightLayerSpread() + totalLayers));
    00627             }
    00628
    00629             size_t thisNum = csMin (num,
    00630               layerConfig.GetMaxLightNum (layer));
    00631             thisNum = csMin (thisNum, (size_t)lastMetadata.numberOfLights);
    00632
    00633             for (size_t s = 0; s < shadows.GetLightLayerSpread(); s++)
    00634             {
    00635               node->GetOwner().svArrays.SetupSVStack (localStacks[s],
    00636                 layers.GetNewLayerIndex (layer,
    00637                   n*shadows.GetLightLayerSpread() + totalLayers) + s,
    00638                 mesh.contextLocalId);
    00639
    00640               csShaderVariable* lightNum = lightVarsHelper.CreateVarOnStack (
    00641                 persist.svNames.GetDefaultSVId (
    00642                   csLightShaderVarCache::varLightCount), localStacks[s]);
    00643               lightNum->SetValue ((int)thisNum);
    00644
    00645               csShaderVariable* passNum = lightVarsHelper.CreateVarOnStack (
    00646                 persist.svPassNum, localStacks[s]);
    00647               passNum->SetValue ((int)(n + totalLayers));
    00648
    00649               csShaderVariable* lightTypeSV = lightVarsHelper.CreateVarOnStack (
    00650                 persist.svNames.GetLightSVId (
    00651                   csLightShaderVarCache::lightType), localStacks[s]);
    00652               lightTypeSV->SetValue ((int)(lightSettings.type));
    00653             }
    00654
    00655             CachedLightData* thisLightSVs;
    00656             iLight* light = 0;
    00657             for (uint l = 0; l < thisNum; l++)
    00658             {
    00659               bool isStaticLight = renderSublights[firstLight + l]->isStatic;
    00660               light = renderSublights[firstLight + l]->light;
    00661               thisLightSVs = persist.lightDataCache.GetElementPointer (light);
    00662
    00663               uint lSpread = shadows.HandleOneLight (mesh, light, *thisLightSVs,
    00664                 localStacks, l, renderSublightNums[firstLight + l]);
    00665               if (lSpread == 0) continue;
    00666
    00667               uint initialActualSpread = 0;
    00668               if (node->sorting == CS_RENDPRI_SORT_BACK2FRONT)
    00669               {
    00670                 /* Hack: to make objects with alpha work w/ shadow_pssm -
    00671                    if they're drawn with the first 'spread' they can draw over
    00672                    a split and make that visible (ugly). Drawing them with the
    00673                    last 'spread' makes sure all splits should be drawn already.
    00674                  */
    00675                 initialActualSpread = (uint)shadows.GetLightLayerSpread()
    00676                   - CS::Utility::BitOps::ComputeBitsSet (lSpread);
    00677               }
    00678               uint actualSpread = initialActualSpread;
    00679               for (size_t s = 0; s < shadows.GetLightLayerSpread(); s++)
    00680               {
    00681                 if (!(lSpread & (1 << s))) continue;
    00682                 if (actualSpread > 0)
    00683                 {
    00684                   node->GetOwner().CopyLayerShader (mesh.contextLocalId,
    00685                     layers.GetNewLayerIndex (layer, 0),
    00686                     layers.GetNewLayerIndex (layer,
    00687                       n*shadows.GetLightLayerSpread() + actualSpread + totalLayers));
    00688                 }
    00689
    00690                 lightVarsHelper.MergeAsArrayItems (localStacks[actualSpread],
    00691                   *(thisLightSVs->shaderVars), l);
    00692                 if (isStaticLight && meshIsStaticLit
    00693                     && layerConfig.GetStaticLightsSettings ().specularOnly)
    00694                 {
    00695                   lightVarsHelper.MergeAsArrayItem (localStacks[actualSpread],
    00696                     persist.diffuseBlack, l);
    00697                 }
    00698                 actualSpread++;
    00699               }
    00700               if (initialActualSpread != 0)
    00701               {
    00702                 node->GetOwner().shaderArray[layers.GetNewLayerIndex (layer,
    00703                     n*shadows.GetLightLayerSpread() + totalLayers)
    00704                   * node->GetOwner().totalRenderMeshes + mesh.contextLocalId] = 0;
    00705               }
    00706             }
    00707             firstLight += thisNum;
    00708             num -= thisNum;
    00709             remainingLights -= thisNum;
    00710           }
    00711
    00712           totalLayers = neededLayers;
    00713         }
    00714
    00715         delete[] localStacks;
    00716
    00717         return firstLight;
    00718       }
    00719     }
    00720
    00721     // Simple cache
    00722     struct CachedShaderMetadata
    00723     {
    00724       iShader* shader;
    00725       csShaderMetadata metadata;
    00726
    00727       CachedShaderMetadata() : shader (0) {}
    00728     };
    00729     csArray<CachedShaderMetadata> metadataCache;
    00730
    00731     inline void UpdateMetadata (size_t layer, iShader* shaderToUse)
    00732     {
    00733       if (shaderToUse != metadataCache[layer].shader)
    00734       {
    00735         metadataCache[layer].metadata = shaderToUse->GetMetadata();
    00736         metadataCache[layer].shader = shaderToUse;
    00737       }
    00738     }
    00739   public:
    00740     struct PersistentData;
    00741     typedef csArray<iShader*> ShaderArrayType;
    00742     typedef ShadowHandler ShadowHandlerType;
    00743     typedef typename ShadowHandler::ShadowParameters ShadowParamType;
    00744
    00748     LightSetup (PersistentData& persist, iLightManager* lightmgr,
    00749       SVArrayHolder& svArrays, const LayerConfigType& layerConfig,
    00750       ShadowParamType& shadowParam)
    00751       : persist (persist), lightmgr (lightmgr),
    00752         svArrays (svArrays), allMaxLights (0), newLayers (layerConfig),
    00753         shadowParam (shadowParam)
    00754     {
    00755       // Sum up the number of lights we can possibly handle
    00756       for (size_t layer = 0; layer < layerConfig.GetLayerCount (); ++layer)
    00757       {
    00758         const size_t layerMax = layerConfig.GetMaxLightNum (layer);
    00759         // Max lights can be ~0, so need to avoid overflow
    00760         allMaxLights += csMin (layerMax, ((size_t)~0) - allMaxLights);
    00761       }
    00762     }
    00763
    00769     void operator() (typename RenderTree::MeshNode* node)
    00770     {
    00771       // The original layers
    00772       const LayerConfigType& layerConfig = newLayers.GetOriginalLayers();
    00773       // Set up metadata cache
    00774       metadataCache.SetSize (layerConfig.GetLayerCount());
    00775
    00776       /* This step will insert layers, keep track of the new indices of
    00777       * the original layer as well as how often a layer has been
    00778       * duplicated */
    00779       LayerHelper<RenderTree, LayerConfigType,
    00780         PostLightingLayers> layerHelper (
    00781         static_cast<RenderTreeLightingTraits::ContextNodeExtraDataType&> (
    00782         node->GetOwner()).layerHelperData, layerConfig, newLayers);
    00783       ShadowHandler shadows (persist.shadowPersist, layerConfig,
    00784         node, shadowParam);
    00785       ShadowNone<RenderTree, LayerConfigType> noShadows;
    00786
    00787       for (size_t i = 0; i < node->meshes.GetSize (); ++i)
    00788       {
    00789         typename RenderTree::MeshNode::SingleMesh& mesh = node->meshes[i];
    00790
    00791         size_t numLights = 0;
    00792         csLightInfluence* influences = 0;
    00793         LightingSorter sortedLights (persist.lightSorterPersist, 0);
    00794
    00795         if (!mesh.meshFlags.Check(CS_ENTITY_NOLIGHTING))
    00796         {
    00797           bool meshIsStaticLit = mesh.meshFlags.Check (CS_ENTITY_STATICLIT);
    00798           bool skipStatic = meshIsStaticLit
    00799             && layerConfig.GetStaticLightsSettings ().nodraw;
    00800
    00801           uint relevantLightsFlags =
    00802             skipStatic ? ((CS_LIGHTQUERY_GET_ALL & ~CS_LIGHTQUERY_GET_TYPE_ALL)
    00803                             | CS_LIGHTQUERY_GET_TYPE_DYNAMIC)
    00804                        : CS_LIGHTQUERY_GET_ALL;
    00805
    00806           lightmgr->GetRelevantLightsSorted (node->GetOwner().sector,
    00807             mesh.renderMesh->bbox, influences, numLights, allMaxLights,
    00808             &mesh.renderMesh->object2world,
    00809             relevantLightsFlags);
    00810
    00811           sortedLights.SetNumLights (numLights);
    00812           for (size_t l = 0; l < numLights; ++l)
    00813           {
    00814             iLight* light = influences[l].light;
    00815             CachedLightData* thisLightSVs =
    00816               persist.lightDataCache.GetElementPointer (light);
    00817             if (thisLightSVs == 0)
    00818             {
    00819               CachedLightData newCacheData;
    00820               newCacheData.shaderVars =
    00821                 &(light->GetSVContext()->GetShaderVariables());
    00822               thisLightSVs = &persist.lightDataCache.Put (
    00823                 light, newCacheData);
    00824               light->SetLightCallback (persist.GetLightCallback());
    00825             }
    00826             thisLightSVs->SetupFrame (node->GetOwner().owner, shadows, light);
    00827             csFlags lightFlagsMask;
    00828             if (mesh.meshFlags.Check (CS_ENTITY_NOSHADOWS))
    00829               lightFlagsMask = noShadows.GetLightFlagsMask();
    00830             else
    00831               lightFlagsMask = shadows.GetLightFlagsMask();
    00832             sortedLights.AddLight (influences[l], thisLightSVs->GetSublightNum(),
    00833               ~lightFlagsMask);
    00834           }
    00835         }
    00836
    00837         size_t lightOffset = 0;
    00838         size_t overallPass = 0;
    00839         for (size_t layer = 0; layer < layerConfig.GetLayerCount (); ++layer)
    00840         {
    00841           size_t layerLights = (numLights == 0) ? 0 :
    00842             csMin (layerConfig.GetMaxLightNum (layer), numLights - lightOffset);
    00843
    00844           if (layerLights == 0 && !layerConfig.IsAmbientLayer (layer))
    00845           {
    00846             /* Layer has no lights and is no ambient layer - prevent it from
    00847             * being drawn completely */
    00848             node->GetOwner().shaderArray[layerHelper.GetNewLayerIndex (layer, 0)
    00849               * node->GetOwner().totalRenderMeshes + mesh.contextLocalId] = 0;
    00850             continue;
    00851           }
    00852
    00853           sortedLights.SetLightsLimit (layerLights);
    00854           size_t handledLights;
    00855           if (mesh.meshFlags.CheckAll (CS_ENTITY_NOSHADOWCAST
    00856               | CS_ENTITY_NOSHADOWRECEIVE))
    00857             handledLights = HandleLights (noShadows, overallPass, sortedLights,
    00858               layer, layerHelper, layerConfig, mesh, node);
    00859           else
    00860             handledLights = HandleLights (shadows, overallPass, sortedLights,
    00861               layer, layerHelper, layerConfig, mesh, node);
    00862           overallPass++;
    00863           if ((handledLights == 0)
    00864             && (!layerConfig.IsAmbientLayer (layer)))
    00865           {
    00866             /* No lights have been set up, so don't draw either */
    00867             node->GetOwner().shaderArray[layerHelper.GetNewLayerIndex (layer, 0)
    00868               * node->GetOwner().totalRenderMeshes + mesh.contextLocalId] = 0;
    00869             continue;
    00870           }
    00871           lightOffset += handledLights;
    00872         }
    00873
    00874         lightmgr->FreeInfluenceArray (influences);
    00875       }
    00876
    00877       if (shadows.NeedFinalHandleLight())
    00878       {
    00879         typename PersistentData::LightDataCache::GlobalIterator lightDataIt (
    00880           persist.lightDataCache.GetIterator());
    00881         while (lightDataIt.HasNext())
    00882         {
    00883           csPtrKey<iLight> light;
    00884           CachedLightData& data = lightDataIt.Next (light);
    00885           shadows.FinalHandleLight (light, data);
    00886           data.ClearFrameData();
    00887         }
    00888       }
    00889     }
    00890
    00891     class PostLightingLayers
    00892     {
    00893       const LayerConfigType& layerConfig;
    00894       csArray<size_t> layerMap;
    00895
    00896       friend class LightSetup;
    00897       const LayerConfigType& GetOriginalLayers() const
    00898       {
    00899         return layerConfig;
    00900       }
    00901     public:
    00902       PostLightingLayers (const LayerConfigType& layerConfig)
    00903         : layerConfig (layerConfig)
    00904       {
    00905         layerMap.SetCapacity (layerConfig.GetLayerCount());
    00906         for (size_t l = 0; l < layerConfig.GetLayerCount(); l++)
    00907           layerMap.Push (l);
    00908       }
    00909
    00910       size_t GetLayerCount () const
    00911       {
    00912         return layerMap.GetSize();
    00913       }
    00914
    00915       const csStringID* GetShaderTypes (size_t layer, size_t& num) const
    00916       {
    00917         return layerConfig.GetShaderTypes (layerMap[layer], num);
    00918       }
    00919
    00920       iShader* GetDefaultShader (size_t layer) const
    00921       {
    00922         return layerConfig.GetDefaultShader (layerMap[layer]);
    00923       }
    00924
    00925       size_t GetMaxLightNum (size_t layer) const
    00926       {
    00927         return layerConfig.GetMaxLightNum (layerMap[layer]);
    00928       }
    00929
    00930       size_t GetMaxLightPasses (size_t layer) const
    00931       {
    00932         return layerConfig.GetMaxLightPasses (layerMap[layer]);
    00933       }
    00934       bool IsAmbientLayer (size_t layer) const
    00935       {
    00936         return layerConfig.IsAmbientLayer (layerMap[layer]);
    00937       }
    00938
    00939       void InsertLayer (size_t after, size_t oldLayer)
    00940       {
    00941         layerMap.Insert (after+1, oldLayer);
    00942       }
    00943     };
    00944
    00949     const PostLightingLayers& GetPostLightingLayers () const
    00950     {
    00951       return newLayers;
    00952     }
    00953
    00959     struct PersistentData
    00960     {
    00961       typename ShadowHandler::PersistentData shadowPersist;
    00962       LightingSorter::PersistentData lightSorterPersist;
    00963       csLightShaderVarCache svNames;
    00964       CS::ShaderVarStringID svPassNum;
    00965       csRef<csShaderVariable> diffuseBlack;
    00966       LightingVariablesHelper::PersistentData varsHelperPersist;
    00967       typedef csHash<CachedLightData, csPtrKey<iLight> > LightDataCache;
    00968       LightDataCache lightDataCache;
    00969
    00970       ~PersistentData()
    00971       {
    00972         if (lcb.IsValid()) lcb->parent = 0;
    00973       }
    00974
    00980       void Initialize (iObjectRegistry* objReg,
    00981                        RenderTreeBase::DebugPersistent& dbgPersist)
    00982       {
    00983         csRef<iShaderManager> shaderManager =
    00984           csQueryRegistry<iShaderManager> (objReg);
    00985
    00986         iShaderVarStringSet* strings = shaderManager->GetSVNameStringset();
    00987         svNames.SetStrings (strings);
    00988         svPassNum = strings->Request ("pass number");
    00989         shadowPersist.Initialize (objReg, dbgPersist);
    00990
    00991         diffuseBlack.AttachNew (new csShaderVariable (svNames.GetLightSVId (
    00992           csLightShaderVarCache::lightDiffuse)));
    00993         diffuseBlack->SetValue (csVector4 (0, 0, 0, 0));
    00994       }
    00995
    01000       void UpdateNewFrame ()
    01001       {
    01002         shadowPersist.UpdateNewFrame();
    01003         lightSorterPersist.UpdateNewFrame();
    01004         varsHelperPersist.UpdateNewFrame();
    01005       }
    01006
    01007       iLightCallback* GetLightCallback()
    01008       {
    01009         if (!lcb.IsValid()) lcb.AttachNew (new LightCallback (this));
    01010         return lcb;
    01011       }
    01012     protected:
    01013       class LightCallback : public scfImplementation1<LightCallback,
    01014                                                       iLightCallback>
    01015       {
    01016       public:
    01017         PersistentData* parent;
    01018
    01019         LightCallback (PersistentData* parent)
    01020           : scfImplementation1<LightCallback, iLightCallback> (this),
    01021             parent (parent) {}
    01022
    01023         void OnColorChange (iLight* light, const csColor& newcolor) { }
    01024         void OnPositionChange (iLight* light, const csVector3& newpos) { }
    01025         void OnSectorChange (iLight* light, iSector* newsector) { }
    01026         void OnRadiusChange (iLight* light, float newradius) { }
    01027         void OnDestroy (iLight* light)
    01028         {
    01029           if (parent != 0)
    01030           {
    01031             parent->lightDataCache.DeleteAll (light);
    01032           }
    01033         }
    01034         void OnAttenuationChange (iLight* light, int newatt) { }
    01035       };
    01036       csRef<LightCallback> lcb;
    01037     };
    01038
    01039   private:
    01040     PersistentData& persist;
    01041     iLightManager* lightmgr;
    01042     SVArrayHolder& svArrays;
    01043     size_t allMaxLights;
    01044     PostLightingLayers newLayers;
    01045     ShadowParamType& shadowParam;
    01046   };
    01047
    01048 }
    01049 }
    01050
    01051 #endif // __CS_CSPLUGINCOMMON_RENDERMANAGER_LIGHTSETUP_H__