mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-10-31 17:26:42 +00:00 
			
		
		
		
	Merge remote-tracking branch 'scrawl/master'
This commit is contained in:
		
						commit
						e03e2f0817
					
				
					 10 changed files with 143 additions and 90 deletions
				
			
		|  | @ -988,7 +988,7 @@ void RenderingManager::updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, con | |||
| 
 | ||||
| void RenderingManager::frameStarted(float dt, bool paused) | ||||
| { | ||||
|     if (mTerrain && mTerrain->getVisible()) | ||||
|     if (mTerrain) | ||||
|         mTerrain->update(mRendering.getCamera()->getRealPosition()); | ||||
| 
 | ||||
|     if (!paused) | ||||
|  |  | |||
|  | @ -466,6 +466,18 @@ namespace MWWorld | |||
|             ESM::Land *ptr = new ESM::Land(); | ||||
|             ptr->load(esm); | ||||
| 
 | ||||
|             // Same area defined in multiple plugins? -> last plugin wins
 | ||||
|             // Can't use search() because we aren't sorted yet - is there any other way to speed this up?
 | ||||
|             for (std::vector<ESM::Land*>::iterator it = mStatic.begin(); it != mStatic.end(); ++it) | ||||
|             { | ||||
|                 if ((*it)->mX == ptr->mX && (*it)->mY == ptr->mY) | ||||
|                 { | ||||
|                     delete *it; | ||||
|                     mStatic.erase(it); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             mStatic.push_back(ptr); | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -153,6 +153,14 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) | |||
|         // That should be it, I haven't seen any other fields yet.
 | ||||
|     } | ||||
| 
 | ||||
|     // NAM0 sometimes appears here, sometimes further on
 | ||||
|     ref.mNam0 = 0; | ||||
|     if (esm.isNextSub("NAM0")) | ||||
|     { | ||||
|         esm.getHT(ref.mNam0); | ||||
|         //esm.getHNOT(NAM0, "NAM0");
 | ||||
|     } | ||||
| 
 | ||||
|     esm.getHNT(ref.mRefnum, "FRMR"); | ||||
|     ref.mRefID = esm.getHNString("NAME"); | ||||
| 
 | ||||
|  | @ -243,7 +251,6 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) | |||
|     // Update: Well, maybe not completely useless. This might actually be
 | ||||
|     //  number_of_references + number_of_references_moved_here_Across_boundaries,
 | ||||
|     //  and could be helpful for collecting these weird moved references.
 | ||||
