Commits

Xiangquan Xiao committed 7fb2e7b

gsoc12-terrain: save one lod's height and data at the same block

  • Participants
  • Parent commits 10db87c

Comments (0)

Files changed (4)

File Components/Terrain/include/OgreTerrain.h

 			given LOD level. 
 		*/
 		uint16 getResolutionAtLod(uint16 lodLevel);
+		/** Gets the data size at a given LOD level.
+		*/
+		uint getGeoDataSizeAtLod(uint16 lodLevel);
 
 		/** Test for intersection of a given ray with the terrain. If the ray hits
 		 the terrain, the point of intersection is returned.

File Components/Terrain/include/OgreTerrainLodManager.h

 	public:
 		static const uint32 TERRAINLODDATA_CHUNK_ID;
 		static const uint16 TERRAINLODDATA_CHUNK_VERSION;
+		typedef std::vector<float> LodData;
+		typedef std::vector<LodData> LodsData;
 
 		struct LoadLodRequest
 		{
 			_OgreTerrainExport friend std::ostream& operator<<(std::ostream& o, const LoadLodRequest& r)
 			{ return o; }
 		};
-
 	public:
         TerrainLodManager(Terrain* t, const String& filename);
         ~TerrainLodManager();
 		  @remarks Data in buffer has to be both height and delta data. First half is height data.
 			    Seconds half is delta data.
 		  */
-		bool prepareLod(uint lodLevel, float* inData);
+		void prepareLod(uint lodLevel, const LodData& lod );
 		/** Return TerrainQuadTree depth range associated with given LOD level.
 		@param lodLevel A Lod level number
 		@param treeStart, treeEnd Output tree depth start/end
 		  @remarks Geometry data are uncompressed using inflate() and stored into
 			    allocated buffer
 		  */
-		float* readGeometryData(uint lodLevel);
+		void readLodData(uint lodLevel, LodData& lod);
 		void waitForDerivedProcesses();
 
 		int getHighestLodPrepared(){ return mHighestLodPrepared; }
 			    1: 02 10 12 14 22
 			    0: 01 03 05 06 07 08 09 11 13 15 16 17 18 19 21 23
 		  */
