Patch 2793067: fix trunk with OGRE_THREAD_SUPPORT=1 on non-Windows platforms (don...
[ogre3d.git] / Components / Terrain / src / OgreTerrain.cpp
blob4e5825612feaf9e2e4a25e286553310b0631bba8
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/
7 Copyright (c) 2000-2009 Torus Knot Software Ltd
8 Also see acknowledgements in Readme.html
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
13 version.
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22 http://www.gnu.org/copyleft/lesser.txt.
24 You may alternatively use this source under the terms of a specific version of
25 the OGRE Unrestricted License provided you have obtained such a license from
26 Torus Knot Software Ltd.
27 -----------------------------------------------------------------------------
29 #include "OgreTerrain.h"
30 #include "OgreTerrainQuadTreeNode.h"
31 #include "OgreStreamSerialiser.h"
32 #include "OgreMath.h"
33 #include "OgreImage.h"
34 #include "OgrePixelFormat.h"
35 #include "OgreSceneManager.h"
36 #include "OgreSceneNode.h"
37 #include "OgreException.h"
38 #include "OgreBitwise.h"
39 #include "OgreStringConverter.h"
40 #include "OgreViewport.h"
41 #include "OgreLogManager.h"
43 namespace Ogre
45 //---------------------------------------------------------------------
46 const uint32 Terrain::TERRAIN_CHUNK_ID = StreamSerialiser::makeIdentifier("TERR");
47 const uint16 Terrain::TERRAIN_CHUNK_VERSION = 1;
48 // since 129^2 is the greatest power we can address in 16-bit index
49 const uint16 Terrain::TERRAIN_MAX_BATCH_SIZE = 129;
50 //---------------------------------------------------------------------
51 //---------------------------------------------------------------------
52 bool TerrainGlobalOptions::msUseTriangleStrips = true;
53 bool TerrainGlobalOptions::msUseLodMorph = true;
54 Real TerrainGlobalOptions::msSkirtSize = 10;
55 bool TerrainGlobalOptions::msGenerateVertexNormals = false;
56 bool TerrainGlobalOptions::msGenerateNormalMap = true;
57 bool TerrainGlobalOptions::msGenerateShadowMap = false;
58 Vector3 TerrainGlobalOptions::msShadowMapDir = Vector3(1, -1, 0).normalisedCopy();
59 bool TerrainGlobalOptions::msGenerateHorizonMap = false;
60 Radian TerrainGlobalOptions::msHorizonMapAzimuth = Radian(0);
61 Radian TerrainGlobalOptions::msHorizonMapZenith = Radian(0);
62 bool TerrainGlobalOptions::msCastsShadows = false;
63 Real TerrainGlobalOptions::msMaxPixelError = 3.0;
64 uint8 TerrainGlobalOptions::msRenderQueueGroup = RENDER_QUEUE_MAIN;
65 //---------------------------------------------------------------------
66 Terrain::Terrain(SceneManager* sm)
67 : mSceneMgr(sm)
68 , mHeightData(0)
69 , mDeltaData(0)
70 , mPos(Vector3::ZERO)
71 , mQuadTree(0)
72 , mNumLodLevels(0)
73 , mNumLodLevelsPerLeafNode(0)
74 , mTreeDepth(0)
76 mRootNode = sm->getRootSceneNode()->createChildSceneNode();
77 sm->addListener(this);
79 //---------------------------------------------------------------------
80 Terrain::~Terrain()
82 freeGPUResources();
83 freeCPUResources();
84 if (mSceneMgr)
86 mSceneMgr->destroySceneNode(mRootNode);
87 mSceneMgr->removeListener(this);
90 //---------------------------------------------------------------------
91 const AxisAlignedBox& Terrain::getAABB() const
93 if (!mQuadTree)
94 return AxisAlignedBox::BOX_NULL;
95 else
96 return mQuadTree->getAABB();
98 //---------------------------------------------------------------------
99 Real Terrain::getBoundingRadius() const
101 if (!mQuadTree)
102 return 0;
103 else
104 return mQuadTree->getBoundingRadius();
106 //---------------------------------------------------------------------
107 void Terrain::save(StreamSerialiser& stream)
109 stream.writeChunkBegin(TERRAIN_CHUNK_ID, TERRAIN_CHUNK_VERSION);
111 uint8 align = (uint8)mAlign;
112 stream.write(&align);
114 stream.write(&mSize);
115 stream.write(&mWorldSize);
116 uint16 splatDimCount;
117 if (mSplatTextureWorldSize.empty())
119 splatDimCount = 1;
120 Real dim = getSplatTextureWorldSize(0);
121 stream.write(&splatDimCount);
122 stream.write(&dim);
124 else
126 splatDimCount = static_cast<uint16>(mSplatTextureWorldSize.size());
127 stream.write(&splatDimCount);
128 stream.write(&mSplatTextureWorldSize[0], mSplatTextureWorldSize.size());
130 stream.write(&mMaxBatchSize);
131 stream.write(&mMinBatchSize);
132 stream.write(&mPos);
133 stream.write(mHeightData, mSize * mSize);
135 stream.writeChunkEnd(TERRAIN_CHUNK_ID);
137 //---------------------------------------------------------------------
138 bool Terrain::prepare(StreamSerialiser& stream)
140 freeCPUResources();
142 copyGlobalOptions();
144 if (!stream.readChunkBegin(TERRAIN_CHUNK_ID, TERRAIN_CHUNK_VERSION))
145 return false;
147 uint8 align;
148 stream.read(&align);
149 mAlign = (Alignment)align;
150 stream.read(&mWorldSize);
151 uint16 splatDimCount;
152 stream.read(&splatDimCount);
153 for (uint16 i = 0; i < splatDimCount; ++i)
155 Real dim;
156 stream.read(&dim);
157 setSplatTextureWorldSize(i, dim);
159 stream.read(&mMaxBatchSize);
160 stream.read(&mMinBatchSize);
161 stream.read(&mPos);
162 updateBaseScale();
163 determineLodLevels();
166 size_t numVertices = mSize * mSize;
167 mHeightData = OGRE_ALLOC_T(float, numVertices, MEMCATEGORY_GEOMETRY);
168 stream.read(mHeightData, numVertices);
170 stream.readChunkEnd(TERRAIN_CHUNK_ID);
172 mQuadTree = OGRE_NEW TerrainQuadTreeNode(this, 0, 0, 0, mSize, mNumLodLevels - 1, 0, 0);
173 mQuadTree->prepare();
175 mDeltaData = OGRE_ALLOC_T(float, numVertices, MEMCATEGORY_GEOMETRY);
176 // calculate entire terrain
177 Rect rect;
178 rect.top = 0; rect.bottom = mSize;
179 rect.left = 0; rect.right = mSize;
180 calculateHeightDeltas(rect);
182 distributeVertexData();
184 return true;
186 //---------------------------------------------------------------------
187 bool Terrain::prepare(const ImportData& importData)
189 freeCPUResources();
191 copyGlobalOptions();
193 // validate
194 if (!(Bitwise::isPO2(importData.terrainSize - 1) && Bitwise::isPO2(importData.minBatchSize - 1)
195 && Bitwise::isPO2(importData.maxBatchSize - 1)))
197 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
198 "terrainSise, minBatchSize and maxBatchSize must all be n^2 + 1",
199 "Terrain::prepare");
202 if (importData.minBatchSize > importData.maxBatchSize)
204 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
205 "minBatchSize must be less than or equal to maxBatchSize",
206 "Terrain::prepare");
209 if (importData.maxBatchSize > TERRAIN_MAX_BATCH_SIZE)
211 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
212 "maxBatchSize must be no larger than " +
213 StringConverter::toString(TERRAIN_MAX_BATCH_SIZE),
214 "Terrain::prepare");
217 mAlign = importData.terrainAlign;
218 mSize = importData.terrainSize;
219 mWorldSize = importData.worldSize;
220 for (uint16 i = 0; i < importData.splatTextureWorldSizeList.size(); ++i)
222 setSplatTextureWorldSize(i, importData.splatTextureWorldSizeList[i]);
224 mMaxBatchSize = importData.maxBatchSize;
225 mMinBatchSize = importData.minBatchSize;
226 mPos = importData.pos;
227 updateBaseScale();
228 determineLodLevels();
230 size_t numVertices = mSize * mSize;
232 mHeightData = OGRE_ALLOC_T(float, numVertices, MEMCATEGORY_GEOMETRY);
234 if (importData.inputFloat)
236 if (Math::RealEqual(importData.inputBias, 0.0) && Math::RealEqual(importData.inputScale, 1.0))
238 // straight copy
239 memcpy(mHeightData, importData.inputFloat, sizeof(float) * numVertices);
241 else
243 // scale & bias
244 float* src = importData.inputFloat;
245 float* dst = mHeightData;
246 for (size_t i = 0; i < numVertices; ++i)
247 *dst++ = (*src++ * importData.inputScale) + importData.inputBias;
250 else if (importData.inputImage)
252 Image* img = importData.inputImage;
254 if (img->getWidth() != mSize || img->getHeight() != mSize)
255 img->resize(mSize, mSize);
257 // convert image data to floats
258 // Do this on a row-by-row basis, because we describe the terrain in
259 // a bottom-up fashion (ie ascending world coords), while Image is top-down
260 unsigned char* pSrcBase = img->getData();
261 for (size_t i = 0; i < mSize; ++i)
263 size_t srcy = mSize - i - 1;
264 unsigned char* pSrc = pSrcBase + srcy * img->getRowSpan();
265 float* pDst = mHeightData + i * mSize;
266 PixelUtil::bulkPixelConversion(pSrc, img->getFormat(),
267 pDst, PF_FLOAT32_R, mSize);
270 if (!Math::RealEqual(importData.inputBias, 0.0) || !Math::RealEqual(importData.inputScale, 1.0))
272 float* pAdj = mHeightData;
273 for (size_t i = 0; i < numVertices; ++i)
275 *pAdj = (*pAdj * importData.inputScale) + importData.inputBias;
276 ++pAdj;
281 else
283 // start with flat terrain
284 memset(mHeightData, 0, sizeof(float) * mSize * mSize);
287 mDeltaData = OGRE_ALLOC_T(float, numVertices, MEMCATEGORY_GEOMETRY);
290 mQuadTree = OGRE_NEW TerrainQuadTreeNode(this, 0, 0, 0, mSize, mNumLodLevels - 1, 0, 0);
291 mQuadTree->prepare();
293 // calculate entire terrain
294 Rect rect;
295 rect.top = 0; rect.bottom = mSize;
296 rect.left = 0; rect.right = mSize;
297 calculateHeightDeltas(rect);
299 distributeVertexData();
302 return true;
305 //---------------------------------------------------------------------
306 void Terrain::copyGlobalOptions()
308 mUseTriangleStrips = TerrainGlobalOptions::getUseTriangleStrips();
309 mUseLodMorph = TerrainGlobalOptions::getUseLodMorph();
310 mSkirtSize = TerrainGlobalOptions::getSkirtSize();
311 mGenerateVertexNormals = TerrainGlobalOptions::getGenerateVertexNormals();
312 mGenerateNormalMap = TerrainGlobalOptions::getGenerateNormalMap();
313 mGenerateShadowMap = TerrainGlobalOptions::getGenerateShadowMap();
314 mGenerateHorizonMap = TerrainGlobalOptions::getGenerateHorizonMap();
315 mRenderQueueGroup = TerrainGlobalOptions::getRenderQueueGroup();
318 //---------------------------------------------------------------------
319 void Terrain::determineLodLevels()
321 /* On a leaf-node basis, LOD can vary from maxBatch to minBatch in
322 number of vertices. After that, nodes will be gathered into parent
323 nodes with the same number of vertices, but they are combined with
324 3 of their siblings. In practice, the number of LOD levels overall
326 LODlevels = log2(size - 1) - log2(minBatch - 1) + 1
327 TreeDepth = log2((size - 1) / (maxBatch - 1)) + 1
329 .. it's just that at the max LOD, the terrain is divided into
330 (size - 1) / (maxBatch - 1) tiles each of maxBatch vertices, and
331 at the lowest LOD the terrain is made up of one single tile of
332 minBatch vertices.
334 Example: size = 257, minBatch = 17, maxBatch = 33
336 LODlevels = log2(257 - 1) - log2(17 - 1) + 1 = 8 - 4 + 1 = 5
337 TreeDepth = log2((size - 1) / (maxBatch - 1)) + 1 = 4
339 LOD list - this assumes everything changes at once, which rarely happens of course
340 in fact except where groupings must occur, tiles can change independently
341 LOD 0: 257 vertices, 8 x 33 vertex tiles (tree depth 3)
342 LOD 1: 129 vertices, 8 x 17 vertex tiles (tree depth 3)
343 LOD 2: 65 vertices, 4 x 17 vertex tiles (tree depth 2)
344 LOD 3: 33 vertices, 2 x 17 vertex tiles (tree depth 1)
345 LOD 4: 17 vertices, 1 x 17 vertex tiles (tree depth 0)
347 Notice how we only have 2 sizes of index buffer to be concerned about,
348 17 vertices (per side) or 33. This makes buffer re-use much easier while
349 still giving the full range of LODs.
351 mNumLodLevelsPerLeafNode = Math::Log2(mMaxBatchSize - 1) - Math::Log2(mMinBatchSize - 1) + 1;
352 mNumLodLevels = Math::Log2(mSize - 1) - Math::Log2(mMinBatchSize - 1) + 1;
353 //mTreeDepth = Math::Log2(mMaxBatchSize - 1) - Math::Log2(mMinBatchSize - 1) + 2;
354 mTreeDepth = mNumLodLevels - mNumLodLevelsPerLeafNode + 1;
356 LogManager::getSingleton().stream() << "Terrain created; size=" << mSize
357 << " minBatch=" << mMinBatchSize << " maxBatch=" << mMaxBatchSize
358 << " treeDepth=" << mTreeDepth << " lodLevels=" << mNumLodLevels
359 << " leafLods=" << mNumLodLevelsPerLeafNode;
361 //---------------------------------------------------------------------
362 void Terrain::distributeVertexData()
364 /* Now we need to figure out how to distribute vertex data. We want to
365 use 16-bit indexes for compatibility, which means that the maximum patch
366 size that we can address (even sparsely for lower LODs) is 129x129
367 (the next one up, 257x257 is too big).
369 So we need to split the vertex data into chunks of 129. The number of
370 primary tiles this creates also indicates the point above which in
371 the node tree that we can no longer merge tiles at lower LODs without
372 using different vertex data. For example, using the 257x257 input example
373 above, the vertex data would have to be split in 2 (in each dimension)
374 in order to fit within the 129x129 range. This data could be shared by
375 all tree depths from 1 onwards, it's just that LODs 3-1 would sample
376 the 129x129 data sparsely. LOD 0 would sample all of the vertices.
378 LOD 4 however, the lowest LOD, could not work with the same vertex data
379 because it needs to cover the entire terrain. There are 2 choices here:
380 create another set of vertex data at 17x17 which is only used by LOD 4,
381 or make LOD 4 occur at tree depth 1 instead (ie still split up, and
382 rendered as 2x9 along each edge instead.
384 Since rendering very small batches is not desirable, and the vertex counts
385 are inherently not going to be large, creating a separate vertex set is
386 preferable. This will also be more efficient on the vertex cache with
387 distant terrains.
389 We probably need a larger example, because in this case only 1 level (LOD 0)
390 needs to use this separate vertex data. Higher detail terrains will need
391 it for multiple levels, here's a 2049x2049 example with 65 / 33 batch settings:
393 LODlevels = log2(2049 - 1) - log2(33 - 1) + 1 = 11 - 5 + 1 = 7
394 TreeDepth = log2((2049 - 1) / (65 - 1)) + 1 = 6
395 Number of vertex data splits at most detailed level:
396 (size - 1) / (TERRAIN_MAX_BATCH_SIZE - 1) = 2048 / 128 = 16
398 LOD 0: 2049 vertices, 32 x 65 vertex tiles (tree depth 5) vdata 0-15 [129x16]
399 LOD 1: 1025 vertices, 32 x 33 vertex tiles (tree depth 5) vdata 0-15 [129x16]
400 LOD 2: 513 vertices, 16 x 33 vertex tiles (tree depth 4) vdata 0-15 [129x16]
401 LOD 3: 257 vertices, 8 x 33 vertex tiles (tree depth 3) vdata 16-17 [129x2]
402 LOD 4: 129 vertices, 4 x 33 vertex tiles (tree depth 2) vdata 16-17 [129x2]
403 LOD 5: 65 vertices, 2 x 33 vertex tiles (tree depth 1) vdata 16-17 [129x2]
404 LOD 6: 33 vertices, 1 x 33 vertex tiles (tree depth 0) vdata 18 [33]
406 All the vertex counts are to be squared, they are just along one edge.
407 So as you can see, we need to have 3 levels of vertex data to satisy this
408 (admittedly quite extreme) case, and a total of 19 sets of vertex data.
409 The full detail geometry, which is 16(x16) sets of 129(x129), used by
410 LODs 0-2. LOD 3 can't use this set because it needs to group across them,
411 because it has only 8 tiles, so we make another set which satisfies this
412 at a maximum of 129 vertices per vertex data section. In this case LOD
413 3 needs 257(x257) total vertices so we still split into 2(x2) sets of 129.
414 This set is good up to and including LOD 5, but LOD 6 needs a single
415 contiguous set of vertices, so we make a 33x33 vertex set for it.
417 In terms of vertex data stored, this means that while our primary data is:
418 2049^2 = 4198401 vertices
419 our final stored vertex data is
420 (16 * 129)^2 + (2 * 129)^2 + 33^2 = 4327749 vertices
422 That equals a 3% premium, but it's both necessary and worth it for the
423 reduction in batch count resulting from the grouping. In addition, at
424 LODs 3 and 6 (or rather tree depth 3 and 0) there is the opportunity
425 to free up the vertex data used by more detailed LODs, which is
426 important when dealing with large terrains. For example, if we
427 freed the (GPU) vertex data for LOD 0-2 in the medium distance,
428 we would save 98% of the memory overhead for this terrain.
432 LogManager& logMgr = LogManager::getSingleton();
433 logMgr.stream(LML_TRIVIAL) << "Terrain::distributeVertexData processing source "
434 "terrain size of " << mSize;
436 uint16 depth = mTreeDepth;
437 uint16 prevdepth = depth;
438 uint16 currresolution = mSize;
439 uint16 bakedresolution = mSize;
440 uint16 targetSplits = (bakedresolution - 1) / (TERRAIN_MAX_BATCH_SIZE - 1);
441 while(depth-- && targetSplits)
443 uint splits = 1 << depth;
444 if (splits == targetSplits)
446 logMgr.stream(LML_TRIVIAL) << " Assigning vertex data, resolution="
447 << bakedresolution << " startDepth=" << depth << " endDepth=" << prevdepth
448 << " splits=" << splits;
449 // vertex data goes at this level, at bakedresolution
450 // applies to all lower levels (except those with a closer vertex data)
451 mQuadTree->assignVertexData(depth, prevdepth, bakedresolution);
453 // next set to look for
454 bakedresolution = ((currresolution - 1) >> 1) + 1;
455 targetSplits = (bakedresolution - 1) / (TERRAIN_MAX_BATCH_SIZE - 1);
456 prevdepth = depth;
460 currresolution = ((currresolution - 1) >> 1) + 1;
465 // Always assign vertex data to the top of the tree
466 if (prevdepth > 0)
468 mQuadTree->assignVertexData(0, 1, getMinBatchSize());
469 logMgr.stream(LML_TRIVIAL) << " Assigning vertex data, resolution: "
470 << getMinBatchSize() << " startDepth: 0 endDepth: 1 splits: 1";
474 logMgr.stream(LML_TRIVIAL) << "Terrain::distributeVertexData finished";
477 //---------------------------------------------------------------------
478 void Terrain::load()
480 if (mQuadTree)
481 mQuadTree->load();
483 //---------------------------------------------------------------------
484 void Terrain::unload()
486 if (mQuadTree)
487 mQuadTree->unload();
489 //---------------------------------------------------------------------
490 void Terrain::unprepare()
492 if (mQuadTree)
493 mQuadTree->unprepare();
495 //---------------------------------------------------------------------
496 float* Terrain::getHeightData()
498 return mHeightData;
500 //---------------------------------------------------------------------
501 float* Terrain::getHeightData(long x, long y)
503 assert (x >= 0 && x < mSize && y >= 0 && y < mSize);
504 return &mHeightData[y * mSize + x];
506 //---------------------------------------------------------------------
507 float Terrain::getHeight(long x, long y)
509 return *getHeightData(x, y);
511 //---------------------------------------------------------------------
512 const float* Terrain::getDeltaData()
514 return mDeltaData;
516 //---------------------------------------------------------------------
517 const float* Terrain::getDeltaData(long x, long y)
519 assert (x >= 0 && x < mSize && y >= 0 && y < mSize);
520 return &mDeltaData[y * mSize + x];
522 //---------------------------------------------------------------------
523 void Terrain::getPoint(long x, long y, Vector3* outpos)
525 getPointAlign(x, y, mAlign, outpos);
527 //---------------------------------------------------------------------
528 void Terrain::getPoint(long x, long y, float height, Vector3* outpos)
530 getPointAlign(x, y, height, mAlign, outpos);
532 //---------------------------------------------------------------------
533 void Terrain::getPointAlign(long x, long y, Alignment align, Vector3* outpos)
535 getPointAlign(x, y, *getHeightData(x, y), align, outpos);
537 //---------------------------------------------------------------------
538 void Terrain::getPointAlign(long x, long y, float height, Alignment align, Vector3* outpos)
540 switch(align)
542 case ALIGN_X_Z:
543 outpos->y = height;
544 outpos->x = x * mScale + mBase;
545 outpos->z = y * -mScale - mBase;
546 break;
547 case ALIGN_Y_Z:
548 outpos->x = height;
549 outpos->y = x * mScale + mBase;
550 outpos->z = y * -mScale - mBase;
551 break;
552 case ALIGN_X_Y:
553 outpos->z = height;
554 outpos->x = x * mScale + mBase;
555 outpos->y = y * mScale + mBase;
556 break;
560 //---------------------------------------------------------------------
561 void Terrain::getVector(const Vector3& inVec, Vector3* outVec)
563 getVectorAlign(inVec.x, inVec.y, inVec.z, mAlign, outVec);
565 //---------------------------------------------------------------------
566 void Terrain::getVector(Real x, Real y, Real z, Vector3* outVec)
568 getVectorAlign(x, y, z, mAlign, outVec);
570 //---------------------------------------------------------------------
571 void Terrain::getVectorAlign(const Vector3& inVec, Alignment align, Vector3* outVec)
573 getVectorAlign(inVec.x, inVec.y, inVec.z, align, outVec);
575 //---------------------------------------------------------------------
576 void Terrain::getVectorAlign(Real x, Real y, Real z, Alignment align, Vector3* outVec)
579 switch(align)
581 case ALIGN_X_Z:
582 outVec->y = z;
583 outVec->x = x;
584 outVec->z = -y;
585 break;
586 case ALIGN_Y_Z:
587 outVec->x = z;
588 outVec->y = y;
589 outVec->z = -x;
590 break;
591 case ALIGN_X_Y:
592 outVec->x = x;
593 outVec->y = y;
594 outVec->z = z;
595 break;
599 //---------------------------------------------------------------------
600 Terrain::Alignment Terrain::getAlignment() const
602 return mAlign;
604 //---------------------------------------------------------------------
605 uint16 Terrain::getSize() const
607 return mSize;
609 //---------------------------------------------------------------------
610 uint16 Terrain::getMaxBatchSize() const
612 return mMaxBatchSize;
614 //---------------------------------------------------------------------
615 uint16 Terrain::getMinBatchSize() const
617 return mMinBatchSize;
619 //---------------------------------------------------------------------
620 Real Terrain::getWorldSize() const
622 return mWorldSize;
624 //---------------------------------------------------------------------
625 Real Terrain::getSplatTextureWorldSize(uint16 index) const
627 if (index < mSplatTextureWorldSize.size())
629 return mSplatTextureWorldSize[index];
631 else if (!mSplatTextureWorldSize.empty())
633 return mSplatTextureWorldSize[0];
635 else
637 // default to tile 100 times
638 return mWorldSize * 0.01;
641 //---------------------------------------------------------------------
642 void Terrain::setSplatTextureWorldSize(uint16 index, Real size)
644 if (index >= mSplatTextureWorldSize.size())
646 mSplatTextureWorldSize.resize(index + 1);
647 mSplatTextureUVMultiplier.resize(index + 1);
650 mSplatTextureWorldSize[index] = size;
651 mSplatTextureUVMultiplier[index] = mWorldSize / size;
653 //---------------------------------------------------------------------
654 Real Terrain::getSplatTextureUVMultipler(uint16 index) const
656 if (index < mSplatTextureUVMultiplier.size())
658 return mSplatTextureUVMultiplier[index];
660 else if (!mSplatTextureUVMultiplier.empty())
662 return mSplatTextureUVMultiplier[0];
664 else
666 // default to tile 100 times
667 return 100;
670 //---------------------------------------------------------------------
671 void Terrain::setPosition(const Vector3& pos)
673 mPos = pos;
674 mRootNode->setPosition(pos);
675 updateBaseScale();
677 //---------------------------------------------------------------------
678 SceneNode* Terrain::_getRootSceneNode() const
680 return mRootNode;
682 //---------------------------------------------------------------------
683 void Terrain::updateBaseScale()
685 // centre the terrain on local origin
686 mBase = -mWorldSize * 0.5;
687 // scale determines what 1 unit on the grid becomes in world space
688 mScale = mWorldSize / (Real)(mSize-1);
690 //---------------------------------------------------------------------
691 void Terrain::dirty()
693 // TODO - geometry
695 // calculate entire terrain
696 Rect rect;
697 rect.top = 0; rect.bottom = mSize;
698 rect.left = 0; rect.right = mSize;
699 calculateHeightDeltas(rect);
701 //---------------------------------------------------------------------
702 void Terrain::dirtyRect(const Rect& rect)
704 // TODO - geometry
706 calculateHeightDeltas(rect);
709 //---------------------------------------------------------------------
710 void Terrain::freeCPUResources()
712 OGRE_FREE(mHeightData, MEMCATEGORY_GEOMETRY);
713 mHeightData = 0;
715 OGRE_FREE(mDeltaData, MEMCATEGORY_GEOMETRY);
716 mHeightData = 0;
718 OGRE_DELETE mQuadTree;
719 mQuadTree = 0;
724 //---------------------------------------------------------------------
725 void Terrain::freeGPUResources()
727 // delete batched geometry
729 // SHARE geometry between Terrain instances!
732 //---------------------------------------------------------------------
733 void Terrain::calculateHeightDeltas(const Rect& rect)
735 Rect clampedRect(rect);
736 clampedRect.left = std::max(0L, clampedRect.left);
737 clampedRect.top = std::max(0L, clampedRect.top);
738 clampedRect.right = std::min((long)mSize, clampedRect.right);
739 clampedRect.bottom = std::min((long)mSize, clampedRect.bottom);
741 mQuadTree->preDeltaCalculation(clampedRect);
743 /// Iterate over target levels,
744 for (int targetLevel = 1; targetLevel < mNumLodLevels; ++targetLevel)
746 int sourceLevel = targetLevel - 1;
747 int step = 1 << targetLevel;
748 // The step of the next higher LOD
749 int higherstep = step >> 1;
751 // round the rectangle at this level so that it starts & ends on
752 // the step boundaries
753 Rect lodRect(clampedRect);
754 lodRect.left -= lodRect.left % step;
755 lodRect.top -= lodRect.top % step;
756 if (lodRect.right % step)
757 lodRect.right += step - (lodRect.right % step);
758 if (lodRect.bottom % step)
759 lodRect.bottom += step - (lodRect.bottom % step);
761 for (int j = lodRect.top; j < lodRect.bottom - step; j += step )
763 for (int i = lodRect.left; i < lodRect.right - step; i += step )
765 // Form planes relating to the lower detail tris to be produced
766 // For tri lists and even tri strip rows, they are this shape:
767 // x---x
768 // | / |
769 // x---x
770 // For odd tri strip rows, they are this shape:
771 // x---x
772 // | \ |
773 // x---x
775 Vector3 v1, v2, v3, v4;
776 getPointAlign(i, j, ALIGN_X_Z, &v1);
777 getPointAlign(i + step, j, ALIGN_X_Z, &v2);
778 getPointAlign(i, j + step, ALIGN_X_Z, &v3);
779 getPointAlign(i + step, j + step, ALIGN_X_Z, &v4);
781 Plane t1, t2;
782 bool backwardTri = false;
783 if (!mUseTriangleStrips || j % 2 == 0)
785 t1.redefine(v1, v3, v2);
786 t2.redefine(v2, v3, v4);
788 else
790 t1.redefine(v1, v3, v4);
791 t2.redefine(v1, v4, v2);
792 backwardTri = true;
795 // include the bottommost row of vertices if this is the last row
796 int zubound = (j == (mSize - step)? step : step - 1);
797 for ( int z = 0; z <= zubound; z++ )
799 // include the rightmost col of vertices if this is the last col
800 int xubound = (i == (mSize - step)? step : step - 1);
801 for ( int x = 0; x <= xubound; x++ )
803 int fulldetailx = i + x;
804 int fulldetailz = j + z;
805 if ( fulldetailx % step == 0 &&
806 fulldetailz % step == 0 )
808 // Skip, this one is a vertex at this level
809 continue;
812 Real zpct = (Real)z / (Real)step;
813 Real xpct = (Real)x / (Real)step;
815 //interpolated height
816 Vector3 actualPos;
817 getPointAlign(fulldetailx, fulldetailz, ALIGN_X_Z, &actualPos);
818 Real interp_h;
819 // Determine which tri we're on
820 if ((xpct + zpct <= 1.0f && !backwardTri) ||
821 (xpct + (1-zpct) <= 1.0f && backwardTri))
823 // Solve for x/z
824 interp_h =
825 (-(t1.normal.x * actualPos.x)
826 - t1.normal.z * actualPos.z
827 - t1.d) / t1.normal.y;
829 else
831 // Second tri
832 interp_h =
833 (-(t2.normal.x * actualPos.x)
834 - t2.normal.z * actualPos.z
835 - t2.d) / t2.normal.y;
838 Real actual_h = actualPos.y;
839 Real delta = interp_h - actual_h;
841 // max(delta) is the worst case scenario at this LOD
842 // compared to the original heightmap
844 // tell the quadtree about this
845 mQuadTree->notifyDelta(fulldetailx, fulldetailz, sourceLevel, delta);
848 // If this vertex is being removed at this LOD,
849 // then save the height difference since that's the move
850 // it will need to make. Vertices to be removed at this LOD
851 // are halfway between the steps
852 if ((fulldetailx % step) == step / 2 || (fulldetailz % step) == step / 2)
854 // Save height difference
855 mDeltaData[fulldetailx + (fulldetailz * mSize)] = delta;
861 } // i
862 } // j
863 } // targetLevel
865 mQuadTree->postDeltaCalculation(clampedRect);
869 //---------------------------------------------------------------------
870 uint16 Terrain::getResolutionAtLod(uint16 lodLevel)
872 return ((mSize - 1) >> lodLevel) + 1;
874 //---------------------------------------------------------------------
875 void Terrain::preFindVisibleObjects(SceneManager* source,
876 SceneManager::IlluminationRenderStage irs, Viewport* v)
878 // only calculate LOD on main render passes
879 if (irs == SceneManager::IRS_NONE)
880 calculateCurrentLod(v);
882 //---------------------------------------------------------------------
883 void Terrain::sceneManagerDestroyed(SceneManager* source)
885 unload();
886 unprepare();
887 if (source == mSceneMgr)
888 mSceneMgr = 0;
890 //---------------------------------------------------------------------
891 void Terrain::calculateCurrentLod(Viewport* vp)
893 if (mQuadTree)
895 // calculate error terms
896 const Camera* cam = vp->getCamera()->getLodCamera();
898 // A = 1 / tan(fovy) (== 1 for fovy=45)
899 Real A = 1.0 / Math::Tan(cam->getFOVy());
900 // T = 2 * maxPixelError / vertRes
901 Real maxPixelError = TerrainGlobalOptions::getMaxPixelError() * cam->_getLodBiasInverse();
902 Real T = 2.0 * maxPixelError / (Real)vp->getActualHeight();
904 // CFactor = A / T
905 Real cFactor = A / T;
907 // CFactor should be squared before being used
908 cFactor = Math::Sqr(cFactor);
910 mQuadTree->calculateCurrentLod(cam, cFactor);
913 //---------------------------------------------------------------------
914 std::pair<bool, Vector3> Terrain::rayIntersects(const Ray& ray)
916 typedef std::pair<bool, Vector3> Result;
917 // first step: convert the ray to a local vertex space
918 // we assume terrain to be in the x-z plane, with the [0,0] vertex
919 // at origin and a plane distance of 1 between vertices.
920 // This makes calculations easier.
921 Vector3 rayOrigin = ray.getOrigin() - getPosition();
922 Vector3 rayDirection = ray.getDirection();
923 // relabel axes (probably wrong? need correct coordinate transformation)
924 switch (getAlignment())
926 case ALIGN_X_Y:
927 std::swap(rayOrigin.y, rayOrigin.z);
928 std::swap(rayDirection.y, rayDirection.z);
929 break;
930 case ALIGN_Y_Z:
931 std::swap(rayOrigin.x, rayOrigin.y);
932 std::swap(rayDirection.x, rayDirection.y);
933 break;
934 case ALIGN_X_Z:
935 break;
937 // readjust coordinate origin
938 rayOrigin.x += mWorldSize/2;
939 rayOrigin.z += mWorldSize/2;
940 // scale down to vertex level
941 rayOrigin.x /= mScale;
942 rayOrigin.z /= mScale;
943 rayDirection.x /= mScale;
944 rayDirection.z /= mScale;
945 rayDirection.normalise();
946 Ray localRay (rayOrigin, rayDirection);
948 // test if the ray actually hits the terrain's bounds
949 // TODO: Replace y values with actual heightmap height limits
950 AxisAlignedBox aabb (Vector3(0, 0, 0), Vector3(mSize, 1000000, mSize));
951 std::pair<bool, Real> aabbTest = localRay.intersects(aabb);
952 if (!aabbTest.first)
953 return Result(false, Vector3());
954 // get intersection point and move inside
955 Vector3 cur = localRay.getPoint(aabbTest.second);
957 // now check every quad the ray touches
958 int quadX = std::min(std::max(static_cast<int>(cur.x), 0), (int)mSize-2);
959 int quadZ = std::min(std::max(static_cast<int>(cur.z), 0), (int)mSize-2);
960 int flipX = (rayDirection.x < 0 ? 0 : 1);
961 int flipZ = (rayDirection.z < 0 ? 0 : 1);
962 int xDir = (rayDirection.x < 0 ? -1 : 1);
963 int zDir = (rayDirection.z < 0 ? -1 : 1);
964 Result result;
965 while (cur.y >= -1 && cur.y <= 2)
967 if (quadX < 0 || quadX >= (int)mSize-1 || quadZ < 0 || quadZ >= (int)mSize-1)
968 break;
970 result = checkQuadIntersection(quadX, quadZ, localRay);
971 if (result.first)
972 break;
974 // determine next quad to test
975 Real xDist = (quadX - cur.x + flipX) / rayDirection.x;
976 Real zDist = (quadZ - cur.z + flipZ) / rayDirection.z;
977 if (xDist < zDist)
979 quadX += xDir;
980 cur += rayDirection * xDist;
982 else
984 quadZ += zDir;
985 cur += rayDirection * zDist;
990 if (result.first)
992 // transform the point of intersection back to world space
993 result.second.x *= mScale;
994 result.second.z *= mScale;
995 result.second.x -= mWorldSize/2;
996 result.second.z -= mWorldSize/2;
997 switch (getAlignment())
999 case ALIGN_X_Y:
1000 std::swap(result.second.y, result.second.z);
1001 break;
1002 case ALIGN_Y_Z:
1003 std::swap(result.second.x, result.second.y);
1004 break;
1005 case ALIGN_X_Z:
1006 break;
1008 result.second += getPosition();
1010 return result;
1012 //---------------------------------------------------------------------
1013 std::pair<bool, Vector3> Terrain::checkQuadIntersection(int x, int z, const Ray& ray)
1015 // build the two planes belonging to the quad's triangles
1016 Vector3 v1 (x, *getHeightData(x,z), z);
1017 Vector3 v2 (x+1, *getHeightData(x+1,z), z);
1018 Vector3 v3 (x, *getHeightData(x,z+1), z+1);
1019 Vector3 v4 (x+1, *getHeightData(x+1,z+1), z+1);
1020 // TODO: Is this the correct triangle order?
1021 Plane p1 (v1, v3, v2);
1022 Plane p2 (v3, v4, v2);
1024 // Test for intersection with the two planes.
1025 // Then test that the intersection points are actually
1026 // still inside the triangle (with a small error margin)
1027 std::pair<bool, Real> planeInt = ray.intersects(p1);
1028 if (planeInt.first)
1030 Vector3 where = ray.getPoint(planeInt.second);
1031 Vector3 rel = where - v1;
1032 if (rel.x >= -0.01 && rel.x <= 1.01 && rel.z >= -0.01 && rel.z <= 1.01 && rel.x+rel.z <= 1.01)
1033 return std::pair<bool, Vector3>(true, where);
1035 planeInt = ray.intersects(p2);
1036 if (planeInt.first)
1038 Vector3 where = ray.getPoint(planeInt.second);
1039 Vector3 rel = where - v1;
1040 if (rel.x >= -0.01 && rel.x <= 1.01 && rel.z >= -0.01 && rel.z <= 1.01 && rel.x+rel.z >= 0.99)
1041 return std::pair<bool, Vector3>(true, where);
1044 return std::pair<bool, Vector3>(false, Vector3());
1046 //---------------------------------------------------------------------
1047 const MaterialPtr& Terrain::getMaterial() const
1049 // TODO - generate material
1051 return mMaterial;