Terrain.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. #include "Base.h"
  2. #include "Terrain.h"
  3. #include "TerrainPatch.h"
  4. #include "Node.h"
  5. #include "FileSystem.h"
  6. namespace gameplay
  7. {
  8. // The default square size of terrain patches for a terrain that
  9. // does not have an explicitly specified patch size.
  10. //
  11. #define DEFAULT_TERRAIN_PATCH_SIZE 32
  12. // The default height of a terrain that does not have an explicitly
  13. // specified terrain size, expressed as a ratio of the average
  14. // of the dimensions of the terrain heightfield:
  15. //
  16. // heightMax = (image.width + image.height) / 2 * DEFAULT_TERRAIN_HEIGHT_RATIO
  17. //
  18. #define DEFAULT_TERRAIN_HEIGHT_RATIO 0.3f
  19. // Terrain dirty flag bits
  20. #define TERRAIN_DIRTY_WORLD_MATRIX 1
  21. #define TERRAIN_DIRTY_INV_WORLD_MATRIX 2
  22. #define TERRAIN_DIRTY_NORMAL_MATRIX 4
  23. /**
  24. * @script{ignore}
  25. */
  26. float getDefaultHeight(unsigned int width, unsigned int height);
  27. Terrain::Terrain() :
  28. _heightfield(NULL), _node(NULL), _normalMap(NULL), _flags(FRUSTUM_CULLING | LEVEL_OF_DETAIL),
  29. _dirtyFlags(TERRAIN_DIRTY_WORLD_MATRIX | TERRAIN_DIRTY_INV_WORLD_MATRIX | TERRAIN_DIRTY_NORMAL_MATRIX)
  30. {
  31. }
  32. Terrain::~Terrain()
  33. {
  34. _listeners.clear();
  35. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  36. {
  37. SAFE_DELETE(_patches[i]);
  38. }
  39. if (_node)
  40. _node->removeListener(this);
  41. SAFE_RELEASE(_normalMap);
  42. SAFE_RELEASE(_heightfield);
  43. }
  44. Terrain* Terrain::create(const char* path)
  45. {
  46. return create(path, NULL);
  47. }
  48. Terrain* Terrain::create(Properties* properties)
  49. {
  50. return create(properties->getNamespace(), properties);
  51. }
  52. Terrain* Terrain::create(const char* path, Properties* properties)
  53. {
  54. // Terrain properties
  55. Properties* p = properties;
  56. Properties* pTerrain = NULL;
  57. bool externalProperties = (p != NULL);
  58. HeightField* heightfield = NULL;
  59. Vector3 terrainSize;
  60. int patchSize = 0;
  61. int detailLevels = 1;
  62. float skirtScale = 0;
  63. const char* normalMap = NULL;
  64. if (!p && path)
  65. {
  66. p = Properties::create(path);
  67. }
  68. if (p)
  69. {
  70. pTerrain = strlen(p->getNamespace()) > 0 ? p : p->getNextNamespace();
  71. if (pTerrain == NULL)
  72. {
  73. GP_WARN("Invalid terrain definition.");
  74. if (!externalProperties)
  75. SAFE_DELETE(p);
  76. return NULL;
  77. }
  78. // Read heightmap info
  79. Properties* pHeightmap = pTerrain->getNamespace("heightmap", true);
  80. if (pHeightmap)
  81. {
  82. // Read heightmap path
  83. const char* heightmap = pHeightmap->getString("path");
  84. if (strlen(heightmap) == 0)
  85. {
  86. GP_WARN("No 'path' property supplied in heightmap section of terrain definition: %s", path);
  87. if (!externalProperties)
  88. SAFE_DELETE(p);
  89. return NULL;
  90. }
  91. std::string ext = FileSystem::getExtension(heightmap);
  92. if (ext == ".PNG")
  93. {
  94. // Read normalized height values from heightmap image
  95. heightfield = HeightField::createFromImage(heightmap, 0, 1);
  96. }
  97. else if (ext == ".RAW" || ext == ".R16")
  98. {
  99. // Require additional properties to be specified for RAW files
  100. Vector2 imageSize;
  101. if (!pHeightmap->getVector2("size", &imageSize))
  102. {
  103. GP_WARN("Invalid or missing 'size' attribute in heightmap defintion of terrain definition: %s", path);
  104. if (!externalProperties)
  105. SAFE_DELETE(p);
  106. return NULL;
  107. }
  108. // Read normalized height values from RAW file
  109. heightfield = HeightField::createFromRAW(heightmap, (unsigned int)imageSize.x, (unsigned int)imageSize.y, 0, 1);
  110. }
  111. else
  112. {
  113. // Unsupported heightmap format
  114. GP_WARN("Unsupported heightmap format ('%s') in terrain definition: %s", heightmap, path);
  115. if (!externalProperties)
  116. SAFE_DELETE(p);
  117. return NULL;
  118. }
  119. }
  120. else
  121. {
  122. // Try to read 'heightmap' as a simple string property
  123. const char* heightmap = pTerrain->getString("heightmap");
  124. if (heightmap == NULL || strlen(heightmap) == 0)
  125. {
  126. GP_WARN("No 'heightmap' property supplied in terrain definition: %s", path);
  127. if (!externalProperties)
  128. SAFE_DELETE(p);
  129. return NULL;
  130. }
  131. std::string ext = FileSystem::getExtension(heightmap);
  132. if (ext == ".PNG")
  133. {
  134. // Read normalized height values from heightmap image
  135. heightfield = HeightField::createFromImage(heightmap, 0, 1);
  136. }
  137. else if (ext == ".RAW" || ext == ".R16")
  138. {
  139. GP_WARN("RAW heightmaps must be specified inside a heightmap block with width and height properties.");
  140. if (!externalProperties)
  141. SAFE_DELETE(p);
  142. return NULL;
  143. }
  144. else
  145. {
  146. GP_WARN("Unsupported 'heightmap' format ('%s') in terrain definition: %s.", heightmap, path);
  147. if (!externalProperties)
  148. SAFE_DELETE(p);
  149. return NULL;
  150. }
  151. }
  152. // Read terrain 'size'
  153. if (pTerrain->exists("size"))
  154. {
  155. if (!pTerrain->getVector3("size", &terrainSize))
  156. {
  157. GP_WARN("Invalid 'size' value ('%s') in terrain definition: %s", pTerrain->getString("size"), path);
  158. }
  159. }
  160. // Read terrain 'patch size'
  161. if (pTerrain->exists("patchSize"))
  162. {
  163. patchSize = pTerrain->getInt("patchSize");
  164. }
  165. // Read terrain 'detailLevels'
  166. if (pTerrain->exists("detailLevels"))
  167. {
  168. detailLevels = pTerrain->getInt("detailLevels");
  169. }
  170. // Read 'skirtScale'
  171. if (pTerrain->exists("skirtScale"))
  172. {
  173. skirtScale = pTerrain->getFloat("skirtScale");
  174. }
  175. // Read 'normalMap'
  176. normalMap = pTerrain->getString("normalMap");
  177. }
  178. if (heightfield == NULL)
  179. {
  180. GP_WARN("Failed to read heightfield heights for terrain definition: %s", path);
  181. if (!externalProperties)
  182. SAFE_DELETE(p);
  183. return NULL;
  184. }
  185. if (terrainSize.isZero())
  186. {
  187. terrainSize.set(heightfield->getColumnCount(), getDefaultHeight(heightfield->getColumnCount(), heightfield->getRowCount()), heightfield->getRowCount());
  188. }
  189. if (patchSize <= 0 || patchSize > (int)heightfield->getColumnCount() || patchSize > (int)heightfield->getRowCount())
  190. {
  191. patchSize = std::min(heightfield->getRowCount(), std::min(heightfield->getColumnCount(), (unsigned int)DEFAULT_TERRAIN_PATCH_SIZE));
  192. }
  193. if (detailLevels <= 0)
  194. detailLevels = 1;
  195. if (skirtScale < 0)
  196. skirtScale = 0;
  197. // Compute terrain scale
  198. Vector3 scale(terrainSize.x / (heightfield->getColumnCount()-1), terrainSize.y, terrainSize.z / (heightfield->getRowCount()-1));
  199. // Create terrain
  200. Terrain* terrain = create(heightfield, scale, (unsigned int)patchSize, (unsigned int)detailLevels, skirtScale, normalMap, pTerrain);
  201. if (!externalProperties)
  202. SAFE_DELETE(p);
  203. return terrain;
  204. }
  205. Terrain* Terrain::create(HeightField* heightfield, const Vector3& scale, unsigned int patchSize, unsigned int detailLevels, float skirtScale, const char* normalMapPath)
  206. {
  207. return create(heightfield, scale, patchSize, detailLevels, skirtScale, normalMapPath, NULL);
  208. }
  209. Terrain* Terrain::create(HeightField* heightfield, const Vector3& scale, unsigned int patchSize, unsigned int detailLevels, float skirtScale, const char* normalMapPath, Properties* properties)
  210. {
  211. GP_ASSERT(heightfield);
  212. unsigned int width = heightfield->getColumnCount();
  213. unsigned int height = heightfield->getRowCount();
  214. // Create the terrain object
  215. Terrain* terrain = new Terrain();
  216. terrain->_heightfield = heightfield;
  217. terrain->_localScale = scale;
  218. // Store reference to bounding box (it is calculated and updated from TerrainPatch)
  219. BoundingBox& bounds = terrain->_boundingBox;
  220. if (normalMapPath)
  221. terrain->_normalMap = Texture::Sampler::create(normalMapPath, true);
  222. float halfWidth = (width - 1) * 0.5f;
  223. float halfHeight = (height - 1) * 0.5f;
  224. unsigned int maxStep = (unsigned int)std::pow(2.0, (double)(detailLevels-1));
  225. // Create terrain patches
  226. unsigned int x1, x2, z1, z2;
  227. unsigned int row = 0, column = 0;
  228. for (unsigned int z = 0; z < height-1; z = z2, ++row)
  229. {
  230. z1 = z;
  231. z2 = std::min(z1 + patchSize, height-1);
  232. for (unsigned int x = 0; x < width-1; x = x2, ++column)
  233. {
  234. x1 = x;
  235. x2 = std::min(x1 + patchSize, width-1);
  236. // Create this patch
  237. TerrainPatch* patch = TerrainPatch::create(terrain, row, column, heightfield->getArray(), width, height, x1, z1, x2, z2, -halfWidth, -halfHeight, maxStep, skirtScale);
  238. terrain->_patches.push_back(patch);
  239. // Append the new patch's local bounds to the terrain local bounds
  240. bounds.merge(patch->getBoundingBox(false));
  241. }
  242. }
  243. // Read additional layer information from properties (if specified)
  244. if (properties)
  245. {
  246. // Parse terrain layers
  247. Properties* lp;
  248. int index = -1;
  249. while ((lp = properties->getNextNamespace()) != NULL)
  250. {
  251. if (strcmp(lp->getNamespace(), "layer") == 0)
  252. {
  253. // If there is no explicitly specified index for this layer, assume it's the 'next' layer
  254. if (lp->exists("index"))
  255. index = lp->getInt("index");
  256. else
  257. ++index;
  258. const char* textureMap = NULL;
  259. const char* blendMap = NULL;
  260. Vector2 textureRepeat;
  261. int blendChannel = 0;
  262. int row = -1, column = -1;
  263. Vector4 temp;
  264. // Read layer textures
  265. Properties* t = lp->getNamespace("texture", true);
  266. if (t)
  267. {
  268. textureMap = t->getString("path");
  269. if (!t->getVector2("repeat", &textureRepeat))
  270. textureRepeat.set(1,1);
  271. }
  272. Properties* b = lp->getNamespace("blend", true);
  273. if (b)
  274. {
  275. blendMap = b->getString("path");
  276. const char* channel = b->getString("channel");
  277. if (channel && strlen(channel) > 0)
  278. {
  279. char c = std::toupper(channel[0]);
  280. if (c == 'R' || c == '0')
  281. blendChannel = 0;
  282. else if (c == 'G' || c == '1')
  283. blendChannel = 1;
  284. else if (c == 'B' || c == '2')
  285. blendChannel = 2;
  286. else if (c == 'A' || c == '3')
  287. blendChannel = 3;
  288. }
  289. }
  290. // Get patch row/columns that this layer applies to.
  291. if (lp->exists("row"))
  292. row = lp->getInt("row");
  293. if (lp->exists("column"))
  294. column = lp->getInt("column");
  295. if (!terrain->setLayer(index, textureMap, textureRepeat, blendMap, blendChannel, row, column))
  296. {
  297. GP_WARN("Failed to load terrain layer: %s", textureMap);
  298. }
  299. }
  300. }
  301. }
  302. // Load materials for all patches
  303. for (size_t i = 0, count = terrain->_patches.size(); i < count; ++i)
  304. terrain->_patches[i]->updateMaterial();
  305. return terrain;
  306. }
  307. void Terrain::setNode(Node* node)
  308. {
  309. if (_node != node)
  310. {
  311. if (_node)
  312. _node->removeListener(this);
  313. _node = node;
  314. if (_node)
  315. _node->addListener(this);
  316. _dirtyFlags |= TERRAIN_DIRTY_WORLD_MATRIX | TERRAIN_DIRTY_INV_WORLD_MATRIX | TERRAIN_DIRTY_NORMAL_MATRIX;
  317. }
  318. }
  319. bool Terrain::setLayer(int index, const char* texturePath, const Vector2& textureRepeat, const char* blendPath, int blendChannel, int row, int column)
  320. {
  321. if (!texturePath)
  322. return false;
  323. // Set layer on applicable patches
  324. bool result = true;
  325. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  326. {
  327. TerrainPatch* patch = _patches[i];
  328. if ((row == -1 || (int)patch->_row == row) && (column == -1 || (int)patch->_column == column))
  329. {
  330. if (!patch->setLayer(index, texturePath, textureRepeat, blendPath, blendChannel))
  331. result = false;
  332. }
  333. }
  334. return result;
  335. }
  336. Node* Terrain::getNode() const
  337. {
  338. return _node;
  339. }
  340. bool Terrain::isFlagSet(Flags flag) const
  341. {
  342. return (_flags & flag) == flag;
  343. }
  344. void Terrain::setFlag(Flags flag, bool on)
  345. {
  346. bool changed = false;
  347. if (on)
  348. {
  349. if ((_flags & flag) == 0)
  350. {
  351. _flags |= flag;
  352. changed = true;
  353. }
  354. }
  355. else
  356. {
  357. if ((_flags & flag) == flag)
  358. {
  359. _flags &= ~flag;
  360. changed = true;
  361. }
  362. }
  363. if (flag == DEBUG_PATCHES && changed)
  364. {
  365. // Dirty all materials since they need to be updated to support debug drawing
  366. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  367. _patches[i]->_materialDirty = true;
  368. }
  369. }
  370. unsigned int Terrain::getPatchCount() const
  371. {
  372. return _patches.size();
  373. }
  374. unsigned int Terrain::getVisiblePatchCount() const
  375. {
  376. unsigned int visibleCount = 0;
  377. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  378. {
  379. if (_patches[i]->isVisible())
  380. ++visibleCount;
  381. }
  382. return visibleCount;
  383. }
  384. unsigned int Terrain::getTriangleCount() const
  385. {
  386. unsigned int triangleCount = 0;
  387. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  388. {
  389. triangleCount += _patches[i]->getTriangleCount();
  390. }
  391. return triangleCount;
  392. }
  393. unsigned int Terrain::getVisibleTriangleCount() const
  394. {
  395. unsigned int triangleCount = 0;
  396. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  397. {
  398. triangleCount += _patches[i]->getVisibleTriangleCount();
  399. }
  400. return triangleCount;
  401. }
  402. const BoundingBox& Terrain::getBoundingBox() const
  403. {
  404. return _boundingBox;
  405. }
  406. float Terrain::getHeight(float x, float z) const
  407. {
  408. // Calculate the correct x, z position relative to the heightfield data.
  409. float cols = _heightfield->getColumnCount();
  410. float rows = _heightfield->getRowCount();
  411. GP_ASSERT(cols > 0);
  412. GP_ASSERT(rows > 0);
  413. // Since the specified coordinates are in world space, we need to use the
  414. // inverse of our world matrix to transform the world x,z coords back into
  415. // local heightfield coordinates for indexing into the height array.
  416. Vector3 v = getInverseWorldMatrix() * Vector3(x, 0.0f, z);
  417. x = v.x + (cols - 1) * 0.5f;
  418. z = v.z + (rows - 1) * 0.5f;
  419. // Get the unscaled height value from the HeightField
  420. float height = _heightfield->getHeight(x, z);
  421. // Now apply world scale (this includes local terrain scale) to the heightfield value
  422. Vector3 worldScale;
  423. getWorldMatrix().getScale(&worldScale);
  424. height *= worldScale.y;
  425. return height;
  426. }
  427. void Terrain::draw(bool wireframe)
  428. {
  429. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  430. {
  431. _patches[i]->draw(wireframe);
  432. }
  433. }
  434. void Terrain::transformChanged(Transform* transform, long cookie)
  435. {
  436. _dirtyFlags |= TERRAIN_DIRTY_WORLD_MATRIX | TERRAIN_DIRTY_INV_WORLD_MATRIX | TERRAIN_DIRTY_NORMAL_MATRIX;
  437. }
  438. void Terrain::addListener(Terrain::Listener* listener)
  439. {
  440. _listeners.push_back(listener);
  441. // Fire initial events in case this listener may have missed them
  442. for (size_t i = 0, patchCount = _patches.size(); i < patchCount; ++i)
  443. {
  444. TerrainPatch* patch = _patches[i];
  445. for (size_t j = 0, levelCount = patch->_levels.size(); j < levelCount; ++j)
  446. {
  447. TerrainPatch::Level* level = patch->_levels[j];
  448. Material* material = level->model ? level->model->getMaterial() : NULL;
  449. if (material)
  450. {
  451. // Fire materialUpdated event for materials that are already active
  452. for (size_t k = 0, lcount = _listeners.size(); k < lcount; ++k)
  453. {
  454. _listeners[k]->materialUpdated(this, material);
  455. }
  456. }
  457. }
  458. }
  459. }
  460. void Terrain::removeListener(Terrain::Listener* listener)
  461. {
  462. std::vector<Terrain::Listener*>::iterator itr = std::find(_listeners.begin(), _listeners.end(), listener);
  463. if (itr != _listeners.end())
  464. _listeners.erase(itr);
  465. }
  466. const Matrix& Terrain::getWorldMatrix() const
  467. {
  468. if (_dirtyFlags & TERRAIN_DIRTY_WORLD_MATRIX)
  469. {
  470. _dirtyFlags &= ~TERRAIN_DIRTY_WORLD_MATRIX;
  471. // Apply our attached node's world matrix
  472. if (_node)
  473. {
  474. _worldMatrix = _node->getWorldMatrix();
  475. }
  476. else
  477. {
  478. _worldMatrix.setIdentity();
  479. }
  480. // Factor in our local scaling
  481. _worldMatrix.scale(_localScale);
  482. }
  483. return _worldMatrix;
  484. }
  485. const Matrix& Terrain::getInverseWorldMatrix() const
  486. {
  487. if (_dirtyFlags & TERRAIN_DIRTY_INV_WORLD_MATRIX)
  488. {
  489. _dirtyFlags &= ~TERRAIN_DIRTY_INV_WORLD_MATRIX;
  490. getWorldMatrix().invert(&_inverseWorldMatrix);
  491. }
  492. return _inverseWorldMatrix;
  493. }
  494. const Matrix& Terrain::getNormalMatrix() const
  495. {
  496. if (_dirtyFlags & TERRAIN_DIRTY_NORMAL_MATRIX)
  497. {
  498. _dirtyFlags &= ~TERRAIN_DIRTY_NORMAL_MATRIX;
  499. getInverseWorldMatrix().transpose(&_normalMatrix);
  500. }
  501. return _normalMatrix;
  502. }
  503. const Matrix& Terrain::getWorldViewMatrix() const
  504. {
  505. static Matrix worldView;
  506. if (_node)
  507. Matrix::multiply(_node->getViewMatrix(), getWorldMatrix(), &worldView);
  508. else
  509. worldView = getWorldMatrix(); // no node, so nothing to get view from
  510. return worldView;
  511. }
  512. const Matrix& Terrain::getWorldViewProjectionMatrix() const
  513. {
  514. static Matrix worldViewProj;
  515. if (_node)
  516. Matrix::multiply(_node->getViewProjectionMatrix(), getWorldMatrix(), &worldViewProj);
  517. else
  518. worldViewProj = getWorldMatrix(); // no node, so nothing to get viewProjection from
  519. return worldViewProj;
  520. }
  521. float getDefaultHeight(unsigned int width, unsigned int height)
  522. {
  523. // When terrain height is not specified, we'll use a default height of ~ 0.3 of the image dimensions
  524. return ((width + height) * 0.5f) * DEFAULT_TERRAIN_HEIGHT_RATIO;
  525. }
  526. }