Commits

Xiangquan Xiao committed bb07c90

gsoc12-terrain: Build a LodInfo table for looking up

  • Participants
  • Parent commits 96b012e

Comments (0)

Files changed (4)

File Components/Terrain/include/OgreTerrain.h

 		void freeGPUResources();
 		void determineLodLevels();
 		void distributeVertexData();
-		/** Create CPU vertex data for given LOD level
-		  @param lodLevel A LOD level to prepare
-		  */
-		void distributeVertexData(uint lodLevel);
 		inline void freeLodData();
 		void updateBaseScale();
 		void createGPUBlendTextures();

File Components/Terrain/include/OgreTerrainLodManager.h

 			_OgreTerrainExport friend std::ostream& operator<<(std::ostream& o, const LoadLodRequest& r)
 			{ return o; }
 		};
+
+		struct LodInfo
+		{
+			uint treeStart;
+			uint treeEnd;
+			bool isLast;
+
+			uint16 resolution;
+			uint size;
+		};
 	public:
         TerrainLodManager(Terrain* t, const String& filename);
         ~TerrainLodManager();
 			    Seconds half is delta data.
 		  */
 		void fillBufferAtLod(uint lodLevel, const float* data, uint dataSize );
-		/** Return TerrainQuadTree depth range associated with given LOD level.
-		@param lodLevel A Lod level number
-		@param treeStart, treeEnd Output tree depth start/end
-		@param lastLevel Output variable. true if lodLevel is highest LOD level in treeStart/treeEnd range.
-		@remarks This method is used to find out what TerrainQuadTree nodes are associated with given LOD level
-				so you know what part of TerrainQuadTree needs to be updated. lastLevel is typically used when
-				LOD level is removed to find out if it is OK to remove whole vertex data range.
-		*/
-		bool getVertexDataRange(uint lodLevel, uint *treeStart, uint *treeEnd);
 		/** Read separated geometry data from file into allocated memory
 		  @param lodLevel Which LOD level to load
 		  @returns Allocated array containing geometry data of given LOD level
 		int getHighestLodPrepared(){ return mHighestLodPrepared; }
 		int getHighestLodLoaded(){ return mHighestLodLoaded; }
 		int getTargetLodLevel(){ return mTargetLodLevel; }
+
+		LodInfo& getLodInfo(uint lodLevel)
+		{
+			if(!mLodInfoTable)
+				buildLodInfoTable();
+			return mLodInfoTable[lodLevel];
+		}
 	private:
 		/** Separate geometry data by LOD level
 		@param data A geometry data to separate i.e. mHeightData/mDeltaData
 			    0: 01 03 05 06 07 08 09 11 13 15 16 17 18 19 21 23
 		  */
 		static void separateData(float* data, uint16 size, uint16 numLodLevels, LodsData& lods );
+		void buildLodInfoTable();
 	private:
 		Terrain* mTerrain;
 		String mDatafile;
 		uint16 mWorkQueueChannel;
 
+		LodInfo* mLodInfoTable;
 		int mHighestLodPrepared;  /// Highest LOD level stored in memory i.e. mHeightData/mDeltaData
 		int mHighestLodLoaded;  /// Highest LOD level loaded in GPU
 

File Components/Terrain/src/OgreTerrain.cpp

 
 	}
 	//---------------------------------------------------------------------
