Commits

Xiangquan Xiao committed e236759

gsoc12-terrain: Move increaseLod,read/WriteGeometry,fillLod to LodManager

  • Participants
  • Parent commits d5d8042

Comments (0)

Files changed (7)

File Components/Terrain/include/OgreTerrain.h

 				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, uint *lastLevel = NULL);
-
-		/** Write already separated geometry data into stream
-		  @param data A geometry data to save
-		  @param stream Stream to write into
-		  @remarks Each LOD level has its own Chunk of data for easy read later.
-			Each chunk's payload is compressed using deflate() as well.
-		  */
-		void writeGeometryData(float* data, StreamSerialiser& stream);
 
 	public:
 

File Components/Terrain/include/OgreTerrainGroup.h

 			TerrainSlotDefinition def;
 			/// Actual terrain instance
 			Terrain* instance;
-			/// Is terrain already prepared?
-			bool isPrepared;
-			/// Is Terrain::prepare() in progress?
-			bool prepareInProgress;
-			/// Is terrain already loaded?
-			bool isLoaded;
-			/// Should this request run asychronously?
-			bool synchronous;
-			/// Should there be increaseLodLevel() called after prepare()?
-			bool load;
 
-			TerrainSlot(long _x, long _y) : x(_x), y(_y), instance(0)
-				, isPrepared(false)
-				, prepareInProgress(false)
-				, isLoaded(false)
-				, synchronous(false)
-				, load(false) {}
+			TerrainSlot(long _x, long _y) : x(_x), y(_y), instance(0) {}
 			~TerrainSlot();
 			void freeInstance();
 		};

File Components/Terrain/include/OgreTerrainLodManager.h

 #include "OgreTerrainPrerequisites.h"
 #include "OgreWorkQueue.h"
 
