Terrain.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  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. {
  223. terrain->_normalMap = Texture::Sampler::create(normalMapPath, true);
  224. GP_ASSERT( terrain->_normalMap->getTexture()->getType() == Texture::TEXTURE_2D );
  225. }
  226. float halfWidth = (width - 1) * 0.5f;
  227. float halfHeight = (height - 1) * 0.5f;
  228. // Compute the maximum step size, which is a function of our lowest level of detail.
  229. // This determines how many vertices will be skipped per triange/quad on the lowest
  230. // level detail terrain patch.
  231. unsigned int maxStep = (unsigned int)std::pow(2.0, (double)(detailLevels-1));
  232. // Create terrain patches
  233. unsigned int x1, x2, z1, z2;
  234. unsigned int row = 0, column = 0;
  235. for (unsigned int z = 0; z < height-1; z = z2, ++row)
  236. {
  237. z1 = z;
  238. z2 = std::min(z1 + patchSize, height-1);
  239. for (unsigned int x = 0; x < width-1; x = x2, ++column)
  240. {
  241. x1 = x;
  242. x2 = std::min(x1 + patchSize, width-1);
  243. // Create this patch
  244. TerrainPatch* patch = TerrainPatch::create(terrain, terrain->_patches.size(), row, column, heightfield->getArray(), width, height, x1, z1, x2, z2, -halfWidth, -halfHeight, maxStep, skirtScale);
  245. terrain->_patches.push_back(patch);
  246. // Append the new patch's local bounds to the terrain local bounds
  247. bounds.merge(patch->getBoundingBox(false));
  248. }
  249. }
  250. // Read additional layer information from properties (if specified)
  251. if (properties)
  252. {
  253. // Parse terrain layers
  254. Properties* lp;
  255. int index = -1;
  256. while ((lp = properties->getNextNamespace()) != NULL)
  257. {
  258. if (strcmp(lp->getNamespace(), "layer") == 0)
  259. {
  260. // If there is no explicitly specified index for this layer, assume it's the 'next' layer
  261. if (lp->exists("index"))
  262. index = lp->getInt("index");
  263. else
  264. ++index;
  265. std::string textureMap;
  266. const char* textureMapPtr = NULL;
  267. std::string blendMap;
  268. const char* blendMapPtr = NULL;
  269. Vector2 textureRepeat;
  270. int blendChannel = 0;
  271. int row = -1, column = -1;
  272. Vector4 temp;
  273. // Read layer textures
  274. Properties* t = lp->getNamespace("texture", true);
  275. if (t)
  276. {
  277. if (t->getPath("path", &textureMap))
  278. {
  279. textureMapPtr = textureMap.c_str();
  280. }
  281. if (!t->getVector2("repeat", &textureRepeat))
  282. textureRepeat.set(1,1);
  283. }
  284. Properties* b = lp->getNamespace("blend", true);
  285. if (b)
  286. {
  287. if (b->getPath("path", &blendMap))
  288. {
  289. blendMapPtr = blendMap.c_str();
  290. }
  291. const char* channel = b->getString("channel");
  292. if (channel && strlen(channel) > 0)
  293. {
  294. char c = std::toupper(channel[0]);
  295. if (c == 'R' || c == '0')
  296. blendChannel = 0;
  297. else if (c == 'G' || c == '1')
  298. blendChannel = 1;
  299. else if (c == 'B' || c == '2')
  300. blendChannel = 2;
  301. else if (c == 'A' || c == '3')
  302. blendChannel = 3;
  303. }
  304. }
  305. // Get patch row/columns that this layer applies to.
  306. if (lp->exists("row"))
  307. row = lp->getInt("row");
  308. if (lp->exists("column"))
  309. column = lp->getInt("column");
  310. if (!terrain->setLayer(index, textureMapPtr, textureRepeat, blendMapPtr, blendChannel, row, column))
  311. {
  312. GP_WARN("Failed to load terrain layer: %s", textureMap.c_str());
  313. }
  314. }
  315. }
  316. }
  317. // Load materials for all patches
  318. for (size_t i = 0, count = terrain->_patches.size(); i < count; ++i)
  319. terrain->_patches[i]->updateMaterial();
  320. return terrain;
  321. }
  322. void Terrain::setNode(Node* node)
  323. {
  324. if (_node != node)
  325. {
  326. if (_node)
  327. {
  328. _node->removeListener(this);
  329. }
  330. _node = node;
  331. if (_node)
  332. {
  333. _node->addListener(this);
  334. }
  335. // Update patch node bindings
  336. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  337. {
  338. _patches[i]->updateNodeBindings();
  339. }
  340. _dirtyFlags |= DIRTY_FLAG_INVERSE_WORLD;
  341. }
  342. }
  343. void Terrain::transformChanged(Transform* transform, long cookie)
  344. {
  345. _dirtyFlags |= DIRTY_FLAG_INVERSE_WORLD;
  346. }
  347. const Matrix& Terrain::getInverseWorldMatrix() const
  348. {
  349. if (_dirtyFlags & DIRTY_FLAG_INVERSE_WORLD)
  350. {
  351. _dirtyFlags &= ~DIRTY_FLAG_INVERSE_WORLD;
  352. if (_node)
  353. _inverseWorldMatrix.set(_node->getWorldMatrix());
  354. else
  355. _inverseWorldMatrix = Matrix::identity();
  356. // Apply local scale and invert
  357. _inverseWorldMatrix.scale(_localScale);
  358. _inverseWorldMatrix.invert();
  359. }
  360. return _inverseWorldMatrix;
  361. }
  362. bool Terrain::setLayer(int index, const char* texturePath, const Vector2& textureRepeat, const char* blendPath, int blendChannel, int row, int column)
  363. {
  364. if (!texturePath)
  365. return false;
  366. // Set layer on applicable patches
  367. bool result = true;
  368. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  369. {
  370. TerrainPatch* patch = _patches[i];
  371. if ((row == -1 || (int)patch->_row == row) && (column == -1 || (int)patch->_column == column))
  372. {
  373. if (!patch->setLayer(index, texturePath, textureRepeat, blendPath, blendChannel))
  374. result = false;
  375. }
  376. }
  377. return result;
  378. }
  379. Node* Terrain::getNode() const
  380. {
  381. return _node;
  382. }
  383. bool Terrain::isFlagSet(Flags flag) const
  384. {
  385. return (_flags & flag) == flag;
  386. }
  387. void Terrain::setFlag(Flags flag, bool on)
  388. {
  389. bool changed = false;
  390. if (on)
  391. {
  392. if ((_flags & flag) == 0)
  393. {
  394. _flags |= flag;
  395. changed = true;
  396. }
  397. }
  398. else
  399. {
  400. if ((_flags & flag) == flag)
  401. {
  402. _flags &= ~flag;
  403. changed = true;
  404. }
  405. }
  406. if (flag == DEBUG_PATCHES && changed)
  407. {
  408. // Dirty all materials since they need to be updated to support debug drawing
  409. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  410. _patches[i]->setMaterialDirty();
  411. }
  412. }
  413. unsigned int Terrain::getPatchCount() const
  414. {
  415. return _patches.size();
  416. }
  417. TerrainPatch* Terrain::getPatch(unsigned int index) const
  418. {
  419. return _patches[index];
  420. }
  421. const BoundingBox& Terrain::getBoundingBox() const
  422. {
  423. return _boundingBox;
  424. }
  425. float Terrain::getHeight(float x, float z) const
  426. {
  427. // Calculate the correct x, z position relative to the heightfield data.
  428. float cols = _heightfield->getColumnCount();
  429. float rows = _heightfield->getRowCount();
  430. GP_ASSERT(cols > 0);
  431. GP_ASSERT(rows > 0);
  432. // Since the specified coordinates are in world space, we need to use the
  433. // inverse of our world matrix to transform the world x,z coords back into
  434. // local heightfield coordinates for indexing into the height array.
  435. Vector3 v = getInverseWorldMatrix() * Vector3(x, 0.0f, z);
  436. x = v.x + (cols - 1) * 0.5f;
  437. z = v.z + (rows - 1) * 0.5f;
  438. // Get the unscaled height value from the HeightField
  439. float height = _heightfield->getHeight(x, z);
  440. // Apply world scale to the height value
  441. if (_node)
  442. {
  443. Vector3 worldScale;
  444. _node->getWorldMatrix().getScale(&worldScale);
  445. height *= worldScale.y;
  446. }
  447. // Apply local scale
  448. height *= _localScale.y;
  449. return height;
  450. }
  451. unsigned int Terrain::draw(bool wireframe)
  452. {
  453. size_t visibleCount = 0;
  454. for (size_t i = 0, count = _patches.size(); i < count; ++i)
  455. {
  456. visibleCount += _patches[i]->draw(wireframe);
  457. }
  458. return visibleCount;
  459. }
  460. static float getDefaultHeight(unsigned int width, unsigned int height)
  461. {
  462. // When terrain height is not specified, we'll use a default height of ~ 0.3 of the image dimensions
  463. return ((width + height) * 0.5f) * DEFAULT_TERRAIN_HEIGHT_RATIO;
  464. }
  465. }