Terrain.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. #include "Base.h"
  2. #include "Terrain.h"
  3. #include "Node.h"
  4. #include "Image.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. // maxHeight = (image.width + image.height) / 2 * DEFAULT_TERRAIN_HEIGHT_RATIO
  17. //
  18. #define DEFAULT_TERRAIN_HEIGHT_RATIO 0.3f
  19. /**
  20. * @script{ignore}
  21. */
  22. std::string getExtension(const char* filename);
  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(ENABLE_FRUSTUM_CULLING | ENABLE_LEVEL_OF_DETAIL), _worldMatrixDirty(true)
  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* terrainFile)
  39. {
  40. // Terrain properties
  41. HeightField* heightfield = NULL;
  42. Vector3 terrainSize;
  43. int patchSize = 0;
  44. int detailLevels = 1;
  45. float skirtScale = 0;
  46. Properties* p = NULL;
  47. Properties* pTerrain = NULL;
  48. const char* normalMap = NULL;
  49. std::string ext = getExtension(terrainFile);
  50. if (ext == "PNG")
  51. {
  52. // Load terrain directly from a heightmap image
  53. heightfield = HeightField::create(terrainFile, 0, 0, 0, 1);
  54. }
  55. else
  56. {
  57. // Read terrain from properties file
  58. p = Properties::create(terrainFile);
  59. if (p == NULL)
  60. return NULL;
  61. pTerrain = strlen(p->getNamespace()) > 0 ? p : p->getNextNamespace();
  62. if (pTerrain == NULL)
  63. {
  64. GP_WARN("Invalid terrain definition file.");
  65. SAFE_DELETE(p);
  66. return NULL;
  67. }
  68. // Read heightmap info
  69. Properties* pHeightmap = pTerrain->getNamespace("heightmap", true);
  70. if (pHeightmap)
  71. {
  72. // Read heightmap path
  73. const char* heightmap = pHeightmap->getString("path");
  74. if (strlen(heightmap) == 0)
  75. {
  76. GP_WARN("No 'path' property supplied in heightmap section of terrain definition file: %s", terrainFile);
  77. SAFE_DELETE(p);
  78. return NULL;
  79. }
  80. ext = getExtension(heightmap);
  81. if (ext == "PNG")
  82. {
  83. // Read normalized height values from heightmap image
  84. heightfield = HeightField::create(heightmap, 0, 0, 0, 1);
  85. }
  86. else if (ext == "RAW")
  87. {
  88. // Require additional properties to be specified for RAW files
  89. Vector2 imageSize;
  90. if (!pHeightmap->getVector2("size", &imageSize))
  91. {
  92. GP_WARN("Invalid or missing 'size' attribute in heightmap defintion of terrain file: %s", terrainFile);
  93. SAFE_DELETE(p);
  94. return NULL;
  95. }
  96. // Read normalized height values from RAW file
  97. heightfield = HeightField::create(heightmap, (unsigned int)imageSize.x, (unsigned int)imageSize.y, 0, 1);
  98. }
  99. else
  100. {
  101. // Unsupported heightmap format
  102. GP_WARN("Unsupported heightmap format ('%s') in terrain definition file: %s", heightmap, terrainFile);
  103. SAFE_DELETE(p);
  104. return NULL;
  105. }
  106. }
  107. else
  108. {
  109. // Try to read 'heightmap' as a simple string property
  110. const char* heightmap = pTerrain->getString("heightmap");
  111. if (heightmap == NULL || strlen(heightmap) == 0)
  112. {
  113. GP_WARN("No 'heightmap' property supplied in terrain definition file: %s", terrainFile);
  114. SAFE_DELETE(p);
  115. return NULL;
  116. }
  117. ext = getExtension(heightmap);
  118. if (ext == "PNG")
  119. {
  120. // Read normalized height values from heightmap image
  121. heightfield = HeightField::create(heightmap, 0, 0, 0, 1);
  122. }
  123. else if (ext == "RAW")
  124. {
  125. GP_WARN("RAW heightmaps must be specified inside a heightmap block with width and height properties.");
  126. SAFE_DELETE(p);
  127. return NULL;
  128. }
  129. else
  130. {
  131. GP_WARN("Unsupported 'heightmap' format ('%s') in terrain definition file: %s.", heightmap, terrainFile);
  132. SAFE_DELETE(p);
  133. return NULL;
  134. }
  135. }
  136. // Read terrain 'size'
  137. if (pTerrain->exists("size"))
  138. {
  139. if (!pTerrain->getVector3("size", &terrainSize))
  140. {
  141. GP_WARN("Invalid 'size' value ('%s') in terrain definition file: %s", pTerrain->getString("size"), terrainFile);
  142. }
  143. }
  144. // Read terrain 'patch size'
  145. if (pTerrain->exists("patchSize"))
  146. {
  147. patchSize = pTerrain->getInt("patchSize");
  148. }
  149. // Read terrain 'detailLevels'
  150. if (pTerrain->exists("detailLevels"))
  151. {
  152. detailLevels = pTerrain->getInt("detailLevels");
  153. }
  154. // Read 'skirtScale'
  155. if (pTerrain->exists("skirtScale"))
  156. {
  157. skirtScale = pTerrain->getFloat("skirtScale");
  158. }
  159. // Read 'normalMap'
  160. normalMap = pTerrain->getString("normalMap");
  161. }
  162. if (heightfield == NULL)
  163. {
  164. GP_WARN("Failed to read heightfield heights for terrain: %s", terrainFile);
  165. SAFE_DELETE(p);
  166. return NULL;
  167. }
  168. if (terrainSize.isZero())
  169. {
  170. terrainSize.set(heightfield->getColumnCount(), getDefaultHeight(heightfield->getColumnCount(), heightfield->getRowCount()), heightfield->getRowCount());
  171. }
  172. if (patchSize <= 0 || patchSize > (int)heightfield->getColumnCount() || patchSize > (int)heightfield->getRowCount())
  173. {
  174. patchSize = std::min(heightfield->getRowCount(), std::min(heightfield->getColumnCount(), (unsigned int)DEFAULT_TERRAIN_PATCH_SIZE));
  175. }
  176. if (detailLevels <= 0)
  177. detailLevels = 1;
  178. if (skirtScale < 0)
  179. skirtScale = 0;
  180. // Compute terrain scale
  181. Vector3 scale(terrainSize.x / (heightfield->getColumnCount()-1), terrainSize.y, terrainSize.z / (heightfield->getRowCount()-1));
  182. // Create terrain
  183. Terrain* terrain = create(heightfield, scale, (unsigned int)patchSize, (unsigned int)detailLevels, skirtScale, normalMap, pTerrain);
  184. SAFE_DELETE(p);
  185. return terrain;
  186. }
  187. Terrain* Terrain::create(HeightField* heightfield, const Vector3& scale, unsigned int patchSize, unsigned int detailLevels, float skirtScale, const char* normalMapPath)
  188. {
  189. return create(heightfield, scale, patchSize, detailLevels, skirtScale, normalMapPath, NULL);
  190. }
  191. Terrain* Terrain::create(HeightField* heightfield, const Vector3& scale, unsigned int patchSize, unsigned int detailLevels, float skirtScale, const char* normalMapPath, Properties* properties)
  192. {
  193. GP_ASSERT(heightfield);
  194. unsigned int width = heightfield->getColumnCount();
  195. unsigned int height = heightfield->getRowCount();
  196. // Create the terrain object
  197. Terrain* terrain = new Terrain();
  198. terrain->_heightfield = heightfield;
  199. terrain->_localScale = scale;
  200. BoundingBox& bounds = terrain->_boundingBox;
  201. if (normalMapPath)
  202. terrain->_normalMap = Texture::Sampler::create(normalMapPath, true);
  203. float halfWidth = (width - 1) * 0.5f;
  204. float halfHeight = (height - 1) * 0.5f;
  205. unsigned int maxStep = (unsigned int)std::pow(2.0, (double)(detailLevels-1));
  206. // Create terrain patches
  207. unsigned int x1, x2, z1, z2;
  208. unsigned int row = 0, column = 0;
  209. for (unsigned int z = 0; z < height-1; z = z2, ++row)
  210. {
  211. z1 = z;
  212. z2 = std::min(z1 + patchSize, height-1);
  213. for (unsigned int x = 0; x < width-1; x = x2, ++column)
  214. {
  215. x1 = x;
  216. x2 = std::min(x1 + patchSize, width-1);
  217. // Create this patch
  218. TerrainPatch* patch = TerrainPatch::create(terrain, row, column, heightfield->getArray(), width, height, x1, z1, x2, z2, -halfWidth, -halfHeight, maxStep, skirtScale);
  219. terrain->_patches.push_back(patch);
  220. // Append the new patch's local bounds to the terrain local bounds
  221. bounds.merge(patch->getBoundingBox(false));
  222. }
  223. }
  224. // Read additional layer information from properties (if specified)
  225. if (properties)
  226. {
  227. // Parse terrain layers
  228. Properties* lp;
  229. int index = -1;
  230. while (lp = properties->getNextNamespace())
  231. {
  232. if (strcmp(lp->getNamespace(), "layer") == 0)
  233. {
  234. // If there is no explicitly specified index for this layer, assume it's the 'next' layer
  235. if (lp->exists("index"))
  236. index = lp->getInt("index");
  237. else
  238. ++index;
  239. const char* textureMap = NULL;
  240. const char* blendMap = NULL;
  241. Vector2 textureRepeat;
  242. int blendChannel = 0;
  243. int row = -1, column = -1;
  244. Vector4 temp;
  245. // Read layer textures
  246. Properties* t = lp->getNamespace("texture", true);
  247. if (t)
  248. {
  249. textureMap = t->getString("path");
  250. if (!t->getVector2("repeat", &textureRepeat))
  251. textureRepeat.set(1,1);
  252. }
  253. Properties* b = lp->getNamespace("blend", true);
  254. if (b)
  255. {
  256. blendMap = b->getString("path");
  257. const char* channel = b->getString("channel");
  258. if (channel && strlen(channel) > 0)
  259. {
  260. char c = std::toupper(channel[0]);
  261. if (c == 'R' || c == '0')
  262. blendChannel = 0;
  263. else if (c == 'G' || c == '1')
  264. blendChannel = 1;
  265. else if (c == 'B' || c == '2')
  266. blendChannel = 2;
  267. else if (c == 'A' || c == '3')
  268. blendChannel = 3;
  269. }
  270. }
  271. // Get patch row/columns that this layer applies to.
  272. if (lp->exists("row"))
  273. row = lp->getInt("row");
  274. if (lp->exists("column"))
  275. column = lp->getInt("column");
  276. if (!terrain->setLayer(index, textureMap, textureRepeat, blendMap, blendChannel, row, column))
  277. {
  278. GP_WARN("Failed to load terrain layer: %s", textureMap);
  279. }
  280. }
  281. }
  282. }
  283. // Load materials for all patches
  284. for (size_t i = 0, count = terrain->_patches.size(); i < count; ++i)
  285. terrain->_patches[i]->updateMaterial();
  286. return terrain;
  287. }
  288. void Terrain::setNode(Node* node)
  289. {
  290. if (_node != node)
  291. {
  292. if (_node)
  293. _node->removeListener(this);
  294. _node = node;
  295. if (_node)
  296. _node->addListener(this);
  297. _worldMatrixDirty = true;
  298. }
  299. }
  300. bool Terrain::setLayer(int index, const char* texturePath, const Vector2& textureRepeat, const char* blendPath, int blendChannel, int row, int column)
  301. {
  302. if (!texturePath)
  303. return false;
  304. // Set layer on applicable patches
  305. bool result = true;
  306. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  307. {
  308. TerrainPatch* patch = _patches[i];
  309. if ((row == -1 || patch->_row == row) && (column == -1 || patch->_column == column))
  310. {
  311. if (!patch->setLayer(index, texturePath, textureRepeat, blendPath, blendChannel))
  312. result = false;
  313. }
  314. }
  315. return result;
  316. }
  317. bool Terrain::isFlagSet(Flags flag) const
  318. {
  319. return (_flags & flag) == flag;
  320. }
  321. void Terrain::setFlag(Flags flag, bool on)
  322. {
  323. bool changed = false;
  324. if (on)
  325. {
  326. if ((_flags & flag) == 0)
  327. {
  328. _flags |= flag;
  329. changed = true;
  330. }
  331. }
  332. else
  333. {
  334. if ((_flags & flag) == flag)
  335. {
  336. _flags &= ~flag;
  337. changed = true;
  338. }
  339. }
  340. if (flag == DEBUG_PATCHES && changed)
  341. {
  342. // Dirty all materials since they need to be updated to support debug drawing
  343. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  344. _patches[i]->_materialDirty = true;
  345. }
  346. }
  347. unsigned int Terrain::getPatchCount() const
  348. {
  349. return _patches.size();
  350. }
  351. unsigned int Terrain::getVisiblePatchCount() const
  352. {
  353. unsigned int visibleCount = 0;
  354. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  355. {
  356. if (_patches[i]->isVisible())
  357. ++visibleCount;
  358. }
  359. return visibleCount;
  360. }
  361. unsigned int Terrain::getTriangleCount() const
  362. {
  363. unsigned int triangleCount = 0;
  364. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  365. {
  366. triangleCount += _patches[i]->getTriangleCount();
  367. }
  368. return triangleCount;
  369. }
  370. unsigned int Terrain::getVisibleTriangleCount() const
  371. {
  372. unsigned int triangleCount = 0;
  373. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  374. {
  375. triangleCount += _patches[i]->getVisibleTriangleCount();
  376. }
  377. return triangleCount;
  378. }
  379. const BoundingBox& Terrain::getBoundingBox() const
  380. {
  381. return _boundingBox;
  382. }
  383. void Terrain::draw(bool wireframe)
  384. {
  385. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  386. {
  387. _patches[i]->draw(wireframe);
  388. }
  389. }
  390. void Terrain::transformChanged(Transform* transform, long cookie)
  391. {
  392. _worldMatrixDirty = true;
  393. }
  394. const Matrix& Terrain::getWorldMatrix() const
  395. {
  396. if (_worldMatrixDirty)
  397. {
  398. _worldMatrixDirty = false;
  399. // Apply our attached node's world matrix
  400. if (_node)
  401. {
  402. _worldMatrix = _node->getWorldMatrix();
  403. }
  404. else
  405. {
  406. _worldMatrix.setIdentity();
  407. }
  408. // Factor in our local scaling
  409. _worldMatrix.scale(_localScale);
  410. }
  411. return _worldMatrix;
  412. }
  413. const Matrix& Terrain::getWorldViewProjectionMatrix() const
  414. {
  415. static Matrix worldViewProj;
  416. if (_node)
  417. Matrix::multiply(_node->getViewProjectionMatrix(), getWorldMatrix(), &worldViewProj);
  418. else
  419. worldViewProj = getWorldMatrix(); // no node, so nothing to get viewProjection from
  420. return worldViewProj;
  421. }
  422. // Returns the uppercase extension of a file
  423. std::string getExtension(const char* filename)
  424. {
  425. const char* str = strrchr(filename, '.');
  426. if (str == NULL)
  427. return NULL;
  428. std::string ext;
  429. size_t len = strlen(str);
  430. for (size_t i = 1; i < len; ++i)
  431. ext += std::toupper(str[i]);
  432. return ext;
  433. }
  434. float getDefaultHeight(unsigned int width, unsigned int height)
  435. {
  436. // When terrain height is not specified, we'll use a default height of ~ 0.3 of the image dimensions
  437. return ((width + height) * 0.5f) * DEFAULT_TERRAIN_HEIGHT_RATIO;
  438. }
  439. Terrain::HeightField::HeightField(unsigned int columns, unsigned int rows)
  440. : _array(NULL), _cols(columns), _rows(rows)
  441. {
  442. _array = new float[columns * rows];
  443. }
  444. Terrain::HeightField::~HeightField()
  445. {
  446. SAFE_DELETE_ARRAY(_array);
  447. }
  448. Terrain::HeightField* Terrain::HeightField::create(unsigned int columns, unsigned int rows)
  449. {
  450. return new HeightField(columns, rows);
  451. }
  452. /**
  453. * @script{ignore}
  454. */
  455. float normalizedHeightPacked(float r, float g, float b)
  456. {
  457. // This formula is intended for 24-bit packed heightmap images (that are generated
  458. // with gameplay-encoder. However, it is also compatible with normal grayscale
  459. // heightmap images, with an error of approximately 0.4%. This can be seen by
  460. // setting r=g=b=x and comparing the grayscale height expression to the packed
  461. // height expression: the error is 2^-8 + 2^-16 which is just under 0.4%.
  462. return (256.0f*r + g + 0.00390625f*b) / 65536.0f;
  463. }
  464. Terrain::HeightField* Terrain::HeightField::create(const char* imagePath, unsigned int width, unsigned int height, float minHeight, float maxHeight)
  465. {
  466. GP_ASSERT(imagePath);
  467. GP_ASSERT(maxHeight >= minHeight);
  468. // Validate input parameters
  469. size_t pathLength = strlen(imagePath);
  470. if (pathLength <= 4)
  471. {
  472. GP_WARN("Unrecognized file extension for heightfield image: %s.", imagePath);
  473. return NULL;
  474. }
  475. float heightScale = maxHeight - minHeight;
  476. HeightField* heightfield = NULL;
  477. // Load height data from image
  478. const char* ext = imagePath + (pathLength - 4);
  479. if (ext[0] == '.' && toupper(ext[1]) == 'P' && toupper(ext[2]) == 'N' && toupper(ext[3]) == 'G')
  480. {
  481. // Normal image
  482. Image* image = Image::create(imagePath);
  483. if (!image)
  484. return NULL;
  485. unsigned int pixelSize = 0;
  486. switch (image->getFormat())
  487. {
  488. case Image::RGB:
  489. pixelSize = 3;
  490. break;
  491. case Image::RGBA:
  492. pixelSize = 4;
  493. break;
  494. default:
  495. SAFE_RELEASE(image);
  496. GP_WARN("Unsupported pixel format for heightfield image: %s.", imagePath);
  497. return NULL;
  498. }
  499. // Calculate the heights for each pixel.
  500. heightfield = HeightField::create(image->getWidth(), image->getHeight());
  501. float* heights = heightfield->getArray();
  502. unsigned char* data = image->getData();
  503. int idx;
  504. for (int y = image->getHeight()-1, i = 0; y >= 0; --y)
  505. {
  506. for (unsigned int x = 0, w = image->getWidth(); x < w; ++x)
  507. {
  508. idx = (y*w + x) * pixelSize;
  509. heights[i++] = minHeight + normalizedHeightPacked(data[idx], data[idx + 1], data[idx + 2]) * heightScale;
  510. }
  511. }
  512. SAFE_RELEASE(image);
  513. }
  514. else if (ext[0] == '.' && toupper(ext[1]) == 'R' && toupper(ext[2]) == 'A' && toupper(ext[3]) == 'W')
  515. {
  516. // RAW image (headerless)
  517. if (width < 2 || height < 2 || maxHeight < 0)
  518. {
  519. GP_WARN("Invalid 'width', 'height' or 'maxHeight' parameter for RAW heightfield image: %s.", imagePath);
  520. return NULL;
  521. }
  522. // Load raw bytes
  523. int fileSize = 0;
  524. unsigned char* bytes = (unsigned char*)FileSystem::readAll(imagePath, &fileSize);
  525. if (bytes == NULL)
  526. {
  527. GP_WARN("Falied to read bytes from RAW heightfield image: %s.", imagePath);
  528. return NULL;
  529. }
  530. // Determine if the RAW file is 8-bit or 16-bit based on file size.
  531. int bits = (fileSize / (width * height)) * 8;
  532. if (bits != 8 && bits != 16)
  533. {
  534. GP_WARN("Invalid RAW file - must be 8-bit or 16-bit, but found neither: %s.", imagePath);
  535. SAFE_DELETE_ARRAY(bytes);
  536. return NULL;
  537. }
  538. heightfield = HeightField::create(width, height);
  539. float* heights = heightfield->getArray();
  540. // RAW files have an origin of bottom left, whereas our height array needs an origin of
  541. // top left, so we need to flip the Y as we write height values out.
  542. if (bits == 16)
  543. {
  544. // 16-bit (0-65535)
  545. int idx;
  546. for (int y = height-1, i = 0; y >= 0; --y)
  547. {
  548. for (unsigned int x = 0; x < width; ++x, ++i)
  549. {
  550. idx = (y * width + x) << 1;
  551. heights[i] = minHeight + ((bytes[idx] | (int)bytes[idx+1] << 8) / 65535.0f) * heightScale;
  552. }
  553. }
  554. }
  555. else
  556. {
  557. // 8-bit (0-255)
  558. for (int y = height-1, i = 0; y >= 0; --y)
  559. {
  560. for (unsigned int x = 0; x < width; ++x, ++i)
  561. {
  562. heights[i] = minHeight + (bytes[y * width + x] / 255.0f) * heightScale;
  563. }
  564. }
  565. }
  566. SAFE_DELETE_ARRAY(bytes);
  567. }
  568. else
  569. {
  570. GP_WARN("Unsupported heightfield image format: %s.", imagePath);
  571. }
  572. return heightfield;
  573. }
  574. float* Terrain::HeightField::getArray() const
  575. {
  576. return _array;
  577. }
  578. unsigned int Terrain::HeightField::getColumnCount() const
  579. {
  580. return _cols;
  581. }
  582. unsigned int Terrain::HeightField::getRowCount() const
  583. {
  584. return _rows;
  585. }
  586. }