|     ref.mNam0 = 0; | ||||
|     if (esm.isNextSub("NAM0")) | ||||
|     { | ||||
|         esm.getHT(ref.mNam0); | ||||
|  |  | |||
|  | @ -40,29 +40,6 @@ namespace Terrain | |||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     int MaterialGenerator::getMaxLayersPerPass () | ||||
|     { | ||||
|         // count the texture units free
 | ||||
|         Ogre::uint8 freeTextureUnits = 16; | ||||
| 
 | ||||
|         // first layer doesn't need blendmap
 | ||||
|         --freeTextureUnits; | ||||
| 
 | ||||
|         if (mSplitShadows) | ||||
|             freeTextureUnits -= 3; | ||||
|         else if (mShadows) | ||||
|             --freeTextureUnits; | ||||
| 
 | ||||
|         // each layer needs 1.25 units (1xdiffusespec, 0.25xblend)
 | ||||
|         return static_cast<Ogre::uint8>(freeTextureUnits / (1.25f)) + 1; | ||||
|     } | ||||
| 
 | ||||
|     int MaterialGenerator::getRequiredPasses () | ||||
|     { | ||||
|         int maxLayersPerPass = getMaxLayersPerPass(); | ||||
|         return std::max(1.f, std::ceil(static_cast<float>(mLayerList.size()) / maxLayersPerPass)); | ||||
|     } | ||||
| 
 | ||||
|     Ogre::MaterialPtr MaterialGenerator::generate(Ogre::MaterialPtr mat) | ||||
|     { | ||||
|         return create(mat, false, false); | ||||
|  | @ -201,45 +178,64 @@ namespace Terrain | |||
|             else | ||||
|             { | ||||
| 
 | ||||
|                 int numPasses = getRequiredPasses(); | ||||
|                 assert(numPasses); | ||||
|                 int maxLayersInOnePass = getMaxLayersPerPass(); | ||||
|                 bool shadows = mShadows && !renderCompositeMap; | ||||
| 
 | ||||
|                 for (int pass=0; pass<numPasses; ++pass) | ||||
|                 int layerOffset = 0; | ||||
|                 while (layerOffset < (int)mLayerList.size()) | ||||
|                 { | ||||
|                     int layerOffset = maxLayersInOnePass * pass; | ||||
|                     int blendmapOffset = (pass == 0) ? 1 : 0; // the first layer of the first pass is the base layer and does not need a blend map
 | ||||
|                     int blendmapOffset = (layerOffset == 0) ? 1 : 0; // the first layer of the first pass is the base layer and does not need a blend map
 | ||||
| 
 | ||||
|                     // Check how many layers we can fit in this pass
 | ||||
|                     int numLayersInThisPass = 0; | ||||
|                     int numBlendTextures = 0; | ||||
|                     std::vector<std::string> blendTextures; | ||||
|                     int remainingTextureUnits = OGRE_MAX_TEXTURE_LAYERS; | ||||
|                     if (shadows) | ||||
|                         remainingTextureUnits -= (mSplitShadows ? 3 : 1); | ||||
|                     while (remainingTextureUnits && layerOffset + numLayersInThisPass < (int)mLayerList.size()) | ||||
|                     { | ||||
|                         int layerIndex = numLayersInThisPass + layerOffset; | ||||
| 
 | ||||
|                         int neededTextureUnits=0; | ||||
|                         int neededBlendTextures=0; | ||||
| 
 | ||||
|                         if (layerIndex != 0) | ||||
|                         { | ||||
|                             std::string blendTextureName = mBlendmapList[getBlendmapIndexForLayer(layerIndex)]->getName(); | ||||
|                             if (std::find(blendTextures.begin(), blendTextures.end(), blendTextureName) == blendTextures.end()) | ||||
|                             { | ||||
|                                 blendTextures.push_back(blendTextureName); | ||||
|                                 ++neededBlendTextures; | ||||
|                                 ++neededTextureUnits; // blend texture
 | ||||
|                             } | ||||
|                         } | ||||
|                         ++neededTextureUnits; // layer texture
 | ||||
|                         if (neededTextureUnits <= remainingTextureUnits) | ||||
|                         { | ||||
|                             // We can fit another!
 | ||||
|                             remainingTextureUnits -= neededTextureUnits; | ||||
|                             numBlendTextures += neededBlendTextures; | ||||
|                             ++numLayersInThisPass; | ||||
|                         } | ||||
|                         else | ||||
|                             break; // We're full
 | ||||
|                     } | ||||
| 
 | ||||
| 
 | ||||
|                     sh::MaterialInstancePass* p = material->createPass (); | ||||
| 
 | ||||
|                     p->setProperty ("vertex_program", sh::makeProperty<sh::StringValue>(new sh::StringValue("terrain_vertex"))); | ||||
|                     p->setProperty ("fragment_program", sh::makeProperty<sh::StringValue>(new sh::StringValue("terrain_fragment"))); | ||||
|                     if (pass != 0) | ||||
|                     if (layerOffset != 0) | ||||
|                     { | ||||
|                         p->setProperty ("scene_blend", sh::makeProperty(new sh::StringValue("alpha_blend"))); | ||||
|                         // Only write if depth is equal to the depth value written by the previous pass.
 | ||||
|                         p->setProperty ("depth_func", sh::makeProperty(new sh::StringValue("equal"))); | ||||
|                     } | ||||
| 
 | ||||
|                     p->mShaderProperties.setProperty ("is_first_pass", sh::makeProperty(new sh::BooleanValue(pass == 0))); | ||||
|                     p->mShaderProperties.setProperty ("render_composite_map", sh::makeProperty(new sh::BooleanValue(renderCompositeMap))); | ||||
|                     p->mShaderProperties.setProperty ("display_composite_map", sh::makeProperty(new sh::BooleanValue(displayCompositeMap))); | ||||
| 
 | ||||
|                     Ogre::uint numLayersInThisPass = std::min(maxLayersInOnePass, (int)mLayerList.size()-layerOffset); | ||||
| 
 | ||||
|                     // a blend map might be shared between two passes
 | ||||
|                     Ogre::uint numBlendTextures=0; | ||||
|                     std::vector<std::string> blendTextures; | ||||
|                     for (unsigned int layer=blendmapOffset; layer<numLayersInThisPass; ++layer) | ||||
|                     { | ||||
|                         std::string blendTextureName = mBlendmapList[getBlendmapIndexForLayer(layerOffset+layer)]->getName(); | ||||
|                         if (std::find(blendTextures.begin(), blendTextures.end(), blendTextureName) == blendTextures.end()) | ||||
|                         { | ||||
|                             blendTextures.push_back(blendTextureName); | ||||
|                             ++numBlendTextures; | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     p->mShaderProperties.setProperty ("num_layers", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numLayersInThisPass)))); | ||||
|                     p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures)))); | ||||
| 
 | ||||
