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.6.1