+
 namespace Ogre
 {
+	#define OGRE_TERRAIN_DEFLATE_TMP_SIZE 16384
 	class Terrain;
 	/** \addtogroup Optional Components
 	*  @{
         ~TerrainLodManager();
 
 		static const uint16 WORKQUEUE_LOAD_DATA_REQUEST;
-        bool canHandleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ);
-        bool canHandleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ);
         virtual WorkQueue::Response* handleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ);
         virtual void handleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ);
 
         	return mWorkQueueChannel;
         }
 
-	public:
-		struct LoadRequest
-		{
-			Terrain* terrain;
-			String filename;
-			uint16 lodLevel;
-			bool readDone;
-			bool synchronous;
-			_OgreTerrainExport friend std::ostream& operator<<(std::ostream& o, const LoadRequest& r)
-			{ return o; }
-		};
+        /** Increase Terrain's LOD level by 1
+		  @param filename File to read geometry data from
+		  @param synchronous Run synchronously
+		  */
+    	void increaseLodLevel(const String& filename, bool synchronous = false);
 
 		/** Separate geometry data by LOD level
 		@param data A geometry data to separate i.e. mHeightData/mDeltaData
 			    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 patchSize, uint16 numLodLevels);
+		float* separateData(float* data);
+		/** Write already separated geometry data into stream
+		  @param data A geometry data to save
+		  @param stream Stream to write into
+		  @remarks Each LOD level has its own Chunk of data for easy read later.
+			Each chunk's payload is compressed using deflate() as well.
+		  */
+		void writeGeometryData(float* data, StreamSerialiser& stream);
+		/** 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);
+		/** 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);
 
+	public:
+		struct LoadRequest
+		{
+			String filename;
+			uint16 lodLevel;
+			bool readDone;
+			bool synchronous;
+			_OgreTerrainExport friend std::ostream& operator<<(std::ostream& o, const LoadRequest& r)
+			{ return o; }
+		};
 
 		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

 #include "OgreMaterialManager.h"
 #include "OgreHardwareBufferManager.h"
 #include "OgreDeflate.h"
-#include <zlib.h>
 
 
 #if OGRE_COMPILER == OGRE_COMPILER_MSVC
 		stream.write(&mPos);
 
 		// write heights
-		writeGeometryData(mHeightData, stream);
+		mLodManager.writeGeometryData(mHeightData, stream);
 		// write deltas
-		writeGeometryData(mDeltaData, stream);
+		mLodManager.writeGeometryData(mDeltaData, stream);
 
 		writeLayerDeclaration(mLayerDecl, stream);
 
 
 	bool Terrain::fillLodData(uint lodLevel, float* data)
 	{
-		//if (lodLevel >= mHighestLodStored && mHighestLodStored >= 0)
-			//return true;
-
 		if (!mHeightData)
 		{
 			mHeightData = OGRE_ALLOC_T(float, mSize * mSize, MEMCATEGORY_GEOMETRY);
 			mDeltaData = OGRE_ALLOC_T(float, mSize * mSize, MEMCATEGORY_GEOMETRY);
 		}
-
-		unsigned int ptr = 0;
-		unsigned int inc = 1 << lodLevel;
-		unsigned int prev = 1 << (lodLevel + 1);
-
-		for (uint16 y = 0; y < mSize; y += inc)
-		{
-			for (uint16 x = 0; x < mSize-1; x += inc)
-			{
-				if ((lodLevel == mNumLodLevels - 1) || (x % prev != 0) || (y % prev != 0))
-					mHeightData[y * mSize + x] = data[ptr++];
-			}
-			if ((lodLevel == mNumLodLevels - 1) || (y % prev) != 0)
-				mHeightData[y * mSize + mSize - 1] = data[ptr++];
-
-			if (y+inc > mSize)
-				break;
-		}
-
-		for (uint16 y = 0; y < mSize; y += inc)
-		{
-			for (uint16 x = 0; x < mSize-1; x += inc)
-			{
-				if ((lodLevel == mNumLodLevels - 1) || (x % prev != 0) || (y % prev != 0))
-					mDeltaData[y * mSize + x] = data[ptr++];
-			}
-			if ((lodLevel == mNumLodLevels - 1) || (y % prev) != 0)
-				mDeltaData[y * mSize + mSize - 1] = data[ptr++];
-
-			if (y+inc > mSize)
-				break;
-		}
-
-		mLodManager.mHighestLodPrepared = lodLevel;
-
+		mLodManager.fillLodData(lodLevel,data,mHeightData,mDeltaData);
 		return true;
 	}
 	//---------------------------------------------------------------------
 			  mHeightData[y2 * mSize + x1] * (1.0 - rx) * ry +
 			  mHeightData[y2 * mSize + x2] * rx * ry;
 
-		//LogManager::getSingleton().stream() << res << " -- " << mHeightData[y * mSize + x];
-
 		return res;
 
 	}
 	//---------------------------------------------------------------------
 	void Terrain::increaseLodLevel(const String& filename, bool synchronous /* = false */)
 	{
-		if (!mIsPrepared || mLodManager.mHighestLodLoaded == 0 || mLodManager.mTargetLodLevel == 0)
+		if (!mIsPrepared)
 			return ;
-
-		if (mLodManager.mTargetLodLevel == -1)
-		{
-			if (mLodManager.mHighestLodLoaded == -1)
-				mLodManager.mTargetLodLevel = mNumLodLevels - 1;
-			else
-				mLodManager.mTargetLodLevel = mLodManager.mHighestLodLoaded - 1;
-		}
-		else
-			mLodManager.mTargetLodLevel--;
-
-		// dont load if lod already loaded
-		if (mLodManager.mHighestLodLoaded != -1 && mLodManager.mTargetLodLevel >= mLodManager.mHighestLodLoaded)
-		{
-			mLodManager.mTargetLodLevel = mLodManager.mHighestLodLoaded;
-			return ;
-		}
-
-		if (!mLodManager.mIncreaseLodLevelInProgress)
-		{
-			mLodManager.mIncreaseLodLevelInProgress = true;
-
-			TerrainLodManager::LoadRequest req;
-			req.terrain = this;
-			req.lodLevel = mLodManager.mTargetLodLevel;
-			req.filename = filename;
-			req.synchronous = synchronous;
-			req.readDone = false;
-
-			if (mLodManager.mHighestLodPrepared != -1
-					&& mLodManager.mTargetLodLevel >= mLodManager.mHighestLodPrepared)
-				req.readDone = true;
-
-			Root::getSingleton().getWorkQueue()->addRequest(
-				mLodManager.getWorkQueueChannel(), TerrainLodManager::WORKQUEUE_LOAD_DATA_REQUEST,
-				Any(req), 0, synchronous);
-		}
+		mLodManager.increaseLodLevel(filename,synchronous);
 	}
 	//---------------------------------------------------------------------
 	void Terrain::decreaseLodLevel()
 		// TODO
 	}
 