|  | @ -250,7 +246,7 @@ namespace Terrain | |||
|                         blendmapStart = 0; | ||||
|                     else | ||||
|                         blendmapStart = getBlendmapIndexForLayer(layerOffset+blendmapOffset); | ||||
|                     for (Ogre::uint i = 0; i < numBlendTextures; ++i) | ||||
|                     for (int i = 0; i < numBlendTextures; ++i) | ||||
|                     { | ||||
|                         sh::MaterialInstanceTextureUnit* blendTex = p->createTextureUnit ("blendMap" + Ogre::StringConverter::toString(i)); | ||||
|                         blendTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(mBlendmapList[blendmapStart+i]->getName()))); | ||||
|  | @ -258,7 +254,7 @@ namespace Terrain | |||
|                     } | ||||
| 
 | ||||
|                     // layer maps
 | ||||
|                     for (Ogre::uint i = 0; i < numLayersInThisPass; ++i) | ||||
|                     for (int i = 0; i < numLayersInThisPass; ++i) | ||||
|                     { | ||||
|                         sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i)); | ||||
|                         diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue("textures\\"+mLayerList[layerOffset+i]))); | ||||
|  | @ -280,7 +276,7 @@ namespace Terrain | |||
|                     } | ||||
| 
 | ||||
|                     // shadow
 | ||||
|                     if (mShadows) | ||||
|                     if (shadows) | ||||
|                     { | ||||
|                         for (Ogre::uint i = 0; i < (mSplitShadows ? 3 : 1); ++i) | ||||
|                         { | ||||
|  | @ -292,7 +288,9 @@ namespace Terrain | |||
|                         Ogre::StringConverter::toString(numBlendTextures + numLayersInThisPass)))); | ||||
| 
 | ||||
|                     // Make sure the pass index is fed to the permutation handler, because blendmap components may be different
 | ||||
|                     p->mShaderProperties.setProperty ("pass_index", sh::makeProperty(new sh::IntValue(pass))); | ||||
|                     p->mShaderProperties.setProperty ("pass_index", sh::makeProperty(new sh::IntValue(layerOffset))); | ||||
| 
 | ||||
|                     layerOffset += numLayersInThisPass; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  |  | |||
|  | @ -43,10 +43,6 @@ namespace Terrain | |||
|     private: | ||||
|         Ogre::MaterialPtr create (Ogre::MaterialPtr mat, bool renderCompositeMap, bool displayCompositeMap); | ||||
| 
 | ||||
|         int getRequiredPasses (); | ||||
|         int getMaxLayersPerPass (); | ||||
| 
 | ||||
