💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
3.6 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "relief-map.hpp"
  20. #include <array>
  21. #include <cmath>
  22. #include <map>
  23. namespace cart
  24. {
  25. geom::mesh* map_elevation(const std::function<float(float, float)>& function, float scale, std::size_t subdivisions)
  26. {
  27. // Allocate terrain mesh
  28. geom::mesh* mesh = new geom::mesh();
  29. // Determine vertex count and placement
  30. std::size_t columns = static_cast<std::size_t>(std::pow(2, subdivisions));
  31. std::size_t rows = columns;
  32. float uv_scale = 1.0f / static_cast<float>(columns);
  33. //std::size_t vertex_count = (columns + 1) * (rows + 1);
  34. // Generate mesh vertices
  35. float3 position;
  36. float2 uv;
  37. for (std::size_t i = 0; i <= rows; ++i)
  38. {
  39. uv.y = static_cast<float>(i) * uv_scale;
  40. position.z = (uv.y - 0.5f) * scale;
  41. for (std::size_t j = 0; j <= columns; ++j)
  42. {
  43. uv.x = static_cast<float>(j) * uv_scale;
  44. position.x = (uv.x - 0.5f) * scale;
  45. position.y = function(uv.x, uv.y);
  46. mesh->add_vertex(position);
  47. }
  48. }
  49. // Function to eliminate duplicate edges
  50. std::map<std::array<std::size_t, 2>, geom::mesh::edge*> edge_map;
  51. auto add_or_find_edge = [&](geom::mesh::vertex* start, geom::mesh::vertex* end) -> geom::mesh::edge*
  52. {
  53. geom::mesh::edge* edge;
  54. if (auto it = edge_map.find({start->index, end->index}); it != edge_map.end())
  55. {
  56. edge = it->second;
  57. }
  58. else
  59. {
  60. edge = mesh->add_edge(start, end);
  61. edge_map[{start->index, end->index}] = edge;
  62. edge_map[{end->index, start->index}] = edge->symmetric;
  63. }
  64. return edge;
  65. };
  66. // Connect vertices with edges and faces
  67. const std::vector<geom::mesh::vertex*>& vertices = mesh->get_vertices();
  68. for (std::size_t i = 0; i < rows; ++i)
  69. {
  70. for (std::size_t j = 0; j < columns; ++j)
  71. {
  72. geom::mesh::vertex* a = vertices[i * (columns + 1) + j];
  73. geom::mesh::vertex* b = vertices[(i + 1) * (columns + 1) + j];
  74. geom::mesh::vertex* c = vertices[i * (columns + 1) + j + 1];
  75. geom::mesh::vertex* d = vertices[(i + 1) * (columns + 1) + j + 1];
  76. // +---+---+
  77. // | \ | / |
  78. // |---+---|
  79. // | / | \ |
  80. // +---+---+
  81. if ((j % 2) == (i % 2))
  82. {
  83. geom::mesh::edge* ab = add_or_find_edge(a, b);
  84. geom::mesh::edge* bd = add_or_find_edge(b, d);
  85. geom::mesh::edge* da = add_or_find_edge(d, a);
  86. geom::mesh::edge* ca = add_or_find_edge(c, a);
  87. geom::mesh::edge* ad = da->symmetric;
  88. geom::mesh::edge* dc = add_or_find_edge(d, c);
  89. // a---c
  90. // | \ |
  91. // b---d
  92. mesh->add_face({ab, bd, da});
  93. mesh->add_face({ca, ad, dc});
  94. }
  95. else
  96. {
  97. geom::mesh::edge* ab = add_or_find_edge(a, b);
  98. geom::mesh::edge* bc = add_or_find_edge(b, c);
  99. geom::mesh::edge* ca = add_or_find_edge(c, a);
  100. geom::mesh::edge* cb = bc->symmetric;
  101. geom::mesh::edge* bd = add_or_find_edge(b, d);
  102. geom::mesh::edge* dc = add_or_find_edge(d, c);
  103. // a---c
  104. // | / |
  105. // b---d
  106. mesh->add_face({ab, bc, ca});
  107. mesh->add_face({cb, bd, dc});
  108. }
  109. }
  110. }
  111. return mesh;
  112. }
  113. } // namespace cart