-	void Terrain::distributeVertexData(uint lodLevel)
-	{
-		uint16 depth = mTreeDepth;
-		uint16 prevdepth = depth;
-
-		uint16 currresolution = mSize;
-		uint16 bakedresolution = mSize;
-		uint16 targetSplits = (bakedresolution - 1) / (Terrain::TERRAIN_MAX_BATCH_SIZE - 1);
-
-		uint lodDepth = (lodLevel<mNumLodLevelsPerLeafNode) ? depth-1 : mNumLodLevels-lodLevel-1;
-
-		while(depth-- && targetSplits)
-		{
-			uint splits = 1 << depth;
-			if (splits == targetSplits)
-			{
-				size_t sz = ((bakedresolution-1) / splits) + 1;
-
-				if (lodDepth >= depth && lodDepth < prevdepth)
-				{
-					mQuadTree->assignVertexData(depth, prevdepth, bakedresolution, sz);
-					return;
-				}
-
-				// next set to look for
-				bakedresolution =  ((currresolution - 1) >> 1) + 1;
-				targetSplits = (bakedresolution - 1) / (Terrain::TERRAIN_MAX_BATCH_SIZE - 1);
-				prevdepth = depth;
-			}
-			currresolution = ((currresolution - 1) >> 1) + 1;
-		}
-
-		// Always assign vertex data to the top of the tree
-		if (lodDepth <= prevdepth)
-			mQuadTree->assignVertexData(0, 1, bakedresolution, bakedresolution);
-	}
-	//---------------------------------------------------------------------
 	void Terrain::load(const String& filename)
 	{
 		if (prepare(filename))

File Components/Terrain/src/OgreTerrainLodManager.cpp

 		, mTargetLodLevel(-1)
 		, mIncreaseLodLevelInProgress(false)
 		, mLastRequestSynchronous(false)
+		, mLodInfoTable(0)
 	{
 		WorkQueue* wq = Root::getSingleton().getWorkQueue();
 		mWorkQueueChannel = wq->getChannel("Ogre/TerrainLodManager");
 
 	TerrainLodManager::~TerrainLodManager()
 	{
+		if(mLodInfoTable)
+			OGRE_DELETE[] mLodInfoTable;
+
 		waitForDerivedProcesses();
 		WorkQueue* wq = Root::getSingleton().getWorkQueue();
 		wq->removeRequestHandler(mWorkQueueChannel, this);
 
 		if (res->succeeded())
 		{
-			LogManager::getSingleton().stream() << "Prepared LOD: " << lreq.higherLodBound;
-
 			mHighestLodPrepared = lreq.higherLodBound;
 			mIncreaseLodLevelInProgress = false;
 			if(mTargetLodLevel!=-1)
 				"Failed to prepare the terrain with the error '" << res->getMessages() << "'";
 		}
 	}
+	void TerrainLodManager::buildLodInfoTable()
+	{
+		int numLodLevels = mTerrain->getNumLodLevels();
+		mLodInfoTable = OGRE_NEW LodInfo[numLodLevels];
+
+		uint16 size = mTerrain->getSize();
+		uint16 depth = mTerrain->mTreeDepth;
+		uint16 prevdepth = depth;
+		uint last = 0;
+		uint16 currresolution = size;
+		uint16 bakedresolution = size;
+		uint16 targetSplits = (bakedresolution - 1) / (Terrain::TERRAIN_MAX_BATCH_SIZE - 1);
+
+		int *lodDepth = OGRE_NEW int[numLodLevels];
+		for(int level=0; level<numLodLevels; level++)
+			lodDepth[level] = (level < mTerrain->getNumLodLevelsPerLeaf()) ? depth-1 : numLodLevels-level-1;
+
+		while(depth-- && targetSplits)
+		{
+			uint splits = 1 << depth;
+			if (splits == targetSplits)
+			{
+				for(int level=0; level<numLodLevels; level++)
+				{
+					if (lodDepth[level] >= depth && lodDepth[level] < prevdepth)
+					{
+						mLodInfoTable[level].treeStart = depth;
+						mLodInfoTable[level].treeEnd = prevdepth;
+						mLodInfoTable[level].isLast = level == last+prevdepth-depth-1;
+						mLodInfoTable[level].resolution = bakedresolution;
+						mLodInfoTable[level].size = ((bakedresolution-1) / splits) + 1;
+						// this lod info has been filled
+						lodDepth[level] = -1;
+					}
+				}
+				// next set to look for
+				bakedresolution =  ((currresolution - 1) >> 1) + 1;
+				targetSplits = (bakedresolution - 1) / (Terrain::TERRAIN_MAX_BATCH_SIZE - 1);
+				prevdepth = depth;
+			}
+			currresolution = ((currresolution - 1) >> 1) + 1;
+			last++;
+		}
+		for(int level=0; level<numLodLevels; level++)
+		{
+			if (lodDepth[level]>=0 && lodDepth[level]<=prevdepth)
+			{
+				mLodInfoTable[level].treeStart = 0;
+				mLodInfoTable[level].treeEnd = 1;
+				mLodInfoTable[level].isLast = level == last+prevdepth-depth-1;
+				mLodInfoTable[level].resolution = bakedresolution;
+				mLodInfoTable[level].size = bakedresolution;
+				// this lod info has been filled
+				lodDepth[level] = -1;
+			}
+		}
+		OGRE_DELETE[] lodDepth;
+	}
 
     // data are reorganized from lowest lod level(mNumLodLevels-1) to highest(0)
 	void TerrainLodManager::separateData(float* data, uint16 size, uint16 numLodLevels, LodsData& lods)
 	//---------------------------------------------------------------------
 	void TerrainLodManager::increaseLodLevel(bool synchronous /* = false */)
 	{
-		for (int i=4; i>=0; i--)
-		{
-			uint start, end;
-			LogManager::getSingleton().stream() << getVertexDataRange(i,&start,&end)
-					<< " " << i << " " << start << " " << end;
-		}
-
 		int lodLevel = (mTargetLodLevel>=0) ? mTargetLodLevel-1 : mHighestLodLoaded-1;
 		if( lodLevel>=0 )
 			updateToLodLevel(lodLevel, synchronous);
 				req.lowerLodBound = mHighestLodPrepared-1;
 				req.higherLodBound = lodLevel;
 
-				LogManager::getSingleton().stream() << "Preparing LOD: ("<<req.lowerLodBound<<","<<req.higherLodBound<<")";
-
 				Root::getSingleton().getWorkQueue()->addRequest(
 					mWorkQueueChannel, WORKQUEUE_LOAD_LOD_DATA_REQUEST,
 					Any(req), 0, synchronous);
 			int level=mHighestLodLoaded-1;
 			for( ; level>=lodLevel && level>=mHighestLodPrepared; level-- )
 			{
-				getVertexDataRange(level, &treeStart, &treeEnd);
-				mTerrain->distributeVertexData(level);
-				mTerrain->getQuadTree()->load(treeStart, treeEnd);
+				LodInfo& lod = getLodInfo(level);
+				mTerrain->getQuadTree()->assignVertexData(lod.treeStart, lod.treeEnd, lod.resolution, lod.size);
+				mTerrain->getQuadTree()->load(lod.treeStart, lod.treeEnd);
 			}
 			mHighestLodLoaded = level+1;
 			mTargetLodLevel = (mHighestLodLoaded!=lodLevel) ? lodLevel : -1;
 			uint treeStart, treeEnd;
 			for( int level=mHighestLodLoaded; level<lodLevel; level++ )
 			{
-				if(getVertexDataRange(level, &treeStart, &treeEnd))
+				LodInfo& lod = getLodInfo(level);
+				if(lod.isLast)
 				{
-					mTerrain->getQuadTree()->unload(treeStart, treeEnd);
+					mTerrain->getQuadTree()->unload(lod.treeStart, lod.treeEnd);
 					mHighestLodLoaded = level+1;
 				}
 			}
 				break;
 		}
 	}
-
-	bool TerrainLodManager::getVertexDataRange(uint lodLevel, uint *treeStart, uint *treeEnd)
-	{
-		uint16 numLodLevels = mTerrain->getNumLodLevels();
-		uint16 size = mTerrain->getSize();
-		uint16 depth = mTerrain->mTreeDepth;
-		uint16 prevdepth = depth;
-
-		uint lodDepth = (lodLevel < mTerrain->getNumLodLevelsPerLeaf())
-				? depth - 1 : numLodLevels - lodLevel - 1;
-
-		uint last = 0;
-		uint16 currresolution = size;
-		uint16 bakedresolution = size;
-		uint16 targetSplits = (bakedresolution - 1) / (Terrain::TERRAIN_MAX_BATCH_SIZE - 1);
-		while(depth-- && targetSplits)
-		{
-			uint splits = 1 << depth;
-			if (splits == targetSplits)
-			{
-				if (lodDepth >= depth && lodDepth < prevdepth)
-				{
-					*treeStart = depth;
-					*treeEnd = prevdepth;
-					return (lodLevel == last+prevdepth-depth-1);
-				}
-
-				// next set to look for
-				bakedresolution =  ((currresolution - 1) >> 1) + 1;
-				targetSplits = (bakedresolution - 1) / (Terrain::TERRAIN_MAX_BATCH_SIZE - 1);
-				prevdepth = depth;
-			}
-			currresolution = ((currresolution - 1) >> 1) + 1;
-			last++;
-		}
-		// Always assign vertex data to the top of the tree
-		if (lodDepth<=prevdepth)
-		{
-			*treeStart = 0;
-			*treeEnd = 1;
-		}
-		return (lodLevel == last+prevdepth-depth-1);
-	}
-
 	void TerrainLodManager::waitForDerivedProcesses()
 	{
 		while (mIncreaseLodLevelInProgress)