-	void* OgreTerrainZalloc(void* opaque, unsigned int items, unsigned int size)
-	{
-		return OGRE_MALLOC(items * size, MEMCATEGORY_GENERAL);
-	}
-	void OgreTerrainZfree(void* opaque, void* address)
-	{
-		OGRE_FREE(address, MEMCATEGORY_GENERAL);
-	}
-	#define OGRE_TERRAIN_DEFLATE_TMP_SIZE 16384
-	// save each LOD level separately compressed so seek is possible
-	void Terrain::writeGeometryData(float* data, StreamSerialiser& stream)
-	{
-		z_stream* zstream = OGRE_ALLOC_T(z_stream, 1, MEMCATEGORY_GENERAL);
-		zstream->zalloc = OgreTerrainZalloc;
-		zstream->zfree = OgreTerrainZfree;
-
-		int ret;
-		char out[OGRE_TERRAIN_DEFLATE_TMP_SIZE];
-
-		float* sep = TerrainLodManager::separateData(data,mSize,mNumLodLevels);
-
-		uint32 offset = 0;
-		uint32 size;
-		uint32 prevSize = 0;
-		uint32 diff;
-		for (int i = mNumLodLevels - 1; i >=0; i--)
-		{
-			if (deflateInit(zstream, Z_DEFAULT_COMPRESSION) != Z_OK)
-			{
-				OGRE_EXCEPT(Exception::ERR_INVALID_STATE,
-					"Error initialising deflate compressed stream!",
-					"Terrain::writeGeometryData");
-			}
-
-			size = getResolutionAtLod(i);
-			if (i != mNumLodLevels-1)
-				prevSize = getResolutionAtLod(i+1);
-
-			diff = size*size - prevSize*prevSize;
-
-			int flush = Z_NO_FLUSH;
-			uint done = 0;
-
-			stream.writeChunkBegin(TERRAINHEIGHTDATA_CHUNK_ID, TERRAINHEIGHTDATA_CHUNK_VERSION);
-			do
-			{
-				zstream->next_in = ((Bytef*)(sep + offset)) + done;
-
-				done += OGRE_TERRAIN_DEFLATE_TMP_SIZE;
-				if (done >= diff*sizeof(float))
-				{
-					flush = Z_FINISH;
-					zstream->avail_in = OGRE_TERRAIN_DEFLATE_TMP_SIZE - (done - diff * sizeof(float));
-				}
-				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
-					size_t compressed = OGRE_TERRAIN_DEFLATE_TMP_SIZE - zstream->avail_out;
-					stream.write(out, compressed);
-				} while (zstream->avail_out == 0);
-			} while (flush != Z_FINISH);
-			stream.writeChunkEnd(TERRAINHEIGHTDATA_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
-
-			deflateEnd(zstream);
-
-			offset += diff;
-		}	   
-
-		OGRE_FREE(sep, MEMCATEGORY_GENERAL);
-		OGRE_FREE(zstream, MEMCATEGORY_GENERAL);	   
-	}
-
 	float* Terrain::readGeometryData(String& filename, uint lodLevel)
 	{
 		DataStreamPtr dStream = Root::getSingleton().openFileStream(filename,
 			_getDerivedResourceGroup());
-
-		StreamSerialiser stream(dStream);		
+		StreamSerialiser stream(dStream);
 
 		stream.readChunkBegin(TERRAIN_CHUNK_ID, TERRAIN_CHUNK_VERSION);
 		stream.skip(sizeof(uint8));  // align
 		stream.skip(sizeof(mMaxBatchSize));
 		stream.skip(sizeof(mMinBatchSize));
 		stream.skip(sizeof(mPos));
-
-		z_stream* zstream = OGRE_ALLOC_T(z_stream, 1, MEMCATEGORY_GENERAL);
-		zstream->zalloc = OgreTerrainZalloc;
-		zstream->zfree = OgreTerrainZfree;
-
-		uint32 size = getResolutionAtLod(lodLevel);
-		uint32 prevSize = 0;
-		if (lodLevel != mNumLodLevels-1)
-		prevSize = 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 + mNumLodLevels;
-		for (uint i = mNumLodLevels*2; i > 0 ; i--)
-		{
-			stream.readChunkBegin(TERRAINHEIGHTDATA_CHUNK_ID, TERRAINHEIGHTDATA_CHUNK_VERSION);
-
-			if (i != lvlCalc && i != lvlCalc-mNumLodLevels)
-			{
-				stream.readChunkEnd(TERRAINHEIGHTDATA_CHUNK_ID);
-				continue;
-			}
-
-			// read
-			const StreamSerialiser::Chunk *c = stream.getCurrentChunk();
-			float* in = OGRE_ALLOC_T(float, c->length, MEMCATEGORY_GENERAL);
-	
-			stream.read((char*)in, c->length);
-	
-			zstream->avail_in = c->length;
-			zstream->next_in = (Bytef*)in;
-	
-			stream.readChunkEnd(TERRAINHEIGHTDATA_CHUNK_ID);
-	
-			// uncompress
-			if (inflateInit(zstream) != Z_OK)
-			{
-				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);
-					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;
-					}
-				}
-			}
-	
-			inflateEnd(zstream);
-
-			OGRE_FREE(in, MEMCATEGORY_GENERAL);
-		}
-
-		OGRE_FREE(zstream, MEMCATEGORY_GENERAL);
-
+		float *out = mLodManager.readGeometryData(stream,lodLevel);
 		stream.readChunkEnd(TERRAIN_CHUNK_ID);
 