|         int mNumLayers; | ||||
|         std::vector<std::string> mLayerList; | ||||
|         std::vector<Ogre::TexturePtr> mBlendmapList; | ||||
|         std::string mCompositeMap; | ||||
|  |  | |||
|  | @ -151,8 +151,15 @@ QuadTreeNode::QuadTreeNode(Terrain* terrain, ChildDirection dir, float size, con | |||
|     for (int i=0; i<4; ++i) | ||||
|         mNeighbours[i] = NULL; | ||||
| 
 | ||||
|     mSceneNode = mTerrain->getSceneManager()->getRootSceneNode()->createChildSceneNode( | ||||
|                 Ogre::Vector3(mCenter.x*8192, mCenter.y*8192, 0)); | ||||
|     if (mDirection == Root) | ||||
|         mSceneNode = mTerrain->getRootSceneNode(); | ||||
|     else | ||||
|         mSceneNode = mTerrain->getSceneManager()->createSceneNode(); | ||||
|     Ogre::Vector2 pos (0,0); | ||||
|     if (mParent) | ||||
|         pos = mParent->getCenter(); | ||||
|     pos = mCenter - pos; | ||||
|     mSceneNode->setPosition(Ogre::Vector3(pos.x*8192, pos.y*8192, 0)); | ||||
| 
 | ||||
|     mLodLevel = log2(mSize); | ||||
| 
 | ||||
|  | @ -221,13 +228,12 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos) | |||
| 
 | ||||
|     float dist = distance(mWorldBounds, cameraPos); | ||||
| 
 | ||||
|     if (!mTerrain->getDistantLandEnabled()) | ||||
|     bool distantLand = mTerrain->getDistantLandEnabled(); | ||||
| 
 | ||||
|     // Make sure our scene node is attached
 | ||||
|     if (!mSceneNode->isInSceneGraph()) | ||||
|     { | ||||
|         if (dist > 8192*2) | ||||
|         { | ||||
|             destroyChunks(); | ||||
|             return; | ||||
|         } | ||||
|         mParent->getSceneNode()->addChild(mSceneNode); | ||||
|     } | ||||
| 
 | ||||
|     /// \todo implement error metrics or some other means of not using arbitrary values
 | ||||
|  | @ -246,9 +252,22 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos) | |||
|     if (dist > 8192*64) | ||||
|         wantedLod = 6; | ||||
| 
 | ||||
|     bool hadChunk = hasChunk(); | ||||
| 
 | ||||
