Terrain.cpp 17 KB

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