1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6 
7 Copyright (c) 2000-2013 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 #include "OgreGrid3DPageStrategy.h"
29 
30 #include "OgreStreamSerialiser.h"
31 #include "OgreException.h"
32 #include "OgreCamera.h"
33 #include "OgrePagedWorldSection.h"
34 #include "OgrePage.h"
35 #include "OgreSceneNode.h"
36 #include "OgreSceneManager.h"
37 #include "OgreMaterialManager.h"
38 #include "OgreManualObject.h"
39 #include "OgrePageManager.h"
40 
41 namespace Ogre
42 {
43 	//---------------------------------------------------------------------
44 	const uint32 Grid3DPageStrategyData::CHUNK_ID = StreamSerialiser::makeIdentifier("G3DD");
45 	const uint16 Grid3DPageStrategyData::CHUNK_VERSION = 1;
46 	//---------------------------------------------------------------------
Grid3DPageStrategyData()47 	Grid3DPageStrategyData::Grid3DPageStrategyData()
48 		: PageStrategyData()
49 		, mWorldOrigin(Vector3::ZERO)
50 		, mOrigin(Vector3::ZERO)
51 		, mCellSize(1000,1000,1000)
52 		, mLoadRadius(2000)
53 		, mHoldRadius(3000)
54 		, mMinCellX(-512)
55 		, mMinCellY(-512)
56 		, mMinCellZ(-512)
57 		, mMaxCellX(511)
58 		, mMaxCellY(511)
59 		, mMaxCellZ(511)
60 	{
61 	}
62 	//---------------------------------------------------------------------
setCellRange(int32 minX,int32 minY,int32 minZ,int32 maxX,int32 maxY,int32 maxZ)63 	void Grid3DPageStrategyData::setCellRange(int32 minX, int32 minY, int32 minZ, int32 maxX, int32 maxY, int32 maxZ)
64 	{
65 		mMinCellX = minX;
66 		mMinCellY = minY;
67 		mMinCellZ = minZ;
68 		mMaxCellX = maxX;
69 		mMaxCellY = maxY;
70 		mMaxCellZ = maxZ;
71 	}
72 	//---------------------------------------------------------------------
setCellRangeMinX(int32 minX)73 	void Grid3DPageStrategyData::setCellRangeMinX(int32 minX)
74 	{
75 		mMinCellX = minX;
76 	}
77 	//---------------------------------------------------------------------
setCellRangeMinY(int32 minY)78 	void Grid3DPageStrategyData::setCellRangeMinY(int32 minY)
79 	{
80 		mMinCellY = minY;
81 	}
82 	//---------------------------------------------------------------------
setCellRangeMinZ(int32 minZ)83 	void Grid3DPageStrategyData::setCellRangeMinZ(int32 minZ)
84 	{
85 		mMinCellZ = minZ;
86 	}
87 	//---------------------------------------------------------------------
setCellRangeMaxX(int32 maxX)88 	void Grid3DPageStrategyData::setCellRangeMaxX(int32 maxX)
89 	{
90 		mMaxCellX = maxX;
91 	}
92 	//---------------------------------------------------------------------
setCellRangeMaxY(int32 maxY)93 	void Grid3DPageStrategyData::setCellRangeMaxY(int32 maxY)
94 	{
95 		mMaxCellY = maxY;
96 	}
97 	//---------------------------------------------------------------------
setCellRangeMaxZ(int32 maxZ)98 	void Grid3DPageStrategyData::setCellRangeMaxZ(int32 maxZ)
99 	{
100 		mMaxCellZ = maxZ;
101 	}
102 	//---------------------------------------------------------------------
~Grid3DPageStrategyData()103 	Grid3DPageStrategyData::~Grid3DPageStrategyData()
104 	{
105 	}
106 	//---------------------------------------------------------------------
setOrigin(const Vector3 & origin)107 	void Grid3DPageStrategyData::setOrigin(const Vector3& origin)
108 	{
109 		mWorldOrigin = origin;
110 	}
111 	//---------------------------------------------------------------------
determineGridLocation(const Vector3 & pos,int32 * x,int32 * y,int32 * z)112 	void Grid3DPageStrategyData::determineGridLocation(const Vector3& pos, int32 *x, int32 *y, int32 *z)
113 	{
114 		Vector3 relPos = pos - mOrigin + mCellSize * 0.5f;
115 
116 		*x = static_cast<int32>(floor(relPos.x / mCellSize.x));
117 		*y = static_cast<int32>(floor(relPos.y / mCellSize.y));
118 		*z = static_cast<int32>(floor(relPos.z / mCellSize.z));
119 	}
120 	//---------------------------------------------------------------------
getBottomLeftGridSpace(int32 x,int32 y,int32 z,Vector3 & bl)121 	void Grid3DPageStrategyData::getBottomLeftGridSpace(int32 x, int32 y, int32 z, Vector3& bl)
122 	{
123 		bl.x = mOrigin.x + (x-0.5f) * mCellSize.x;
124 		bl.y = mOrigin.y + (y-0.5f) * mCellSize.y;
125 		bl.z = mOrigin.z + (z-0.5f) * mCellSize.z;
126 	}
127 	//---------------------------------------------------------------------
getMidPointGridSpace(int32 x,int32 y,int32 z,Vector3 & mid)128 	void Grid3DPageStrategyData::getMidPointGridSpace(int32 x, int32 y, int32 z, Vector3& mid)
129 	{
130 		mid.x = mOrigin.x + float(x) * mCellSize.x;
131 		mid.y = mOrigin.y + float(y) * mCellSize.y;
132 		mid.z = mOrigin.z + float(z) * mCellSize.z;
133 	}
134 	//---------------------------------------------------------------------
getCornersGridSpace(int32 x,int32 y,int32 z,Vector3 * pEightPoints)135 	void Grid3DPageStrategyData::getCornersGridSpace(int32 x, int32 y, int32 z, Vector3* pEightPoints)
136 	{
137 		getBottomLeftGridSpace(x, y, z, pEightPoints[0]);
138 		pEightPoints[1] = pEightPoints[0] + Vector3(mCellSize.x, 0,           0);
139 		pEightPoints[2] = pEightPoints[0] + Vector3(mCellSize.x, mCellSize.y, 0);
140 		pEightPoints[3] = pEightPoints[0] + Vector3(0,           mCellSize.y, 0);
141 		pEightPoints[4] = pEightPoints[0] + Vector3(0, 0, mCellSize.z);
142 		pEightPoints[5] = pEightPoints[1] + Vector3(0, 0, mCellSize.z);
143 		pEightPoints[6] = pEightPoints[2] + Vector3(0, 0, mCellSize.z);
144 		pEightPoints[7] = pEightPoints[3] + Vector3(0, 0, mCellSize.z);
145 	}
146 	//---------------------------------------------------------------------
setCellSize(const Vector3 & sz)147 	void Grid3DPageStrategyData::setCellSize(const Vector3& sz)
148 	{
149 		mCellSize = sz;
150 	}
151 	//---------------------------------------------------------------------
152 	//---------------------------------------------------------------------
setLoadRadius(Real sz)153 	void Grid3DPageStrategyData::setLoadRadius(Real sz)
154 	{
155 		mLoadRadius = sz;
156 	}
157 	//---------------------------------------------------------------------
setHoldRadius(Real sz)158 	void Grid3DPageStrategyData::setHoldRadius(Real sz)
159 	{
160 		mHoldRadius = sz;
161 	}
162 	//---------------------------------------------------------------------
calculatePageID(int32 x,int32 y,int32 z)163 	PageID Grid3DPageStrategyData::calculatePageID(int32 x, int32 y, int32 z)
164 	{
165         // Go into positive range (simpler on decode)
166         x -= mMinCellX;
167         y -= mMinCellY;
168         z -= mMinCellZ;
169         // Push index bits into place
170 		uint32 key = z & 1023;
171         key = (key<<10) | (y&1023);
172         key = (key<<10) | (x&1023);
173 		return (PageID)key;
174 	}
175 	//---------------------------------------------------------------------
calculateCell(PageID inPageID,int32 * x,int32 * y,int32 * z)176 	void Grid3DPageStrategyData::calculateCell(PageID inPageID, int32 *x, int32 *y, int32* z)
177 	{
178 		// Pop bits from page index:
179         int32 ox = inPageID & 1023; inPageID >>= 10;
180         int32 oy = inPageID & 1023; inPageID >>= 10;
181         int32 oz = inPageID & 1023;
182         //// Hand made sign extension from 10bits to 32:
183         //NOT NEEDED ANYMORE because this is crafted positive...
184         //if( ox > 511 ) ox = 1024 - ox;
185         //if( oy > 511 ) oy = 1024 - oy;
186         //if( oz > 511 ) oz = 1024 - oz;
187         // Back in the [min..max] range:
188 		*x = ox + mMinCellX;
189 		*y = oy + mMinCellY;
190 		*z = oz + mMinCellZ;
191 	}
192 	//---------------------------------------------------------------------
load(StreamSerialiser & ser)193 	bool Grid3DPageStrategyData::load(StreamSerialiser& ser)
194 	{
195 		if (!ser.readChunkBegin(CHUNK_ID, CHUNK_VERSION, "Grid3DPageStrategyData"))
196 			return false;
197 
198 		ser.read(&mOrigin);
199 		ser.read(&mCellSize);
200 		ser.read(&mLoadRadius);
201 		ser.read(&mHoldRadius);
202 		ser.read(&mMinCellX);
203 		ser.read(&mMaxCellX);
204 		ser.read(&mMinCellY);
205 		ser.read(&mMaxCellY);
206 		ser.read(&mMinCellZ);
207 		ser.read(&mMaxCellZ);
208 
209 		ser.readChunkEnd(CHUNK_ID);
210 
211 		return true;
212 	}
213 	//---------------------------------------------------------------------
save(StreamSerialiser & ser)214 	void Grid3DPageStrategyData::save(StreamSerialiser& ser)
215 	{
216 		ser.writeChunkBegin(CHUNK_ID, CHUNK_VERSION);
217 
218 		ser.write(&mWorldOrigin);
219 		ser.write(&mCellSize);
220 		ser.write(&mLoadRadius);
221 		ser.write(&mHoldRadius);
222 		ser.write(&mMinCellX);
223 		ser.write(&mMaxCellX);
224 		ser.write(&mMinCellY);
225 		ser.write(&mMaxCellY);
226 		ser.write(&mMinCellZ);
227 		ser.write(&mMaxCellZ);
228 
229 		ser.writeChunkEnd(CHUNK_ID);
230 	}
231 	//---------------------------------------------------------------------
232 	//---------------------------------------------------------------------
Grid3DPageStrategy(PageManager * manager)233 	Grid3DPageStrategy::Grid3DPageStrategy(PageManager* manager)
234 		: PageStrategy("Grid3D", manager)
235 	{
236 
237 	}
238 	//---------------------------------------------------------------------
~Grid3DPageStrategy()239 	Grid3DPageStrategy::~Grid3DPageStrategy()
240 	{
241 
242 	}
243 	//---------------------------------------------------------------------
notifyCamera(Camera * cam,PagedWorldSection * section)244 	void Grid3DPageStrategy::notifyCamera(Camera* cam, PagedWorldSection* section)
245 	{
246 		Grid3DPageStrategyData* stratData = static_cast<Grid3DPageStrategyData*>(section->getStrategyData());
247 
248 		const Vector3& pos = cam->getDerivedPosition();
249 		int32 x, y, z;
250 		stratData->determineGridLocation(pos, &x, &y, &z);
251 
252 		Real loadRadius = stratData->getLoadRadius();
253 		Real holdRadius = stratData->getHoldRadius();
254 		// scan the whole Hold range
255         Real fxmin = (Real)x - holdRadius/stratData->getCellSize().x;
256 		Real fxmax = (Real)x + holdRadius/stratData->getCellSize().x;
257 		Real fymin = (Real)y - holdRadius/stratData->getCellSize().y;
258 		Real fymax = (Real)y + holdRadius/stratData->getCellSize().y;
259 		Real fzmin = (Real)z - holdRadius/stratData->getCellSize().z;
260 		Real fzmax = (Real)z + holdRadius/stratData->getCellSize().z;
261 
262 		int32 xmin = stratData->getCellRangeMinX();
263 		int32 xmax = stratData->getCellRangeMaxX();
264 		int32 ymin = stratData->getCellRangeMinY();
265 		int32 ymax = stratData->getCellRangeMaxY();
266 		int32 zmin = stratData->getCellRangeMinZ();
267 		int32 zmax = stratData->getCellRangeMaxZ();
268 
269 		// Round UP max, round DOWN min
270 		xmin = fxmin < xmin ? xmin : (int32)floor(fxmin);
271 		xmax = fxmax > xmax ? xmax : (int32)ceil(fxmax);
272 		ymin = fymin < ymin ? ymin : (int32)floor(fymin);
273 		ymax = fymax > ymax ? ymax : (int32)ceil(fymax);
274 		zmin = fzmin < zmin ? zmin : (int32)floor(fzmin);
275 		zmax = fzmax > zmax ? zmax : (int32)ceil(fzmax);
276 		// the inner, active load range
277 		fxmin = (Real)x - loadRadius/stratData->getCellSize().x;
278 		fxmax = (Real)x + loadRadius/stratData->getCellSize().x;
279 		fymin = (Real)y - loadRadius/stratData->getCellSize().y;
280 		fymax = (Real)y + loadRadius/stratData->getCellSize().y;
281 		fzmin = (Real)z - loadRadius/stratData->getCellSize().z;
282 		fzmax = (Real)z + loadRadius/stratData->getCellSize().z;
283 		// Round UP max, round DOWN min
284 		int32 loadxmin = fxmin < xmin ? xmin : (int32)floor(fxmin);
285 		int32 loadxmax = fxmax > xmax ? xmax : (int32)ceil(fxmax);
286 		int32 loadymin = fymin < ymin ? ymin : (int32)floor(fymin);
287 		int32 loadymax = fymax > ymax ? ymax : (int32)ceil(fymax);
288 		int32 loadzmin = fzmin < zmin ? zmin : (int32)floor(fzmin);
289 		int32 loadzmax = fzmax > zmax ? zmax : (int32)ceil(fzmax);
290 
291 		for (int32 cz = zmin; cz <= zmax; ++cz)
292 		{
293 		    for (int32 cy = ymin; cy <= ymax; ++cy)
294 		    {
295 			    for (int32 cx = xmin; cx <= xmax; ++cx)
296 			    {
297 				    PageID pageID = stratData->calculatePageID(cx, cy, cz);
298 
299 				    if (cx >= loadxmin && cx <= loadxmax
300                      && cy >= loadymin && cy <= loadymax
301                      && cz >= loadzmin && cz <= loadzmax )
302 				    {
303                         Vector3 bl;
304                         stratData->getBottomLeftGridSpace(cx, cy, cz, bl);
305                         Ogre::AxisAlignedBox bbox(bl, bl+stratData->getCellSize());
306 
307                         if( cam->isVisible(bbox) )
308     					    section->loadPage(pageID);
309                         else
310 					        section->holdPage(pageID);
311 				    }
312 				    else
313 				    {
314 					    // in the outer 'hold' range, keep it but don't actively load
315 					    section->holdPage(pageID);
316 				    }
317 				    // other pages will by inference be marked for unloading
318 			    }
319 		    }
320         }
321 	}
322 	//---------------------------------------------------------------------
createData()323 	PageStrategyData* Grid3DPageStrategy::createData()
324 	{
325 		return OGRE_NEW Grid3DPageStrategyData();
326 	}
327 	//---------------------------------------------------------------------
destroyData(PageStrategyData * d)328 	void Grid3DPageStrategy::destroyData(PageStrategyData* d)
329 	{
330 		OGRE_DELETE d;
331 	}
332 	//---------------------------------------------------------------------
updateDebugDisplay(Page * p,SceneNode * sn)333 	void Grid3DPageStrategy::updateDebugDisplay(Page* p, SceneNode* sn)
334 	{
335 		uint8 dbglvl = mManager->getDebugDisplayLevel();
336 		if (dbglvl)
337 		{
338 			// we could try to avoid updating the geometry every time here, but this
339 			// wouldn't easily deal with paging parameter changes. There shouldn't
340 			// be that many pages anyway, and this is debug after all, so update every time
341 			int32 x, y, z;
342 			Grid3DPageStrategyData* stratData = static_cast<Grid3DPageStrategyData*>(
343 				p->getParentSection()->getStrategyData());
344 			stratData->calculateCell(p->getID(), &x, &y, &z);
345 
346 			Grid3DPageStrategyData* data = static_cast<Grid3DPageStrategyData*>(p->getParentSection()->getStrategyData());
347 
348 			// Determine our centre point, we'll anchor here
349 			Vector3 midPoint;
350 			data->getMidPointGridSpace(x, y, z, midPoint);
351 			sn->setPosition(midPoint);
352 
353             //--- Get coordinates, relative to midPoint :
354 			Vector3 corners[8];
355             Vector3 hSize = 0.500f * stratData->getCellSize();
356 			for (int i = 0; i < 8; ++i)
357             {
358                 corners[i].x = i&1 ? hSize.x : -hSize.x;
359                 corners[i].z = i&2 ? hSize.y : -hSize.y;
360                 corners[i].y = i&4 ? hSize.z : -hSize.z;
361             }
362 
363             //--- Get a material
364 			String matName = "Ogre/G3D/Debug";
365 			MaterialPtr mat = MaterialManager::getSingleton().getByName(matName);
366 			if (mat.isNull())
367 			{
368 				mat = MaterialManager::getSingleton().create(matName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
369 				Pass* pass = mat->getTechnique(0)->getPass(0);
370 				pass->setLightingEnabled(false);
371 				pass->setVertexColourTracking(TVC_AMBIENT);
372 				pass->setDepthWriteEnabled(false);
373 				mat->load();
374 			}
375 
376 			ManualObject* mo = 0;
377             bool update = sn->numAttachedObjects() > 0;
378 			if( update )
379 			{
380 				mo = static_cast<ManualObject*>(sn->getAttachedObject(0));
381 				mo->beginUpdate(0);
382 			}
383 			else
384 			{
385 				mo = p->getParentSection()->getSceneManager()->createManualObject();
386 				mo->begin(matName, RenderOperation::OT_LINE_STRIP);
387 			}
388 
389 			ColourValue vcol = ColourValue::Green;
390 			mo->position(corners[0]); mo->colour(vcol); // First Square...
391 			mo->position(corners[1]); mo->colour(vcol);
392 			mo->position(corners[3]); mo->colour(vcol);
393 			mo->position(corners[2]); mo->colour(vcol);
394 			mo->position(corners[0]); mo->colour(vcol);
395 			mo->position(corners[4]); mo->colour(vcol); // 0-4 link + second square and
396 			mo->position(corners[5]); mo->colour(vcol);
397 			mo->position(corners[7]); mo->colour(vcol);
398 			mo->position(corners[6]); mo->colour(vcol);
399 			mo->position(corners[4]); mo->colour(vcol);
400 			mo->position(corners[5]); mo->colour(vcol); // 5-1 link
401 			mo->position(corners[1]); mo->colour(vcol);
402 			mo->position(corners[3]); mo->colour(vcol); // 3-7 link
403 			mo->position(corners[7]); mo->colour(vcol);
404 			mo->position(corners[6]); mo->colour(vcol); // 6-2 link
405 			mo->position(corners[2]); mo->colour(vcol);
406 			mo->end();
407 
408 			if(!update)
409 				sn->attachObject(mo);
410 		}
411 	}
412 
413 	//---------------------------------------------------------------------
getPageID(const Vector3 & pos,PagedWorldSection * section)414 	PageID Grid3DPageStrategy::getPageID(const Vector3& pos, PagedWorldSection* section)
415 	{
416 		Grid3DPageStrategyData* stratData = static_cast<Grid3DPageStrategyData*>(section->getStrategyData());
417 
418 		int32 x, y, z;
419 		stratData->determineGridLocation(pos, &x, &y, &z);
420 		return stratData->calculatePageID(x, y, z);
421 	}
422 }
423