-		static float* separateData(float* data, uint16 size, uint16 numLodLevels);
+		static void separateData(float* data, uint16 size, uint16 numLodLevels, LodsData& lods );
 		/** Write already separated geometry data into stream
 		  @param stream Stream to write into
 		  @param data A geometry data to save

File Components/Terrain/src/OgreTerrain.cpp

 			stream.readChunkBegin(TerrainLodManager::TERRAINLODDATA_CHUNK_ID, TerrainLodManager::TERRAINLODDATA_CHUNK_VERSION);
 			stream.readChunkEnd(TerrainLodManager::TERRAINLODDATA_CHUNK_ID);
 		}
-		for (int i = 0; i < mNumLodLevels; i++)
-		{
-			stream.readChunkBegin(TerrainLodManager::TERRAINLODDATA_CHUNK_ID, TerrainLodManager::TERRAINLODDATA_CHUNK_VERSION);
-			stream.readChunkEnd(TerrainLodManager::TERRAINLODDATA_CHUNK_ID);
-		}
 
 
 		// Layer declaration
 
 		return true;
 	}
-
 	//---------------------------------------------------------------------
 	bool Terrain::prepare(const ImportData& importData)
 	{
 		mModified = true;
 		mHeightDataModified = true;
 
+
 		return true;
 
 	}
 		mIsLoaded = false;
 		mModified = false;
 		mHeightDataModified = false;
+
 	}
 	//---------------------------------------------------------------------
 	void Terrain::unprepare()
 	void Terrain::freeGPUResources()
 	{
 		// remove textures
-		//TextureManager* tmgr = TextureManager::getSingletonPtr();
-		//if (tmgr)
-		//{
 			for (TexturePtrList::iterator i = mBlendTextureList.begin(); i != mBlendTextureList.end(); ++i)
 			{	
-				//tmgr->remove((*i)->getHandle());
 				getTextureAllocator()->remove((*i));
 			}
 			mBlendTextureList.clear();
-		//}
 
 		if (!mTerrainNormalMap.isNull())
 		{
-			//	tmgr->remove(mTerrainNormalMap->getHandle());
 			getTextureAllocator()->remove(mTerrainNormalMap);
 			mTerrainNormalMap.setNull();
 		}
 
 		if (!mColourMap.isNull())
 		{
-			//	tmgr->remove(mColourMap->getHandle());
 			getTextureAllocator()->remove(mColourMap);
 			mColourMap.setNull();
 		}
 
 		if (!mLightmap.isNull())
 		{
-			//	tmgr->remove(mLightmap->getHandle());
 			getTextureAllocator()->remove(mLightmap);
 			mLightmap.setNull();
 		}
 
 		if (!mCompositeMap.isNull())
 		{
-			//	tmgr->remove(mCompositeMap->getHandle());
 			getTextureAllocator()->remove(mCompositeMap);
 			mCompositeMap.setNull();
 		}
 		return ((mSize - 1) >> lodLevel) + 1;
 	}
 	//---------------------------------------------------------------------
+	uint Terrain::getGeoDataSizeAtLod(uint16 lodLevel)
+	{
+		uint size = getResolutionAtLod(lodLevel);
+		uint prevSize = (lodLevel<mNumLodLevels-1) ? getResolutionAtLod(lodLevel+1) : 0;
+		return size*size - prevSize*prevSize;
+	}
+	//---------------------------------------------------------------------
 	void Terrain::preFindVisibleObjects(SceneManager* source, 
 		SceneManager::IlluminationRenderStage irs, Viewport* v)
 	{
 		while (mBlendTextureList.size() > numTex)
 		{
 			getTextureAllocator()->remove(mBlendTextureList.back());
-			//tmgr->remove(mBlendTextureList.back()->getHandle());
 			mBlendTextureList.pop_back();
 		}
 
 			// Use TU_STATIC because although we will update this, we won't do it every frame
 			// in normal circumstances, so we don't want TU_DYNAMIC. Also we will 
 			// read it (if we've cleared local temp areas) so no WRITE_ONLY
-			//mBlendTextureList[i] = TextureManager::getSingleton().createManual(
-			//	msBlendTextureGenerator.generate(), _getDerivedResourceGroup(),
-			//	TEX_TYPE_2D, mLayerBlendMapSize, mLayerBlendMapSize, 1, 0, fmt, TU_STATIC);
 			mBlendTextureList[i] = getTextureAllocator()->createManual(this,
 			mLayerBlendMapSize, 0, fmt);
 
 		if (mNormalMapRequired && mTerrainNormalMap.isNull())
 		{
 			// create
-			//mTerrainNormalMap = TextureManager::getSingleton().createManual(
-			//	mMaterialName + "/nm", _getDerivedResourceGroup(),
-			//	TEX_TYPE_2D, mSize, mSize, 1, 0, PF_BYTE_RGB, TU_STATIC);
 			mTerrainNormalMap = getTextureAllocator()->createManual(this,
 				mSize, 0, PF_BYTE_RGB);
 
 		{
 			// destroy
 			getTextureAllocator()->remove(mTerrainNormalMap);
-			//TextureManager::getSingleton().remove(mTerrainNormalMap->getHandle());
 			mTerrainNormalMap.setNull();
 		}
 
 		if (mGlobalColourMapEnabled && mColourMap.isNull())
 		{
 			// create
-			//mColourMap = TextureManager::getSingleton().createManual(
-			//	mMaterialName + "/cm", _getDerivedResourceGroup(),
-			//	TEX_TYPE_2D, mGlobalColourMapSize, mGlobalColourMapSize, MIP_DEFAULT,
-			//	PF_BYTE_RGB, TU_STATIC);
 			mColourMap = getTextureAllocator()->createManual(this,
 				mGlobalColourMapSize, MIP_DEFAULT, PF_BYTE_RGB);
 
 		{
 			// destroy
 			getTextureAllocator()->remove(mColourMap);
-			//TextureManager::getSingleton().remove(mColourMap->getHandle());
 			mColourMap.setNull();
 		}
 
 		if (mLightMapRequired && mLightmap.isNull())
 		{
 			// create
-			//mLightmap = TextureManager::getSingleton().createManual(
-			//	mMaterialName + "/lm", _getDerivedResourceGroup(),
-			//	TEX_TYPE_2D, mLightmapSize, mLightmapSize, 0, PF_L8, TU_STATIC);
 			mLightmap = getTextureAllocator()->createManual(this,
 				mLightmapSize, 0, PF_L8);
 
 		{
 			// destroy
 			getTextureAllocator()->remove(mLightmap);
-			//TextureManager::getSingleton().remove(mLightmap->getHandle());
 			mLightmap.setNull();
 		}
 
 		if (mCompositeMapRequired && mCompositeMap.isNull())
 		{
 			// create
-			//mCompositeMap = TextureManager::getSingleton().createManual(
-			//	mMaterialName + "/comp", _getDerivedResourceGroup(),
-			//	TEX_TYPE_2D, mCompositeMapSize, mCompositeMapSize, 0, PF_BYTE_RGBA, TU_STATIC);
 			mCompositeMap = getTextureAllocator()->createManual(this,
 			mCompositeMapSize, 0, PF_BYTE_RGBA);
 
 		{
 			// destroy
 			getTextureAllocator()->remove(mCompositeMap);
-			//TextureManager::getSingleton().remove(mCompositeMap->getHandle());
 			mCompositeMap.setNull();
 		}
 

File Components/Terrain/src/OgreTerrainLodManager.cpp

 namespace Ogre
 {
 	const uint16 TerrainLodManager::WORKQUEUE_LOAD_LOD_DATA_REQUEST = 1;
-	//TODO: use "TLDA"
-	const uint32 TerrainLodManager::TERRAINLODDATA_CHUNK_ID = StreamSerialiser::makeIdentifier("THDA");
+	const uint32 TerrainLodManager::TERRAINLODDATA_CHUNK_ID = StreamSerialiser::makeIdentifier("TLDA");
 	const uint16 TerrainLodManager::TERRAINLODDATA_CHUNK_VERSION = 1;
 
 	TerrainLodManager::TerrainLodManager(Terrain* t, const String& filename)
 		try
 		{
 			// read data from file into temporary height & delta buffer
-			float *tempGeometryData = readGeometryData(lreq.lodLevel);
+			LodData lod;
+			readLodData(lreq.lodLevel, lod);
 			// copy height & delta data into terrain's buffers
-			prepareLod(lreq.lodLevel, tempGeometryData);
-			OGRE_FREE(tempGeometryData, MEMCATEGORY_GEOMETRY);
+			prepareLod(lreq.lodLevel, lod);
 			response = OGRE_NEW WorkQueue::Response(req, true, Any());
 		}
 		catch (Exception& e)
 	}
 
     // data are reorganized from lowest lod level(mNumLodLevels-1) to highest(0)
-	float* TerrainLodManager::separateData(float* data, uint16 size, uint16 numLodLevels)
+	void TerrainLodManager::separateData(float* data, uint16 size, uint16 numLodLevels, LodsData& lods)
 	{
-		unsigned int ptr = 0;
-		float* sep = OGRE_ALLOC_T(float, size*size, MEMCATEGORY_GENERAL);
-
+		lods.resize(numLodLevels);
 		for (int level = numLodLevels - 1; level >= 0; level--)
 		{
 			unsigned int inc = 1 << level;
 			{
 				for (uint16 x = 0; x < size-1; x += inc)
 					if ((level == numLodLevels - 1) || ((x % prev != 0) || (y % prev != 0)))
-						sep[ptr++] = *(data + y * size + x);
+						lods[level].push_back( data[y*size + x] );
 				if ((level == numLodLevels -1) || (y % prev) != 0)
-					sep[ptr++] = *(data + y * size + size - 1);
+					lods[level].push_back( data[y*size + size-1] );
 				if (y+inc > size)
 					break;
 			}
 		}
-
-		return sep;
 	}
 	//---------------------------------------------------------------------
 	void TerrainLodManager::increaseLodLevel(bool synchronous /* = false */)
 	// save each LOD level separately compressed so seek is possible
 	void TerrainLodManager::saveLodData(StreamSerialiser& stream, Terrain* terrain)
 	{
-		// write heights
-		writeGeometryData(stream, terrain, terrain->mHeightData);
-		// write deltas
-		writeGeometryData(stream, terrain, terrain->mDeltaData);
-	}
-
-	// save each LOD level separately compressed so seek is possible
-	void TerrainLodManager::writeGeometryData(StreamSerialiser& stream, Terrain* terrain, float* data)
-	{
 		uint16 numLodLevels = terrain->getNumLodLevels();
 
 		z_stream* zstream = OGRE_ALLOC_T(z_stream, 1, MEMCATEGORY_GENERAL);
 		zstream->zalloc = OgreTerrainZalloc;
 		zstream->zfree = OgreTerrainZfree;
 
-		int ret;
+		int zstream_ret;
 		char out[OGRE_TERRAIN_DEFLATE_TMP_SIZE];
 
-		float* sep = separateData(data, terrain->getSize(), numLodLevels);
+		LodsData lods;
+		separateData(terrain->mHeightData, terrain->getSize(), numLodLevels, lods);
+		separateData(terrain->mDeltaData, terrain->getSize(), numLodLevels, lods);
 
-		uint32 offset = 0;
-		uint32 size;
-		uint32 prevSize = 0;
-		uint32 diff;
-		for (int i = numLodLevels - 1; i >=0; i--)
+		for (int level = numLodLevels - 1; level >=0; level--)
 		{
-			if (deflateInit(zstream, Z_DEFAULT_COMPRESSION) != Z_OK)
-			{
-				OGRE_EXCEPT(Exception::ERR_INVALID_STATE,
-					"Error initialising deflate compressed stream!",
-					"Terrain::writeGeometryData");
-			}
-
-			size = terrain->getResolutionAtLod(i);
-			if (i != numLodLevels-1)
-				prevSize = terrain->getResolutionAtLod(i+1);
-
-			diff = size*size - prevSize*prevSize;
+			zstream_ret = deflateInit(zstream, Z_DEFAULT_COMPRESSION);
+			assert(zstream_ret==Z_OK);
 
 			int flush = Z_NO_FLUSH;
 			uint done = 0;
 			stream.writeChunkBegin(TERRAINLODDATA_CHUNK_ID, TERRAINLODDATA_CHUNK_VERSION);
 			do
 			{
-				zstream->next_in = ((Bytef*)(sep + offset)) + done;
+				zstream->next_in = (Bytef*)(&lods[level][0]) + done;
+				uint length = lods[level].size() * sizeof(float);
 
 				done += OGRE_TERRAIN_DEFLATE_TMP_SIZE;
-				if (done >= diff*sizeof(float))
+				if (done >= length)
 				{
 					flush = Z_FINISH;
-					zstream->avail_in = OGRE_TERRAIN_DEFLATE_TMP_SIZE - (done - diff * sizeof(float));
+					zstream->avail_in = OGRE_TERRAIN_DEFLATE_TMP_SIZE - (done-length);
 				}
-				else zstream->avail_in = OGRE_TERRAIN_DEFLATE_TMP_SIZE;
+				else
+					zstream->avail_in = OGRE_TERRAIN_DEFLATE_TMP_SIZE;
 
 				do
 				{
 					zstream->avail_out = OGRE_TERRAIN_DEFLATE_TMP_SIZE;
 					zstream->next_out = (Bytef*)out;
-					ret = deflate(zstream, flush);	// no bad return value
-					assert(ret != Z_STREAM_ERROR);  // state not clobbered
+					zstream_ret = deflate(zstream, flush);	// no bad return value
+					assert(zstream_ret != Z_STREAM_ERROR);  // state not clobbered
 					size_t compressed = OGRE_TERRAIN_DEFLATE_TMP_SIZE - zstream->avail_out;
 					stream.write(out, compressed);
 				} while (zstream->avail_out == 0);
 			stream.writeChunkEnd(TERRAINLODDATA_CHUNK_ID);
 
 			assert(zstream->avail_in == 0 && "all input not read");	 // all input will be used
-			assert(ret == Z_STREAM_END && "ret not END");		// stream will be complete
+			assert(zstream_ret == Z_STREAM_END && "ret not END");		// stream will be complete
 
 			deflateEnd(zstream);
-
-			offset += diff;
 		}
-
-		OGRE_FREE(sep, MEMCATEGORY_GENERAL);
 		OGRE_FREE(zstream, MEMCATEGORY_GENERAL);
 	}
 
-	float* TerrainLodManager::readGeometryData(uint lodLevel)
+	void TerrainLodManager::readLodData(uint lodLevel, LodData& lod)
 	{
+		uint16 numLodLevels = mTerrain->getNumLodLevels();
+
 		DataStreamPtr dStream = Root::getSingleton().openFileStream(mDatafile,
 			mTerrain->_getDerivedResourceGroup());
 		StreamSerialiser stream(dStream);
 		// skip the general information
 		stream.readChunkBegin(Terrain::TERRAINGENERALINFO_CHUNK_ID, Terrain::TERRAINGENERALINFO_CHUNK_VERSION);
 		stream.readChunkEnd(Terrain::TERRAINGENERALINFO_CHUNK_ID);
-
-		uint16 numLodLevels = mTerrain->getNumLodLevels();
-
-		z_stream* zstream = OGRE_ALLOC_T(z_stream, 1, MEMCATEGORY_GENERAL);
-		zstream->zalloc = OgreTerrainZalloc;
-		zstream->zfree = OgreTerrainZfree;
-
-		uint32 size = mTerrain->getResolutionAtLod(lodLevel);
-		uint32 prevSize = 0;
-		if (lodLevel != numLodLevels-1)
-		prevSize = mTerrain->getResolutionAtLod(lodLevel+1);
-
-		uint32 diff = size*size - prevSize*prevSize;
-
-		float *out = OGRE_ALLOC_T(float, diff*2, MEMCATEGORY_GENERAL);
-
-		uint32 offset = 0;
-		uint32 lvlCalc = lodLevel + 1 + numLodLevels;
-		for (uint i = numLodLevels*2; i > 0 ; i--)
+		// skip the previous lod data
+		for(int skip=numLodLevels-1-lodLevel; skip>0; skip--)
 		{
 			stream.readChunkBegin(TERRAINLODDATA_CHUNK_ID, TERRAINLODDATA_CHUNK_VERSION);
+			stream.readChunkEnd(TERRAINLODDATA_CHUNK_ID);
+		}
 
-			if (i != lvlCalc && i != lvlCalc-numLodLevels)
-			{
-				stream.readChunkEnd(TERRAINLODDATA_CHUNK_ID);
-				continue;
-			}
+		// reach and read the target lod data
+		const StreamSerialiser::Chunk *c = stream.readChunkBegin(TERRAINLODDATA_CHUNK_ID,
+				TERRAINLODDATA_CHUNK_VERSION);
+		float* in = OGRE_ALLOC_T(float, c->length, MEMCATEGORY_GENERAL);
+		stream.read((char*)in, c->length);
 
-			// read
-			const StreamSerialiser::Chunk *c = stream.getCurrentChunk();
-			float* in = OGRE_ALLOC_T(float, c->length, MEMCATEGORY_GENERAL);
+		// uncompress
+		z_stream* zstream = OGRE_ALLOC_T(z_stream, 1, MEMCATEGORY_GENERAL);
+		zstream->zalloc = OgreTerrainZalloc;
+		zstream->zfree = OgreTerrainZfree;
+		zstream->avail_in = c->length;
+		zstream->next_in = (Bytef*)in;
 
-			stream.read((char*)in, c->length);
+		inflateInit(zstream);
 
-			zstream->avail_in = c->length;
-			zstream->next_in = (Bytef*)in;
+		// both height data and delta data
+		uint dataSize = 2 * mTerrain->getGeoDataSizeAtLod(lodLevel);
+		lod.resize(dataSize);
+		zstream->avail_out = dataSize * sizeof(float);
+		zstream->next_out = (Bytef*)(&lod[0]);
 
-			stream.readChunkEnd(TERRAINLODDATA_CHUNK_ID);
-
-			// uncompress
-			if (inflateInit(zstream) != Z_OK)
+		while (zstream->avail_out)
+		{
+			if (zstream->avail_in)
 			{
-				OGRE_EXCEPT(Exception::ERR_INVALID_STATE,
-					"Error initialising deflate compressed stream!",
-					"Terrain::readGeometryData");
-			}
-
-			zstream->avail_out = diff * sizeof(float);
-			zstream->next_out = (Bytef*)(out + offset);
-
-			offset = diff;
-
-			while (zstream->avail_out)
-			{
-				if (zstream->avail_in)
+				int status = inflate(zstream, Z_SYNC_FLUSH);
+				// End of data or error
+				if (status != Z_OK)
 				{
-					int status = inflate(zstream, Z_SYNC_FLUSH);
-					if (status != Z_OK)
-					{
-						// End of data, or error
-						if (status != Z_STREAM_END)
-						{
-							OGRE_EXCEPT(Exception::ERR_INVALID_STATE,
-								"Error in compressed stream",
-								"DeflateStrea::read");
-						}
-						break;
-					}
+					assert(status == Z_STREAM_END && "Error in compressed stream" );
+					break;
 				}
 			}
+		}
+		inflateEnd(zstream);
 
-			inflateEnd(zstream);
-
-			OGRE_FREE(in, MEMCATEGORY_GENERAL);
-		}
+		OGRE_FREE(in, MEMCATEGORY_GENERAL);
 		OGRE_FREE(zstream, MEMCATEGORY_GENERAL);
-		stream.readChunkEnd(Terrain::TERRAIN_CHUNK_ID);
-		return out;
 	}
