Terrain.cpp 17 KB

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