-		return out;		
+		return out;
 	}
 }
 

File Components/Terrain/src/OgreTerrainGroup.cpp

 	//---------------------------------------------------------------------
 	void TerrainGroup::loadTerrainImpl(TerrainSlot* slot, bool synchronous)
 	{
-		slot->load = true;
-		slot->synchronous = synchronous;
-		if (slot->isPrepared || slot->prepareInProgress)
-			return ;
-
-		// if not allocated
 		if (!slot->instance && 
 			(!slot->def.filename.empty() || slot->def.importData))
 		{
 			// Use shared pool of buffers
 			slot->instance->setGpuBufferAllocator(&mBufferAllocator);
 			slot->instance->setTextureAllocator(&mTextureAllocator);
-		}
-
-			slot->prepareInProgress = true;
 
 			LoadRequest req;
 			req.slot = slot;
 			Root::getSingleton().getWorkQueue()->addRequest(
 				mWorkQueueChannel, WORKQUEUE_LOAD_REQUEST, 
 				Any(req), 0, synchronous);
+
+		}
 	}
 	//---------------------------------------------------------------------
 	void TerrainGroup::increaseLodLevel(long x, long y, bool synchronous /* = false */)
 		TerrainSlot* slot = getTerrainSlot(x, y, false);
 		if (slot)
 		{
-			// terrain not prepared yet
-			if (!slot->isPrepared)
-				return ;
-
 			slot->instance->increaseLodLevel(slot->def.filename, synchronous);
-			slot->isLoaded = true;
 		}
 	}
 	void TerrainGroup::decreaseLodLevel(long x, long y)
 		if (slot)
 		{
 			slot->freeInstance();
-			slot->isPrepared = false;
-			slot->prepareInProgress = false;
-			slot->isLoaded = false;
-			LogManager::getSingleton().stream() << "unloaded terrain (" << x << "," << y << ")";
 		}
 
 
 			TerrainSlot* slot = lreq.slot;
 			Terrain* terrain = slot->instance;
 			if (terrain)
-			{
-				slot->isPrepared = true;
-				slot->prepareInProgress = false;
-
+			{
+				// image imported data
 				if (slot->def.filename.empty())
 				{
-					// image imported data
 					terrain->load();
 				}
-				else if (slot->load)
+				else
 				{
-					terrain->increaseLodLevel(slot->def.filename, slot->synchronous);
-					slot->isLoaded = true;
+					terrain->increaseLodLevel(slot->def.filename, true);
 				}
 
 				// do final load now we've prepared in the background

File Components/Terrain/src/OgreTerrainLodManager.cpp

 #include "OgreStreamSerialiser.h"
 #include "OgreRoot.h"
 #include "OgreTerrain.h"
+#include <zlib.h>
 
 namespace Ogre
 {
 		wq->removeResponseHandler(mWorkQueueChannel, this);
 	}
 
-    bool TerrainLodManager::canHandleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ)
-    {
-		if (req->getType() == WORKQUEUE_LOAD_DATA_REQUEST)
-		{
-			LoadRequest lreq = any_cast<LoadRequest>(req->getData());
-			// only deal with own requests
-			// we do this because if we delete a terrain we want any pending tasks to be discarded
-			if (lreq.terrain != terrain)
-				return false;
-		}
-
-		return RequestHandler::canHandleRequest(req, srcQ);
-    }
-
-	bool TerrainLodManager::canHandleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ)
-	{
-		if (res->getRequest()->getType() == WORKQUEUE_LOAD_DATA_REQUEST)
-		{
-			LoadRequest lreq = any_cast<LoadRequest>(res->getRequest()->getData());
-			// only deal with own requests
-			// we do this because if we delete a terrain we want any pending tasks to be discarded
-			if (lreq.terrain != terrain)
-				return false;
-		}
-
-		return true;
-	}
-
     WorkQueue::Response* TerrainLodManager::handleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ)
 	{
 		LoadRequest lreq = any_cast<LoadRequest>(req->getData());
 	}
 
     // data are reorganized from lowest lod level(mNumLodLevels-1) to highest(0)
