Terrain.cpp 18 KB

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