|     if (!distantLand && dist > 8192*2) | ||||
|     { | ||||
|         if (mIsActive) | ||||
|         { | ||||
|             destroyChunks(true); | ||||
|             mIsActive = false; | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     mIsActive = true; | ||||
| 
 | ||||
|     if (mSize <= mTerrain->getMaxBatchSize() && mLodLevel <= wantedLod) | ||||
|     { | ||||
|         bool hadChunk = hasChunk(); | ||||
|         // Wanted LOD is small enough to render this node in one chunk
 | ||||
|         if (!mChunk) | ||||
|         { | ||||
|  | @ -297,32 +316,36 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos) | |||
| 
 | ||||
|         if (!hadChunk && hasChildren()) | ||||
|         { | ||||
|             for (int i=0; i<4; ++i) | ||||
|                 mChildren[i]->hideChunks(); | ||||
|             // Make sure child scene nodes are detached
 | ||||
|             mSceneNode->removeAllChildren(); | ||||
| 
 | ||||
|             // If distant land is enabled, keep the chunks around in case we need them again,
 | ||||
|             // otherwise, prefer low memory usage
 | ||||
|             if (!distantLand) | ||||
|                 for (int i=0; i<4; ++i) | ||||
|                     mChildren[i]->destroyChunks(true); | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // Wanted LOD is too detailed to be rendered in one chunk,
 | ||||
|         // so split it up by delegating to child nodes
 | ||||
|         if (mChunk) | ||||
|             mChunk->setVisible(false); | ||||
|         if (hadChunk) | ||||
|         { | ||||
|             // If distant land is enabled, keep the chunks around in case we need them again,
 | ||||
|             // otherwise, prefer low memory usage
 | ||||
|             if (!distantLand) | ||||
|                 destroyChunks(false); | ||||
|             else if (mChunk) | ||||
|                 mChunk->setVisible(false); | ||||
|         } | ||||
|         assert(hasChildren() && "Leaf node's LOD needs to be 0"); | ||||
|         for (int i=0; i<4; ++i) | ||||
|             mChildren[i]->update(cameraPos); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void QuadTreeNode::hideChunks() | ||||
| { | ||||
|     if (mChunk) | ||||
|         mChunk->setVisible(false); | ||||
|     else if (hasChildren()) | ||||
|         for (int i=0; i<4; ++i) | ||||
|             mChildren[i]->hideChunks(); | ||||
| } | ||||
| 
 | ||||
| void QuadTreeNode::destroyChunks() | ||||
| void QuadTreeNode::destroyChunks(bool children) | ||||
| { | ||||
|     if (mChunk) | ||||
|     { | ||||
|  | @ -348,9 +371,9 @@ void QuadTreeNode::destroyChunks() | |||
|             mCompositeMap.setNull(); | ||||
|         } | ||||
|     } | ||||
|     else if (hasChildren()) | ||||
|     else if (children && hasChildren()) | ||||
|         for (int i=0; i<4; ++i) | ||||
|             mChildren[i]->destroyChunks(); | ||||
|             mChildren[i]->destroyChunks(true); | ||||
| } | ||||
| 
 | ||||
| void QuadTreeNode::updateIndexBuffers() | ||||
|  | @ -366,7 +389,7 @@ void QuadTreeNode::updateIndexBuffers() | |||
| 
 | ||||
| bool QuadTreeNode::hasChunk() | ||||
| { | ||||
|     return mChunk && mChunk->getVisible(); | ||||
|     return mSceneNode->isInSceneGraph() && mChunk && mChunk->getVisible(); | ||||
| } | ||||
| 
 | ||||
| size_t QuadTreeNode::getActualLodLevel() | ||||
|  | @ -400,7 +423,7 @@ void QuadTreeNode::prepareForCompositeMap(Ogre::TRect<float> area) | |||
|         std::vector<std::string> layer; | ||||
|         layer.push_back("_land_default.dds"); | ||||
|         matGen.setLayerList(layer); | ||||
|         makeQuad(sceneMgr, area.left, area.top, area.right, area.bottom, matGen.generate(Ogre::MaterialPtr())); | ||||
|         makeQuad(sceneMgr, area.left, area.top, area.right, area.bottom, matGen.generateForCompositeMapRTT(Ogre::MaterialPtr())); | ||||
|         return; | ||||
|     } | ||||
|     if (mSize > 1) | ||||
|  |  | |||
|  | @ -72,6 +72,8 @@ namespace Terrain | |||
| 
 | ||||
|         QuadTreeNode* getParent() { return mParent; } | ||||
| 
 | ||||
|         Ogre::SceneNode* getSceneNode() { return mSceneNode; } | ||||
| 
 | ||||
|         int getSize() { return mSize; } | ||||
|         Ogre::Vector2 getCenter() { return mCenter; } | ||||
| 
 | ||||
|  | @ -100,11 +102,8 @@ namespace Terrain | |||
|         /// Call after QuadTreeNode::update!
 | ||||
|         void updateIndexBuffers(); | ||||
| 
 | ||||
|         /// Hide chunks rendered by this node and all its children
 | ||||
|         void hideChunks(); | ||||
| 
 | ||||
|         /// Destroy chunks rendered by this node and all its children
 | ||||
|         void destroyChunks(); | ||||
|         /// Destroy chunks rendered by this node *and* its children (if param is true)
 | ||||
|         void destroyChunks(bool children); | ||||
| 
 | ||||
|         /// Get the effective LOD level if this node was rendered in one chunk
 | ||||
|         /// with ESM::Land::LAND_SIZE^2 vertices
 | ||||
|  | @ -127,6 +126,10 @@ namespace Terrain | |||
|         // Stored here for convenience in case we need layer list again
 | ||||
|         MaterialGenerator* mMaterialGenerator; | ||||
| 
 | ||||
|         /// Is this node (or any of its child nodes) currently configured to render itself?
 | ||||
|         /// (only relevant when distant land is disabled, otherwise whole terrain is always rendered)
 | ||||
|         bool mIsActive; | ||||
| 
 | ||||
|         bool mIsDummy; | ||||
|         float mSize; | ||||
|         size_t mLodLevel; // LOD if we were to render this node in one chunk
 | ||||
|  |  | |||
|  | @ -59,6 +59,7 @@ namespace Terrain | |||
|         , mVisibilityFlags(visibilityFlags) | ||||
|         , mDistantLand(distantLand) | ||||
|         , mShaders(shaders) | ||||
|         , mVisible(true) | ||||
|     { | ||||
|         mCompositeMapSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); | ||||
| 
 | ||||
|  | @ -81,6 +82,8 @@ namespace Terrain | |||
|         // Adjust the center according to the new size
 | ||||
|         Ogre::Vector3 center = mBounds.getCenter() + Ogre::Vector3((size-origSizeX)/2.f, (size-origSizeY)/2.f, 0); | ||||
| 
 | ||||
|         mRootSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); | ||||
| 
 | ||||
|         mRootNode = new QuadTreeNode(this, Root, size, Ogre::Vector2(center.x, center.y), NULL); | ||||
|         buildQuadTree(mRootNode); | ||||
|         mRootNode->initAabb(); | ||||
|  | @ -142,6 +145,8 @@ namespace Terrain | |||
| 
 | ||||
|     void Terrain::update(const Ogre::Vector3& cameraPos) | ||||
|     { | ||||
|         if (!mVisible) | ||||
|             return; | ||||
|         mRootNode->update(cameraPos); | ||||
|         mRootNode->updateIndexBuffers(); | ||||
|     } | ||||
|  | @ -379,8 +384,12 @@ namespace Terrain | |||
| 
 | ||||
|     void Terrain::setVisible(bool visible) | ||||
|     { | ||||
|         if (visible && !mVisible) | ||||
|             mSceneMgr->getRootSceneNode()->addChild(mRootSceneNode); | ||||
|         else if (!visible && mVisible) | ||||
|             mSceneMgr->getRootSceneNode()->removeChild(mRootSceneNode); | ||||
| 
 | ||||
|         mVisible = visible; | ||||
|         mRootNode->setVisible(visible); | ||||
|     } | ||||
| 
 | ||||
|     bool Terrain::getVisible() | ||||
|  |  | |||
|  | @ -55,6 +55,8 @@ namespace Terrain | |||
| 
 | ||||
|         Ogre::SceneManager* getSceneManager() { return mSceneMgr; } | ||||
| 
 | ||||
|         Ogre::SceneNode* getRootSceneNode() { return mRootSceneNode; } | ||||
| 
 | ||||
|         Storage* getStorage() { return mStorage; } | ||||
| 
 | ||||
|         /// Show or hide the whole terrain
 | ||||
|  | @ -83,6 +85,7 @@ namespace Terrain | |||
|         bool mVisible; | ||||
| 
 | ||||
|         QuadTreeNode* mRootNode; | ||||
|         Ogre::SceneNode* mRootSceneNode; | ||||
|         Storage* mStorage; | ||||
| 
 | ||||
|         int mVisibilityFlags; | ||||
|  |  | |||
|  | @ -39,7 +39,6 @@ | |||
| #if LIGHTING | ||||
| @shAllocatePassthrough(3, lightResult) | ||||
| @shAllocatePassthrough(3, directionalResult) | ||||
| #endif | ||||
| 
 | ||||
| #if SHADOWS | ||||
| @shAllocatePassthrough(4, lightSpacePos0) | ||||
|  | @ -49,6 +48,7 @@ | |||
|     @shAllocatePassthrough(4, lightSpacePos@shIterator) | ||||
| @shEndForeach | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SH_VERTEX_SHADER | ||||
| 
 | ||||
|  | @ -200,6 +200,7 @@ | |||
|      | ||||
|         @shPassthroughFragmentInputs | ||||
| 
 | ||||
| #if LIGHTING | ||||
| #if SHADOWS | ||||
|         shSampler2D(shadowMap0) | ||||
|         shUniform(float2, invShadowmapSize0)   @shAutoConstant(invShadowmapSize0, inverse_texture_size, @shPropertyString(shadowtexture_offset)) | ||||
|  | @ -215,6 +216,7 @@ | |||
| #if SHADOWS || SHADOWS_PSSM | ||||
|         shUniform(float4, shadowFar_fadeStart) @shSharedParameter(shadowFar_fadeStart) | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| #if (UNDERWATER) || (FOG) | ||||
|         shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue