Commits

Xiangquan Xiao committed 5a8ca8e

gsoc12-terrain: Make LodManager as friend class of Terrain

  • Participants
  • Parent commits c727caf

Comments (0)

Files changed (5)

File Components/Terrain/include/OgreTerrain.h

 		public WorkQueue::RequestHandler, public WorkQueue::ResponseHandler, public TerrainAlloc
 	{
 	public:
+		friend class TerrainLodManager;
+
 		/** Constructor.
 		@param sm The SceneManager to use.
 		*/
 		/// Get the total number of LOD levels in the terrain
 		uint16 getNumLodLevels() const { return mNumLodLevels; }
 
-		uint16 getTreeDepth() const { return mTreeDepth; }
-
 		/// Get the number of LOD levels in a leaf of the terrain quadtree
 		uint16 getNumLodLevelsPerLeaf() const { return mNumLodLevelsPerLeafNode; }
 
 		size_t getPositionBufVertexSize() const;
 		size_t getDeltaBufVertexSize() const;
 
-		bool mIsPrepared;	/// Is Terrain prepared?
 		TerrainLodManager* mLodManager;
 
 	public:
-		/** Read separated geometry data from file into allocated memory
-		  @param filename A file to read from
-		  @param lodLevel Which LOD level to load
-		  @returns Allocated array containing geometry data of given LOD level
-		  @remarks Geometry data are uncompressed using inflate() and stored into
-			    allocated buffer
-		  */
-		float* readGeometryData(String& filename, uint lodLevel);
-
 		/** Create GPU vertex data for given LOD level and textures if needed
 		  @param lodLevel A LOD level to load
 		  @remarks CPU vertex data has to be already created for given LOD level.
-		*/
-		bool loadLodLevel(uint lodLevel);
-
-		/** Copy geometry data from buffer to mHeightData/mDeltaData
-		  @param lodLevel A LOD level to work with
-		  @param data Buffer which holds geometry data if separated form
-		  @remarks Data in buffer has to be both height and delta data. First half is height data.
-			    Seconds half is delta data.
 		  */
-		bool fillLodData(uint lodLevel, float* data);
-
+		bool loadLod(uint lodLevel);
 		/** Increase Terrain's LOD level by 1
 		  @param filename File to read geometry data from
 		  @param synchronous Run synchronously

File Components/Terrain/include/OgreTerrainGroup.h

 		static const uint32 CHUNK_ID;
 		static const uint16 CHUNK_VERSION;
 
-		/// Allocates slot instance and prepares terrain.
-		void prepare(long x, long y, bool synchronous = false);
 		/// Loads terrain's next LOD level.
 		void increaseLodLevel(long x, long y, bool synchronous = false);
 		/// Removes terrain's highest LOD level.

File Components/Terrain/include/OgreTerrainLodManager.h

 		struct LoadLodRequest
 		{
 			uint16 lodLevel;
-			bool readDone;
 			bool synchronous;
 			_OgreTerrainExport friend std::ostream& operator<<(std::ostream& o, const LoadLodRequest& r)
 			{ return o; }
         TerrainLodManager(Terrain* t, const String& filename);
         ~TerrainLodManager();
 
-		static const uint16 WORKQUEUE_LOAD_DATA_REQUEST;
+		static const uint16 WORKQUEUE_LOAD_LOD_DATA_REQUEST;
         virtual WorkQueue::Response* handleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ);
         virtual void handleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ);
 
 		float* separateData(float* data);
 
 		/// save each LOD level separately compressed so seek is possible
-		void saveLodData(StreamSerialiser& stream, float* height, float* delta);
+		void saveLodData(StreamSerialiser& stream);
 		/** Removes highest LOD level loaded
 		  @param onlyLast Remove LOD level only if it is lowest one in its associated vertex data range
 		  @remarks If there is LOD level load in progress it's load is canceled instead of removal of already loaded one.
 		  */
-		bool removeHighestLodLevel(bool onlyLast = false);
+		bool decreaseLodLevel(bool onlyLast = false);
 		/** Create CPU vertex data for given LOD level
 		  @param lodLevel A LOD level to prepare
 		  */
-		bool prepareLodLevel(uint lodLevel);
+		bool assignVertex(uint lodLevel);
 		/** Copy geometry data from buffer to mHeightData/mDeltaData
 		  @param lodLevel A LOD level to work with
 		  @param data Buffer which holds geometry data if separated form
 		  @remarks Data in buffer has to be both height and delta data. First half is height data.
 			    Seconds half is delta data.
 		  */
-		bool fillLodData(uint lodLevel, float* inData, float* heightData, float* deltaData);
+		bool prepareLod(uint lodLevel, float* inData);
 		/** Return TerrainQuadTree depth range associated with given LOD level.
 		@param lodLevel A Lod level number
 		@param treeStart, treeEnd Output tree depth start/end
 		*/
 		bool getVertexDataRange(uint lodLevel, uint *treeStart, uint *treeEnd, uint *lastLevel = NULL);
 		/** Read separated geometry data from file into allocated memory
-		  @param filename A file to read from
 		  @param lodLevel Which LOD level to load
 		  @returns Allocated array containing geometry data of given LOD level
 		  @remarks Geometry data are uncompressed using inflate() and stored into
 			    allocated buffer
 		  */
-		float* readGeometryData(StreamSerialiser& stream, uint lodLevel);
+		float* readGeometryData(uint lodLevel);
 		void waitForDerivedProcesses();
 	private:
 		/** Write already separated geometry data into stream

File Components/Terrain/src/OgreTerrain.cpp

 		, mLastLODFrame(0)
 		, mLastViewportHeight(0)
 		, mCustomGpuBufferAllocator(0)
-		, mIsPrepared(false)
 		, mCustomTextureAllocator(0)
 		, mLodManager(0)
 
 		stream.write(&mMinBatchSize);
 		stream.write(&mPos);
 
-		mLodManager->saveLodData(stream,mHeightData,mDeltaData);
+		mLodManager->saveLodData(stream);
 
 		writeLayerDeclaration(mLayerDecl, stream);
 
 	//---------------------------------------------------------------------
 	bool Terrain::prepare(StreamSerialiser& stream)
 	{
-		if (mIsPrepared)
-			return true;
-
 		freeTemporaryResources();
 		freeCPUResources();
 
 		mModified = false;
 		mHeightDataModified = false;
 
-		mIsPrepared = true;
-
 		return true;
 	}
 
-	bool Terrain::loadLodLevel(uint lodLevel)
+	bool Terrain::loadLod(uint lodLevel)
 	{
 		if(!mLodManager)
 			return false;
 
 		return true;
 	}
-
-	bool Terrain::fillLodData(uint lodLevel, float* data)
-	{
-		if(!mLodManager)
-			return false;
-		mLodManager->fillLodData(lodLevel,data,mHeightData,mDeltaData);
-		return true;
-	}
 	//---------------------------------------------------------------------
 	bool Terrain::prepare(const ImportData& importData)
 	{
 		// Imported data is treated as modified because it's not saved
 		mModified = true;
 		mHeightDataModified = true;
-		mIsPrepared = true;
 
 		return true;
 
 	//---------------------------------------------------------------------
 	void Terrain::increaseLodLevel(bool synchronous /* = false */)
 	{
-		if (!mIsPrepared || !mLodManager)
-			return ;
-		mLodManager->increaseLodLevel(synchronous);
+		if (mLodManager)
+			mLodManager->increaseLodLevel(synchronous);
 	}
 	//---------------------------------------------------------------------
 	void Terrain::decreaseLodLevel()
 	{
-		// if not allocated
-		if (!mIsPrepared || !mLodManager || mLodManager->mTargetLodLevel == -1)
-			return ;
-
-		if (mLodManager->mTargetLodLevel < mNumLodLevels)
-		{
-			mLodManager->removeHighestLodLevel(true);
-		}
+		if (mLodManager)
+			mLodManager->decreaseLodLevel(true);
 	}
 	//---------------------------------------------------------------------
 	void Terrain::setTextureAllocator(TextureAllocator* alloc)
 	{
 		// TODO
 	}
-
-	float* Terrain::readGeometryData(String& filename, uint lodLevel)
-	{
-		DataStreamPtr dStream = Root::getSingleton().openFileStream(filename,
-			_getDerivedResourceGroup());
-		StreamSerialiser stream(dStream);
-
-		stream.readChunkBegin(TERRAIN_CHUNK_ID, TERRAIN_CHUNK_VERSION);
-		stream.skip(sizeof(uint8));  // align
-		stream.skip(sizeof(mSize));
-		stream.skip(sizeof(mWorldSize));
-		stream.skip(sizeof(mMaxBatchSize));
-		stream.skip(sizeof(mMinBatchSize));
-		stream.skip(sizeof(mPos));
-		float *out = mLodManager->readGeometryData(stream,lodLevel);
-		stream.readChunkEnd(TERRAIN_CHUNK_ID);
-
-		return out;
-	}
 }
 

File Components/Terrain/src/OgreTerrainLodManager.cpp

 THE SOFTWARE.
 -----------------------------------------------------------------------------
 */
+#include "OgreRoot.h"
 #include "OgreTerrainQuadTreeNode.h"
 #include "OgreTerrainLodManager.h"
 #include "OgreStreamSerialiser.h"
 
 namespace Ogre
 {
-	const uint16 TerrainLodManager::WORKQUEUE_LOAD_DATA_REQUEST = 1;
+	const uint16 TerrainLodManager::WORKQUEUE_LOAD_LOD_DATA_REQUEST = 1;
 	//TODO: use "TLDA"
 	const uint32 TerrainLodManager::TERRAINLODDATA_CHUNK_ID = StreamSerialiser::makeIdentifier("THDA");
 	const uint16 TerrainLodManager::TERRAINLODDATA_CHUNK_VERSION = 1;
 		LoadLodRequest lreq = any_cast<LoadLodRequest>(req->getData());
 
 		WorkQueue::Response* response = 0;
-		float *mTempGeometryData = NULL;
 		try
 		{
-			if (!lreq.readDone)
-				// read data from file into temporary height & delta buffer
-				mTempGeometryData = terrain->readGeometryData(datafile, lreq.lodLevel);
-			else
-				// create CPU vertex data
-				prepareLodLevel(lreq.lodLevel);
-
-			if (mTempGeometryData)
-				response = OGRE_NEW WorkQueue::Response(req, true, Any(mTempGeometryData));
-			else response = OGRE_NEW WorkQueue::Response(req, true, Any());
+			// read data from file into temporary height & delta buffer
+			float *tempGeometryData = readGeometryData(lreq.lodLevel);
+			// copy height & delta data into terrain's buffers
+			prepareLod(lreq.lodLevel, tempGeometryData);
+			OGRE_FREE(tempGeometryData, MEMCATEGORY_GEOMETRY);
+			response = OGRE_NEW WorkQueue::Response(req, true, Any());
 		}
 		catch (Exception& e)
 		{
 				return ;
 			}
 
-			if (!lreq.readDone)
+			// create GPU data
+			terrain->loadLod(lreq.lodLevel);
+			mHighestLodLoaded = lreq.lodLevel;
+
+			if (mTargetLodLevel < mHighestLodLoaded)
 			{
-				float *mTempGeometryData = any_cast<float*>(res->getData());
-				assert(mTempGeometryData && "Temporary height/delta data can't be NULL");
-
-				// copy height & delta data into terrain's buffers
-				terrain->fillLodData(lreq.lodLevel, mTempGeometryData);
-
-				OGRE_FREE(mTempGeometryData, MEMCATEGORY_GEOMETRY);
-				mTempGeometryData = NULL;
-
-				lreq.readDone = true;
-
-				// create CPU vertex data in background thread
+				lreq.lodLevel--;
 				Root::getSingleton().getWorkQueue()->addRequest(
-				mWorkQueueChannel, WORKQUEUE_LOAD_DATA_REQUEST,
+					mWorkQueueChannel, WORKQUEUE_LOAD_LOD_DATA_REQUEST,
 					Any(lreq), 0, lreq.synchronous);
-
-				return ;
 			}
 			else
-			{
-				// create GPU data
-				terrain->loadLodLevel(lreq.lodLevel);
-
-				mHighestLodLoaded = lreq.lodLevel;
-
-				if (mTargetLodLevel < mHighestLodLoaded)
-				{
-					lreq.lodLevel--;
-					lreq.readDone = false;
-
-					if (mHighestLodPrepared != -1 && mTargetLodLevel >= mHighestLodPrepared)
-						lreq.readDone = true;
-
-					Root::getSingleton().getWorkQueue()->addRequest(
-						mWorkQueueChannel, WORKQUEUE_LOAD_DATA_REQUEST,
-						Any(lreq), 0, lreq.synchronous);
-				}
-				else
-					mIncreaseLodLevelInProgress = false;
-			}
+				mIncreaseLodLevelInProgress = false;
 		}
 		else
 		{
 			// oh dear
 			LogManager::getSingleton().stream(LML_CRITICAL) <<
-				"We failed to prepare the terrain with the error '" << res->getMessages() << "'";
-			// free mem ?
+				"Failed to prepare the terrain with the error '" << res->getMessages() << "'";
 		}
 	}
 
 			LoadLodRequest req;
 			req.lodLevel = mTargetLodLevel;
 			req.synchronous = synchronous;
