Terrain.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  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. std::string heightmap;
  84. if (!pHeightmap->getPath("path", &heightmap))
  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.c_str());
  92. if (ext == ".PNG")
  93. {
  94. // Read normalized height values from heightmap image
  95. heightfield = HeightField::createFromImage(heightmap.c_str(), 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.c_str(), (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.c_str(), 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. std::string heightmap;
  124. if (!pTerrain->getPath("heightmap", &heightmap))
  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.c_str());
  132. if (ext == ".PNG")
  133. {
  134. // Read normalized height values from heightmap image
  135. heightfield = HeightField::createFromImage(heightmap.c_str(), 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.c_str(), 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. std::string textureMap;
  259. const char* textureMapPtr = NULL;
  260. std::string blendMap;
  261. const char* blendMapPtr = NULL;
  262. Vector2 textureRepeat;
  263. int blendChannel = 0;
  264. int row = -1, column = -1;
  265. Vector4 temp;
  266. // Read layer textures
  267. Properties* t = lp->getNamespace("texture", true);
  268. if (t)
  269. {
  270. if (t->getPath("path", &textureMap))
  271. {
  272. textureMapPtr = textureMap.c_str();
  273. }
  274. if (!t->getVector2("repeat", &textureRepeat))
  275. textureRepeat.set(1,1);
  276. }
  277. Properties* b = lp->getNamespace("blend", true);
  278. if (b)
  279. {
  280. if (b->getPath("path", &blendMap))
  281. {
  282. blendMapPtr = blendMap.c_str();
  283. }
  284. const char* channel = b->getString("channel");
  285. if (channel && strlen(channel) > 0)
  286. {
  287. char c = std::toupper(channel[0]);
  288. if (c == 'R' || c == '0')
  289. blendChannel = 0;
  290. else if (c == 'G' || c == '1')
  291. blendChannel = 1;
  292. else if (c == 'B' || c == '2')
  293. blendChannel = 2;
  294. else if (c == 'A' || c == '3')
  295. blendChannel = 3;
  296. }
  297. }
  298. // Get patch row/columns that this layer applies to.
  299. if (lp->exists("row"))
  300. row = lp->getInt("row");
  301. if (lp->exists("column"))
  302. column = lp->getInt("column");
  303. if (!terrain->setLayer(index, textureMapPtr, textureRepeat, blendMapPtr, blendChannel, row, column))
  304. {
  305. GP_WARN("Failed to load terrain layer: %s", textureMap.c_str());
  306. }
  307. }
  308. }
  309. }
  310. // Load materials for all patches
  311. for (size_t i = 0, count = terrain->_patches.size(); i < count; ++i)
  312. terrain->_patches[i]->updateMaterial();
  313. return terrain;
  314. }
  315. void Terrain::setNode(Node* node)
  316. {
  317. if (_node != node)
  318. {
  319. if (_node)
  320. _node->removeListener(this);
  321. _node = node;
  322. if (_node)
  323. _node->addListener(this);
  324. _dirtyFlags |= TERRAIN_DIRTY_WORLD_MATRIX | TERRAIN_DIRTY_INV_WORLD_MATRIX | TERRAIN_DIRTY_NORMAL_MATRIX;
  325. }
  326. }
  327. bool Terrain::setLayer(int index, const char* texturePath, const Vector2& textureRepeat, const char* blendPath, int blendChannel, int row, int column)
  328. {
  329. if (!texturePath)
  330. return false;
  331. // Set layer on applicable patches
  332. bool result = true;
  333. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  334. {
  335. TerrainPatch* patch = _patches[i];
  336. if ((row == -1 || (int)patch->_row == row) && (column == -1 || (int)patch->_column == column))
  337. {
  338. if (!patch->setLayer(index, texturePath, textureRepeat, blendPath, blendChannel))
  339. result = false;
  340. }
  341. }
  342. return result;
  343. }
  344. Node* Terrain::getNode() const
  345. {
  346. return _node;
  347. }
  348. bool Terrain::isFlagSet(Flags flag) const
  349. {
  350. return (_flags & flag) == flag;
  351. }
  352. void Terrain::setFlag(Flags flag, bool on)
  353. {
  354. bool changed = false;
  355. if (on)
  356. {
  357. if ((_flags & flag) == 0)
  358. {
  359. _flags |= flag;
  360. changed = true;
  361. }
  362. }
  363. else
  364. {
  365. if ((_flags & flag) == flag)
  366. {
  367. _flags &= ~flag;
  368. changed = true;
  369. }
  370. }
  371. if (flag == DEBUG_PATCHES && changed)
  372. {
  373. // Dirty all materials since they need to be updated to support debug drawing
  374. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  375. _patches[i]->_materialDirty = true;
  376. }
  377. }
  378. unsigned int Terrain::getPatchCount() const
  379. {
  380. return _patches.size();
  381. }
  382. unsigned int Terrain::getVisiblePatchCount() const
  383. {
  384. unsigned int visibleCount = 0;
  385. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  386. {
  387. if (_patches[i]->isVisible())
  388. ++visibleCount;
  389. }
  390. return visibleCount;
  391. }
  392. unsigned int Terrain::getTriangleCount() const
  393. {
  394. unsigned int triangleCount = 0;
  395. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  396. {
  397. triangleCount += _patches[i]->getTriangleCount();
  398. }
  399. return triangleCount;
  400. }
  401. unsigned int Terrain::getVisibleTriangleCount() const
  402. {
  403. unsigned int triangleCount = 0;
  404. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  405. {
  406. triangleCount += _patches[i]->getVisibleTriangleCount();
  407. }
  408. return triangleCount;
  409. }
  410. const BoundingBox& Terrain::getBoundingBox() const
  411. {
  412. return _boundingBox;
  413. }
  414. float Terrain::getHeight(float x, float z) const
  415. {
  416. // Calculate the correct x, z position relative to the heightfield data.
  417. float cols = _heightfield->getColumnCount();
  418. float rows = _heightfield->getRowCount();
  419. GP_ASSERT(cols > 0);
  420. GP_ASSERT(rows > 0);
  421. // Since the specified coordinates are in world space, we need to use the
  422. // inverse of our world matrix to transform the world x,z coords back into
  423. // local heightfield coordinates for indexing into the height array.
  424. Vector3 v = getInverseWorldMatrix() * Vector3(x, 0.0f, z);
  425. x = v.x + (cols - 1) * 0.5f;
  426. z = v.z + (rows - 1) * 0.5f;
  427. // Get the unscaled height value from the HeightField
  428. float height = _heightfield->getHeight(x, z);
  429. // Now apply world scale (this includes local terrain scale) to the heightfield value
  430. Vector3 worldScale;
  431. getWorldMatrix().getScale(&worldScale);
  432. height *= worldScale.y;
  433. return height;
  434. }
  435. void Terrain::draw(bool wireframe)
  436. {
  437. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  438. {
  439. _patches[i]->draw(wireframe);
  440. }
  441. }
  442. void Terrain::transformChanged(Transform* transform, long cookie)
  443. {
  444. _dirtyFlags |= TERRAIN_DIRTY_WORLD_MATRIX | TERRAIN_DIRTY_INV_WORLD_MATRIX | TERRAIN_DIRTY_NORMAL_MATRIX;
  445. }
  446. void Terrain::addListener(Terrain::Listener* listener)
  447. {
  448. _listeners.push_back(listener);
  449. // Fire initial events in case this listener may have missed them
  450. for (size_t i = 0, patchCount = _patches.size(); i < patchCount; ++i)
  451. {
  452. TerrainPatch* patch = _patches[i];
  453. for (size_t j = 0, levelCount = patch->_levels.size(); j < levelCount; ++j)
  454. {
  455. TerrainPatch::Level* level = patch->_levels[j];
  456. Material* material = level->model ? level->model->getMaterial() : NULL;
  457. if (material)
  458. {
  459. // Fire materialUpdated event for materials that are already active
  460. for (size_t k = 0, lcount = _listeners.size(); k < lcount; ++k)
  461. {
  462. _listeners[k]->materialUpdated(this, material);
  463. }
  464. }
  465. }
  466. }
  467. }
  468. void Terrain::removeListener(Terrain::Listener* listener)
  469. {
  470. std::vector<Terrain::Listener*>::iterator itr = std::find(_listeners.begin(), _listeners.end(), listener);
  471. if (itr != _listeners.end())
  472. _listeners.erase(itr);
  473. }
  474. const Matrix& Terrain::getWorldMatrix() const
  475. {
  476. if (_dirtyFlags & TERRAIN_DIRTY_WORLD_MATRIX)
  477. {
  478. _dirtyFlags &= ~TERRAIN_DIRTY_WORLD_MATRIX;
  479. // Apply our attached node's world matrix
  480. if (_node)
  481. {
  482. _worldMatrix = _node->getWorldMatrix();
  483. }
  484. else
  485. {
  486. _worldMatrix.setIdentity();
  487. }
  488. // Factor in our local scaling
  489. _worldMatrix.scale(_localScale);
  490. }
  491. return _worldMatrix;
  492. }
  493. const Matrix& Terrain::getInverseWorldMatrix() const
  494. {
  495. if (_dirtyFlags & TERRAIN_DIRTY_INV_WORLD_MATRIX)
  496. {
  497. _dirtyFlags &= ~TERRAIN_DIRTY_INV_WORLD_MATRIX;
  498. getWorldMatrix().invert(&_inverseWorldMatrix);
  499. }
  500. return _inverseWorldMatrix;
  501. }
  502. const Matrix& Terrain::getNormalMatrix() const
  503. {
  504. if (_dirtyFlags & TERRAIN_DIRTY_NORMAL_MATRIX)
  505. {
  506. _dirtyFlags &= ~TERRAIN_DIRTY_NORMAL_MATRIX;
  507. getInverseWorldMatrix().transpose(&_normalMatrix);
  508. }
  509. return _normalMatrix;
  510. }
  511. const Matrix& Terrain::getWorldViewMatrix() const
  512. {
  513. static Matrix worldView;
  514. if (_node)
  515. Matrix::multiply(_node->getViewMatrix(), getWorldMatrix(), &worldView);
  516. else
  517. worldView = getWorldMatrix(); // no node, so nothing to get view from
  518. return worldView;
  519. }
  520. const Matrix& Terrain::getWorldViewProjectionMatrix() const
  521. {
  522. static Matrix worldViewProj;
  523. if (_node)
  524. Matrix::multiply(_node->getViewProjectionMatrix(), getWorldMatrix(), &worldViewProj);
  525. else
  526. worldViewProj = getWorldMatrix(); // no node, so nothing to get viewProjection from
  527. return worldViewProj;
  528. }
  529. float getDefaultHeight(unsigned int width, unsigned int height)
  530. {
  531. // When terrain height is not specified, we'll use a default height of ~ 0.3 of the image dimensions
  532. return ((width + height) * 0.5f) * DEFAULT_TERRAIN_HEIGHT_RATIO;
  533. }
  534. }