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