-	float* TerrainLodManager::separateData(float* data, uint16 batchSize, uint16 numLodLevels )
+	float* TerrainLodManager::separateData(float* data)
 	{
-		float* ret = OGRE_ALLOC_T(float, batchSize*batchSize, MEMCATEGORY_GENERAL);
-
 		unsigned int ptr = 0;
 		unsigned int inc, prev;
+		uint16 numLodLevels = terrain->getNumLodLevels();
+		uint16 size = terrain->getSize();
+
+		float* ret = OGRE_ALLOC_T(float, size*size, MEMCATEGORY_GENERAL);
+
 		for (int lvl = numLodLevels - 1; lvl >= 0; lvl--)
 		{
 			inc = 1 << lvl;
 			prev = 1 << (lvl + 1);
 
-			for (uint16 y = 0; y < batchSize; y += inc)
+			for (uint16 y = 0; y < size; y += inc)
 			{
-				for (uint16 x = 0; x < batchSize-1; x += inc)
+				for (uint16 x = 0; x < size-1; x += inc)
 				{
 					if ((lvl == numLodLevels - 1) || ((x % prev != 0) || (y % prev != 0)))
-						ret[ptr++] = *(data + y * batchSize + x);
+						ret[ptr++] = *(data + y * size + x);
 				}
 				if ((lvl == numLodLevels -1) || (y % prev) != 0)
-				ret[ptr++] = *(data + y * batchSize + batchSize - 1);
+					ret[ptr++] = *(data + y * size + size - 1);
 
-				if (y+inc > batchSize)
+				if (y+inc > size)
 					break;
 			}
 		}
 
 		return ret;
 	}
