Terrain.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /*
  2. Copyright (c) 2013 Daniele Bartolini, Michele Rossi
  3. Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
  4. Permission is hereby granted, free of charge, to any person
  5. obtaining a copy of this software and associated documentation
  6. files (the "Software"), to deal in the Software without
  7. restriction, including without limitation the rights to use,
  8. copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. copies of the Software, and to permit persons to whom the
  10. Software is furnished to do so, subject to the following
  11. conditions:
  12. The above copyright notice and this permission notice shall be
  13. included in all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  16. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  19. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  21. OTHER DEALINGS IN THE SOFTWARE.
  22. */
  23. #include "Terrain.h"
  24. #include "Device.h"
  25. #include "Renderer.h"
  26. #include "MathUtils.h"
  27. #include "Log.h"
  28. #include "Vec2.h"
  29. #include "Interpolation.h"
  30. namespace crown
  31. {
  32. Terrain::Terrain() :
  33. mHeights(NULL),
  34. mMinHeight(-10.0f),
  35. mMaxHeight(10.0f),
  36. mVertices(NULL),
  37. mNormals(NULL),
  38. mTexCoords(NULL),
  39. mIndices(NULL)
  40. {
  41. }
  42. Terrain::~Terrain()
  43. {
  44. if (mHeights != NULL)
  45. {
  46. m_allocator.deallocate(mHeights);
  47. }
  48. m_allocator.deallocate(mVertices);
  49. m_allocator.deallocate(mNormals);
  50. m_allocator.deallocate(mTexCoords);
  51. m_allocator.deallocate(mIndices);
  52. }
  53. void Terrain::CreateTerrain(uint32_t xSize, uint32_t zSize, uint32_t tilePerMeter, float initialHeight)
  54. {
  55. mSizeX = xSize;
  56. mSizeZ = zSize;
  57. mTilePerMeter = tilePerMeter;
  58. float tileStep = +(float)mSizeX / ((float)mSizeX * (float)mTilePerMeter); // Tile step is the same for both x and z ;)
  59. mTilesInSizeX = ((float)mSizeX / tileStep);
  60. mTilesInSizeZ = ((float)mSizeZ / tileStep);
  61. mVerticesInSizeX = mTilesInSizeX + 1;
  62. mVerticesInSizeZ = mTilesInSizeZ + 1;
  63. Log::d("Vertices in size x/z: %d %d\n", mVerticesInSizeX, mVerticesInSizeZ);
  64. uint32_t heightsCount = mVerticesInSizeX * mVerticesInSizeZ;
  65. mHeights = (float*)m_allocator.allocate(heightsCount * sizeof(float));
  66. // Init heights
  67. for (uint32_t i = 0; i < heightsCount; i++)
  68. {
  69. mHeights[i] = initialHeight;
  70. }
  71. // Construct drawing data
  72. mVertices = (Vec3*)m_allocator.allocate(heightsCount * sizeof(Vec3)); // There are as many vertices as heights
  73. mVertexCount = heightsCount;
  74. mNormals = (Vec3*)m_allocator.allocate(heightsCount * sizeof(Vec3)); // Same as vertices
  75. mNormalCount = heightsCount;
  76. mTexCoords = (Vec2*)m_allocator.allocate(heightsCount * sizeof(Vec2)); // Same as vertices
  77. mTexCoordCount = heightsCount;
  78. mIndices = (uint16_t*)m_allocator.allocate(mTilesInSizeX * mTilesInSizeZ * 6 * sizeof(uint16_t)); //
  79. mIndexCount = mTilesInSizeX * mTilesInSizeZ * 6;
  80. // Populate vertex list (generate a grid lying on the xz-plane and facing upwards)
  81. float xStart = -(float)mSizeX * 0.5f;
  82. float zStart = +(float)mSizeZ * 0.5f;
  83. mOffsetX = xStart;
  84. mOffsetZ = zStart;
  85. uint32_t vIndex = 0; // Just because I'm lazy
  86. float xCurrent; // Keeps track of current x position
  87. float zCurrent = zStart; // Keeps track of current z position
  88. for (uint32_t z = 0; z < mVerticesInSizeZ; z++)
  89. {
  90. xCurrent = xStart;
  91. for (uint32_t x = 0; x < mVerticesInSizeX; x++)
  92. {
  93. mVertices[vIndex].x = xCurrent;
  94. mVertices[vIndex].y = mHeights[vIndex];
  95. mVertices[vIndex].z = zCurrent;
  96. mNormals[vIndex].x = 0.0f;
  97. mNormals[vIndex].y = 1.0f;
  98. mNormals[vIndex].z = 0.0f;
  99. mTexCoords[vIndex].x = (float)x;
  100. mTexCoords[vIndex].y = (float)z;
  101. vIndex++;
  102. xCurrent += tileStep;
  103. }
  104. zCurrent -= tileStep;
  105. }
  106. // Populate index list
  107. uint32_t iIndex = 0;
  108. for (uint32_t z = 0; z < mTilesInSizeZ; z++)
  109. {
  110. for (uint32_t x = 0; x < mTilesInSizeX; x++)
  111. {
  112. uint32_t firstRow = z * mVerticesInSizeX + x;
  113. uint32_t secondRow = (z + 1) * mVerticesInSizeX + x;
  114. mIndices[iIndex + 0] = firstRow;
  115. mIndices[iIndex + 1] = secondRow + 1;
  116. mIndices[iIndex + 2] = secondRow;
  117. mIndices[iIndex + 3] = firstRow;
  118. mIndices[iIndex + 4] = firstRow + 1;
  119. mIndices[iIndex + 5] = secondRow + 1;
  120. iIndex += 6;
  121. }
  122. }
  123. m_vertex_buffer = device()->renderer()->create_dynamic_vertex_buffer(mVertexCount, VF_XYZ_FLOAT_32, mVertices);
  124. m_normal_buffer = device()->renderer()->create_dynamic_vertex_buffer(mNormalCount, VF_XYZ_NORMAL_FLOAT_32, mNormals);
  125. m_tex_coord_buffer = device()->renderer()->create_vertex_buffer(mTexCoordCount, VF_UV_FLOAT_32, mTexCoords);
  126. m_index_buffer = device()->renderer()->create_index_buffer(mIndexCount, mIndices);
  127. }
  128. void Terrain::UpdateVertexBuffer(bool recomputeNormals)
  129. {
  130. uint32_t vIndex = 0;
  131. for (uint32_t z = 0; z < mVerticesInSizeZ; z++)
  132. {
  133. for (uint32_t x = 0; x < mVerticesInSizeX; x++)
  134. {
  135. mVertices[vIndex].y = mHeights[vIndex];
  136. vIndex++;
  137. }
  138. device()->renderer()->update_vertex_buffer(m_vertex_buffer, 0, mVertexCount, mVertices);
  139. }
  140. if (recomputeNormals)
  141. {
  142. for (uint32_t i = 0; i < mIndexCount; i += 3)
  143. {
  144. Vec3 normal;
  145. Vec3 v1;
  146. Vec3 v2;
  147. v1 = mVertices[mIndices[i + 0]] - mVertices[mIndices[i + 1]];
  148. v2 = mVertices[mIndices[i + 2]] - mVertices[mIndices[i + 1]];
  149. normal = v2.cross(v1).normalize();
  150. mNormals[mIndices[i + 0]] = normal;
  151. mNormals[mIndices[i + 1]] = normal;
  152. mNormals[mIndices[i + 2]] = normal;
  153. }
  154. device()->renderer()->update_vertex_buffer(m_normal_buffer, 0, mNormalCount, mNormals);
  155. }
  156. }
  157. float Terrain::GetHeightAt(uint32_t x, uint32_t z) const
  158. {
  159. if (x > mVerticesInSizeX) return 0.0f;
  160. if (z > mVerticesInSizeZ) return 0.0f;
  161. return mHeights[z * mVerticesInSizeX + x];
  162. }
  163. float Terrain::GetHeightAt(const Vec3& xyz) const
  164. {
  165. uint32_t x, z;
  166. WorldToHeight(xyz, x, z);
  167. return GetHeightAt(x, z);
  168. }
  169. void Terrain::SetHeightAt(uint32_t x, uint32_t z, float height)
  170. {
  171. if (x >= mVerticesInSizeX) return;
  172. if (z >= mVerticesInSizeZ) return;
  173. mHeights[z * mVerticesInSizeX + x] += height;
  174. mHeights[z * mVerticesInSizeX + x] = math::clamp_to_range(mMinHeight, mMaxHeight, mHeights[z * mVerticesInSizeX + x]);
  175. }
  176. void Terrain::SetHeightAt(const Vec3& xyz, float height)
  177. {
  178. uint32_t x, z;
  179. WorldToHeight(xyz, x, z);
  180. SetHeightAt(x + 0, z + 0, height);
  181. }
  182. void Terrain::WorldToHeight(const Vec3& xyz, uint32_t& x, uint32_t& z) const
  183. {
  184. Vec3 offsetted = xyz + Vec3(-mOffsetX, 0.0f, mOffsetZ);
  185. offsetted.z = (float)mSizeZ - offsetted.z;
  186. x = (uint32_t)offsetted.x;
  187. z = (uint32_t)offsetted.z;
  188. }
  189. bool Terrain::TraceRay(const Ray& ray, Triangle& result, Triangle& /*tri2*/, float& dist)
  190. {
  191. bool hit = false;
  192. float minDist = 9999999.0f;
  193. for (uint32_t i = 0; i < mIndexCount; i += 3)
  194. {
  195. Triangle tri(mVertices[mIndices[i + 0]], mVertices[mIndices[i + 1]], mVertices[mIndices[i + 2]]);
  196. float ret;
  197. Vec3 int32_tersectionPoint32_t;
  198. if (Intersection::test_ray_triangle(ray, tri, ret, int32_tersectionPoint32_t))
  199. {
  200. if (ret < minDist)
  201. {
  202. minDist = ret;
  203. result = tri;
  204. }
  205. hit = true;
  206. }
  207. }
  208. dist = minDist;
  209. return hit;
  210. }
  211. uint32_t Terrain::SnapToGrid(const Vec3& vertex)
  212. {
  213. float minDist = 9999999.0f;
  214. uint32_t indexToSnapped;
  215. // Find the snapped point32_t to input vertex
  216. for (uint32_t i = 0; i < mVertexCount; i++)
  217. {
  218. Vec3 tmp = mVertices[i];
  219. Vec3 vertex2 = vertex;
  220. tmp.y = vertex2.y = 0.0f;
  221. if (tmp.get_distance_to(vertex2) < minDist)
  222. {
  223. indexToSnapped = i;
  224. minDist = tmp.get_distance_to(vertex2);
  225. }
  226. }
  227. return indexToSnapped;
  228. }
  229. void Terrain::Render()
  230. {
  231. Renderer* renderer = device()->renderer();
  232. renderer->bind_vertex_buffer(m_vertex_buffer);
  233. renderer->bind_vertex_buffer(m_normal_buffer);
  234. renderer->bind_vertex_buffer(m_tex_coord_buffer);
  235. renderer->draw_triangles(m_index_buffer);
  236. }
  237. float Terrain::GaussDist(float x, float y, float sigma)
  238. {
  239. float gauss = 1.0f / math::TWO_PI * (sigma * sigma);
  240. float e = 2.71828183f;
  241. float exponent = ((x * x) + (y * y)) / (2.0f * (sigma * sigma));
  242. return gauss * pow(e, -exponent);
  243. }
  244. void Terrain::BuildBrush(uint32_t width, uint32_t height, float smooth)
  245. {
  246. mBrushWidth = width;
  247. mBrushHeight = height;
  248. float xStart = -(float)width * 0.5f;
  249. float yStart = -(float)height * 0.5f;
  250. float xCurrent = xStart;
  251. for (uint32_t i = 0; i <= width; i++)
  252. {
  253. float yCurrent = yStart;
  254. for (uint32_t j = 0; j <= height; j++)
  255. {
  256. mBrush[j * MAX_BRUSH_SIZE + i] = GaussDist(xCurrent, yCurrent, smooth);
  257. yCurrent += 1.0f;
  258. }
  259. xCurrent += 1.0f;
  260. }
  261. }
  262. void Terrain::PlotCircle(int32_t xx, int32_t yy, int32_t radius, int32_t i)
  263. {
  264. for (int32_t j = 0; j < 256 * 256; j++)
  265. {
  266. mBrush[j] = 0;
  267. }
  268. int32_t x, y;
  269. mBrushWidth = radius * 2;
  270. mBrushHeight = radius * 2;
  271. for (y = -radius; y <= radius; y++)
  272. for (x = -radius; x <= radius; x++)
  273. if ((x * x) + (y * y) <= (radius * radius))
  274. {
  275. float rDist = 1.0 - math::sqrt(x * x + y * y) / radius;
  276. if (i == 0)
  277. {
  278. mBrush[(y + yy) * MAX_BRUSH_SIZE + (x + xx)] = interpolation::linear(0.0f, 1.0f, rDist);
  279. }
  280. else if (i == 1)
  281. {
  282. mBrush[(y + yy) * MAX_BRUSH_SIZE + (x + xx)] = interpolation::cosine(0.0f, 1.0f, rDist);
  283. }
  284. else if (i == 2)
  285. {
  286. mBrush[(y + yy) * MAX_BRUSH_SIZE + (x + xx)] = interpolation::cubic(0.0f, 1.0f, rDist);
  287. }
  288. }
  289. }
  290. void Terrain::ApplyBrush(uint32_t x, uint32_t z, float scale)
  291. {
  292. uint32_t offsetX = mBrushWidth / 2;
  293. uint32_t offsetY = mBrushHeight / 2;
  294. for (uint32_t i = 0; i < mBrushWidth; i++)
  295. {
  296. for (uint32_t j = 0; j < mBrushHeight; j++)
  297. {
  298. SetHeightAt((x - offsetX) + i, (z - offsetY) + j, scale * mBrush[j * MAX_BRUSH_SIZE + i]);
  299. }
  300. }
  301. }
  302. void Terrain::ApplyBrush(const Vec3& xyz, float scale)
  303. {
  304. uint32_t x, z;
  305. WorldToHeight(xyz, x, z);
  306. ApplyBrush(x, z, scale);
  307. }
  308. } // namespace crown