-			req.readDone = false;
-
-			if (mHighestLodPrepared != -1
-					&& mTargetLodLevel >= mHighestLodPrepared)
-				req.readDone = true;
 
 			Root::getSingleton().getWorkQueue()->addRequest(
-				mWorkQueueChannel, WORKQUEUE_LOAD_DATA_REQUEST,
+				mWorkQueueChannel, WORKQUEUE_LOAD_LOD_DATA_REQUEST,
 				Any(req), 0, synchronous);
 		}
 	}
 	}
 
 	// save each LOD level separately compressed so seek is possible
-	void TerrainLodManager::saveLodData(StreamSerialiser& stream, float* height, float* delta)
+	void TerrainLodManager::saveLodData(StreamSerialiser& stream)
 	{
 		// write heights
-		writeGeometryData(stream, height);
+		writeGeometryData(stream, terrain->mHeightData);
 		// write deltas
-		writeGeometryData(stream, delta);
+		writeGeometryData(stream, terrain->mDeltaData);
 	}
 
 	// save each LOD level separately compressed so seek is possible
 		OGRE_FREE(zstream, MEMCATEGORY_GENERAL);
 	}
 
-	float* TerrainLodManager::readGeometryData(StreamSerialiser& stream, uint lodLevel)
+	float* TerrainLodManager::readGeometryData(uint lodLevel)
 	{
+		DataStreamPtr dStream = Root::getSingleton().openFileStream(datafile,
+			terrain->_getDerivedResourceGroup());
+		StreamSerialiser stream(dStream);
+
+		stream.readChunkBegin(Terrain::TERRAIN_CHUNK_ID, Terrain::TERRAIN_CHUNK_VERSION);
+		stream.skip(sizeof(uint8));  // align
+		stream.skip(sizeof(terrain->mSize));
+		stream.skip(sizeof(terrain->mWorldSize));
+		stream.skip(sizeof(terrain->mMaxBatchSize));
+		stream.skip(sizeof(terrain->mMinBatchSize));
+		stream.skip(sizeof(terrain->mPos));
+
 		uint16 numLodLevels = terrain->getNumLodLevels();
 
 		z_stream* zstream = OGRE_ALLOC_T(z_stream, 1, MEMCATEGORY_GENERAL);
 			OGRE_FREE(in, MEMCATEGORY_GENERAL);
 		}
 		OGRE_FREE(zstream, MEMCATEGORY_GENERAL);
-
+		stream.readChunkEnd(Terrain::TERRAIN_CHUNK_ID);
 		return out;
 	}
-	bool TerrainLodManager::fillLodData(uint lodLevel, float* inData, float* heightData, float* deltaData)
+	bool TerrainLodManager::prepareLod(uint lodLevel, float* inData )
 	{
 		unsigned int ptr = 0;
 		unsigned int inc = 1 << lodLevel;
 		unsigned int prev = 1 << (lodLevel + 1);
+		float* heightData = terrain->mHeightData;
+		float* deltaData = terrain->mDeltaData;
 		uint16 numLodLevels = terrain->getNumLodLevels();
 		uint16 size = terrain->getSize();
 
 
 		mHighestLodPrepared = lodLevel;
 
+		return assignVertex(lodLevel);
+	}
+
+	bool TerrainLodManager::assignVertex(uint lodLevel)
+	{
+		uint16 depth = terrain->mTreeDepth;
+		uint16 prevdepth = depth;
+		uint lodDepth = (lodLevel < terrain->getNumLodLevelsPerLeaf())
+				? depth - 1 : terrain->getNumLodLevels() - lodLevel - 1;
+
+		uint16 currresolution = terrain->getSize();
+		uint16 bakedresolution = terrain->getSize();
+		uint16 targetSplits = (bakedresolution - 1) / (Terrain::TERRAIN_MAX_BATCH_SIZE - 1);
+		while(depth-- && targetSplits)
+		{
+			uint splits = 1 << depth;
+			if (splits == targetSplits)
+			{
+				size_t sz = ((bakedresolution-1) / splits) + 1;
+
+				if (lodDepth >= depth && lodDepth < prevdepth)
+				{
+					terrain->getQuadTree()->assignVertexData(depth, prevdepth, bakedresolution, sz);
+					prevdepth = 0;
+					break;
+				}
+
+				// 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 (prevdepth > 0)
+		{
+			if (lodDepth <= prevdepth)
+				terrain->getQuadTree()->assignVertexData(0, 1, bakedresolution, bakedresolution);
+		}
+
 		return true;
 	}
+	bool TerrainLodManager::decreaseLodLevel(bool onlyLast /* = false */)
+	{
+		if (mTargetLodLevel<0 || mTargetLodLevel >= terrain->getNumLodLevels())
+			return false;
 
-	bool TerrainLodManager::removeHighestLodLevel(bool onlyLast /* = false */)
-	{
 		uint treeStart, treeEnd, lastLevel;
 		uint lodLevel = mTargetLodLevel;
 
 
 		uint16 numLodLevels = terrain->getNumLodLevels();
 		uint16 size = terrain->getSize();
-		uint16 depth = terrain->getTreeDepth();
+		uint16 depth = terrain->mTreeDepth;
 		uint16 prevdepth = depth;
 
 		uint lodDepth = (lodLevel < terrain->getNumLodLevelsPerLeaf())
 				return true;
 			}
 		}
-
 		return false;
 	}
-	bool TerrainLodManager::prepareLodLevel(uint lodLevel)
-	{
-		uint16 depth = terrain->getTreeDepth();
-		uint16 prevdepth = depth;
-		uint lodDepth = (lodLevel < terrain->getNumLodLevelsPerLeaf())
-				? depth - 1 : terrain->getNumLodLevels() - lodLevel - 1;
 
-		uint16 currresolution = terrain->getSize();
-		uint16 bakedresolution = terrain->getSize();
-		uint16 targetSplits = (bakedresolution - 1) / (Terrain::TERRAIN_MAX_BATCH_SIZE - 1);
-		while(depth-- && targetSplits)
-		{
-			uint splits = 1 << depth;
-			if (splits == targetSplits)
-			{
-				size_t sz = ((bakedresolution-1) / splits) + 1;
-
-				if (lodDepth >= depth && lodDepth < prevdepth)
-				{
-					terrain->getQuadTree()->assignVertexData(depth, prevdepth, bakedresolution, sz);
-					prevdepth = 0;
-					break;
-				}
-
-				// 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 (prevdepth > 0)
-		{
-			if (lodDepth <= prevdepth)
-				terrain->getQuadTree()->assignVertexData(0, 1, bakedresolution, bakedresolution);
-		}
-
-		return true;
-	}
 	void TerrainLodManager::waitForDerivedProcesses()
 	{
 		while (mIncreaseLodLevelInProgress)