-	bool TerrainLodManager::prepareLod(uint lodLevel, float* inData )
+	void TerrainLodManager::prepareLod(uint lodLevel, const LodData& lod )
 	{
-		unsigned int ptr = 0;
 		unsigned int inc = 1 << lodLevel;
 		unsigned int prev = 1 << (lodLevel + 1);
-		float* heightData = mTerrain->mHeightData;
-		float* deltaData = mTerrain->mDeltaData;
 		uint16 numLodLevels = mTerrain->getNumLodLevels();
 		uint16 size = mTerrain->getSize();
 
+		LodData::const_iterator heightDataIter = lod.begin();
+		LodData::const_iterator deltaDataIter = heightDataIter + lod.size()/2;
+
 		for (uint16 y = 0; y < size; y += inc)
 		{
 			for (uint16 x = 0; x < size-1; x += inc)
 				if ((lodLevel == numLodLevels - 1) || (x % prev != 0) || (y % prev != 0))
-					heightData[y * size + x] = inData[ptr++];
+				{
+					mTerrain->mHeightData[y*size + x] = *(heightDataIter++);
+					mTerrain->mDeltaData[y*size + x] = *(deltaDataIter++);
+				}
 			if ((lodLevel == numLodLevels - 1) || (y % prev) != 0)
-				heightData[y * size + size - 1] = inData[ptr++];
-			if (y+inc > size)
-				break;
-		}
-
-		for (uint16 y = 0; y < size; y += inc)
-		{
-			for (uint16 x = 0; x < size-1; x += inc)
-				if ((lodLevel == numLodLevels - 1) || (x % prev != 0) || (y % prev != 0))
-					deltaData[y * size + x] = inData[ptr++];
-			if ((lodLevel == numLodLevels - 1) || (y % prev) != 0)
-				deltaData[y * size + size - 1] = inData[ptr++];
+			{
+				mTerrain->mHeightData[y*size + size-1] = *(heightDataIter++);
+				mTerrain->mDeltaData[y*size + size-1] = *(deltaDataIter++);
+			}
 			if (y+inc > size)
 				break;
 		}
 
 		mHighestLodPrepared = lodLevel;
 		mTerrain->distributeVertexData(lodLevel);
-		return true;
 	}
 
 	bool TerrainLodManager::decreaseLodLevel(bool onlyLast /* = false */)