+	//---------------------------------------------------------------------
+	void TerrainLodManager::increaseLodLevel(const String& filename, bool synchronous /* = false */)
+	{
+		if ( mHighestLodLoaded == 0 || mTargetLodLevel == 0)
+			return ;
+
+		if (mTargetLodLevel == -1)
+		{
+			if (mHighestLodLoaded == -1)
+				mTargetLodLevel = terrain->getNumLodLevels() - 1;
+			else
+				mTargetLodLevel = mHighestLodLoaded - 1;
+		}
+		else
+			mTargetLodLevel--;
+
+		// dont load if lod already loaded
+		if (mHighestLodLoaded != -1 && mTargetLodLevel >= mHighestLodLoaded)
+		{
+			mTargetLodLevel = mHighestLodLoaded;
+			return ;
+		}
+
+		if (!mIncreaseLodLevelInProgress)
+		{
+			mIncreaseLodLevelInProgress = true;
+
+			LoadRequest req;
+			req.lodLevel = mTargetLodLevel;
+			req.filename = filename;
+			req.synchronous = synchronous;
+			req.readDone = false;
+
+			if (mHighestLodPrepared != -1
+					&& mTargetLodLevel >= mHighestLodPrepared)
+				req.readDone = true;
+
+			Root::getSingleton().getWorkQueue()->addRequest(
+				mWorkQueueChannel, WORKQUEUE_LOAD_DATA_REQUEST,
+				Any(req), 0, synchronous);
+		}
+	}
+
+	void* OgreTerrainZalloc(void* opaque, unsigned int items, unsigned int size)
+	{
+		return OGRE_MALLOC(items * size, MEMCATEGORY_GENERAL);
+	}
+
+	void OgreTerrainZfree(void* opaque, void* address)
+	{
+		OGRE_FREE(address, MEMCATEGORY_GENERAL);
+	}
+
+	// save each LOD level separately compressed so seek is possible
+	void TerrainLodManager::writeGeometryData(float* data, StreamSerialiser& stream)
+	{
+		uint16 numLodLevels = terrain->getNumLodLevels();
+
+		z_stream* zstream = OGRE_ALLOC_T(z_stream, 1, MEMCATEGORY_GENERAL);
+		zstream->zalloc = OgreTerrainZalloc;
+		zstream->zfree = OgreTerrainZfree;
+
+		int ret;
+		char out[OGRE_TERRAIN_DEFLATE_TMP_SIZE];
+
+		float* sep = separateData(data);
+
+		uint32 offset = 0;
+		uint32 size;
+		uint32 prevSize = 0;
+		uint32 diff;
+		for (int i = numLodLevels - 1; i >=0; i--)
+		{
+			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;
+
+			int flush = Z_NO_FLUSH;
+			uint done = 0;
+
+			stream.writeChunkBegin(Terrain::TERRAINHEIGHTDATA_CHUNK_ID, Terrain::TERRAINHEIGHTDATA_CHUNK_VERSION);
+			do
+			{
+				zstream->next_in = ((Bytef*)(sep + offset)) + done;
+
+				done += OGRE_TERRAIN_DEFLATE_TMP_SIZE;
+				if (done >= diff*sizeof(float))
+				{
+					flush = Z_FINISH;
+					zstream->avail_in = OGRE_TERRAIN_DEFLATE_TMP_SIZE - (done - diff * sizeof(float));
+				}
+				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
+					size_t compressed = OGRE_TERRAIN_DEFLATE_TMP_SIZE - zstream->avail_out;
+					stream.write(out, compressed);
+				} while (zstream->avail_out == 0);
+			} while (flush != Z_FINISH);
+			stream.writeChunkEnd(Terrain::TERRAINHEIGHTDATA_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
+
+			deflateEnd(zstream);
+
+			offset += diff;
+		}
+
+		OGRE_FREE(sep, MEMCATEGORY_GENERAL);
+		OGRE_FREE(zstream, MEMCATEGORY_GENERAL);
+	}
+
+	float* TerrainLodManager::readGeometryData(StreamSerialiser& stream, uint lodLevel)
+	{
+		uint16 numLodLevels = terrain->getNumLodLevels();
+
+		z_stream* zstream = OGRE_ALLOC_T(z_stream, 1, MEMCATEGORY_GENERAL);
+		zstream->zalloc = OgreTerrainZalloc;
+		zstream->zfree = OgreTerrainZfree;
+
+		uint32 size = terrain->getResolutionAtLod(lodLevel);
+		uint32 prevSize = 0;
+		if (lodLevel != numLodLevels-1)
+		prevSize = terrain->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--)
+		{
+			stream.readChunkBegin(Terrain::TERRAINHEIGHTDATA_CHUNK_ID, Terrain::TERRAINHEIGHTDATA_CHUNK_VERSION);
+
+			if (i != lvlCalc && i != lvlCalc-numLodLevels)
+			{
+				stream.readChunkEnd(Terrain::TERRAINHEIGHTDATA_CHUNK_ID);
+				continue;
+			}
+
+			// read
+			const StreamSerialiser::Chunk *c = stream.getCurrentChunk();
+			float* in = OGRE_ALLOC_T(float, c->length, MEMCATEGORY_GENERAL);
+
+			stream.read((char*)in, c->length);
+
+			zstream->avail_in = c->length;
+			zstream->next_in = (Bytef*)in;
+
+			stream.readChunkEnd(Terrain::TERRAINHEIGHTDATA_CHUNK_ID);
+
+			// uncompress
+			if (inflateInit(zstream) != Z_OK)
+			{
+				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);
+					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;
+					}
+				}
+			}
+
+			inflateEnd(zstream);
+
+			OGRE_FREE(in, MEMCATEGORY_GENERAL);
+		}
+		OGRE_FREE(zstream, MEMCATEGORY_GENERAL);
+
+		return out;
+	}
+	bool TerrainLodManager::fillLodData(uint lodLevel, float* inData, float* heightData, float* deltaData)
+	{
+		unsigned int ptr = 0;
+		unsigned int inc = 1 << lodLevel;
+		unsigned int prev = 1 << (lodLevel + 1);
+		uint16 numLodLevels = terrain->getNumLodLevels();
+		uint16 size = terrain->getSize();
+
+		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++];
+			}
+			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++];
+
+			if (y+inc > size)
+				break;
+		}
+
+		mHighestLodPrepared = lodLevel;
+
+		return true;
+	}
 }

File Samples/TerrainPaging/include/TerrainPaging.h

         if (!caps->hasCapability(RSC_VERTEX_PROGRAM) || !caps->hasCapability(RSC_FRAGMENT_PROGRAM))
         {
 			OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your graphics card does not support vertex or fragment shaders, "
-						"so you cannot run this sample. Sorry!", "Sample_TerrainPaging::testCapabilities");
+                        "so you cannot run this sample. Sorry!", "Sample_TerrainPaging::testCapabilities");
         }
 	}