CrystalSpace

Public API Reference

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__

Generated for Crystal Space 2.0 by doxygen 1.7.6.1