summaryrefslogtreecommitdiff
path: root/game/terrain.cpp
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2022-01-02 18:04:00 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2022-01-02 18:04:00 +0000
commitc2421c3ac2018faf5d47205ee979acec181d9672 (patch)
tree53651bfd3e5839c8334862f311466041da5f4d91 /game/terrain.cpp
parentUse Cache system to persist font rendering for Text (diff)
downloadilt-c2421c3ac2018faf5d47205ee979acec181d9672.tar.bz2
ilt-c2421c3ac2018faf5d47205ee979acec181d9672.tar.xz
ilt-c2421c3ac2018faf5d47205ee979acec181d9672.zip
Separate geographic data (GeoData) from its visual representation(s) (Terrain)
Diffstat (limited to 'game/terrain.cpp')
-rw-r--r--game/terrain.cpp145
1 files changed, 49 insertions, 96 deletions
diff --git a/game/terrain.cpp b/game/terrain.cpp
index 3089f3a..10a6215 100644
--- a/game/terrain.cpp
+++ b/game/terrain.cpp
@@ -1,5 +1,8 @@
#include "terrain.h"
+#include "game/geoData.h"
#include "gfx/models/texture.h"
+#include <algorithm>
+#include <array>
#include <cache.h>
#include <cstddef>
#include <filesystem>
@@ -8,116 +11,66 @@
#include <gfx/models/mesh.h>
#include <gfx/models/vertex.hpp>
#include <glm/glm.hpp>
+#include <iterator>
#include <location.hpp>
#include <maths.h>
-#include <random>
-#include <stb/stb_image.h>
+#include <utility>
+#include <vector>
-Terrain::Terrain() : grass {Texture::cachedTexture.get("grass.png")}, water {Texture::cachedTexture.get("water.png")}
+Terrain::Terrain(std::shared_ptr<GeoData> gd) :
+ geoData {std::move(gd)}, grass {Texture::cachedTexture.get("grass.png")}, water {Texture::cachedTexture.get(
+ "water.png")}
{
- constexpr auto size {241}; // Vertices
- constexpr auto offset {(size - 1) / 2};
- constexpr auto verticesCount = size * size;
- constexpr auto resolution = 10; // Grid size
-
- std::vector<Vertex> vertices;
- vertices.reserve(verticesCount + 4);
- vertices.resize(verticesCount, {{}, {}, {}});
-
- // Initial coordinates
- for (auto y = 0U; y < size; y += 1) {
- for (auto x = 0U; x < size; x += 1) {
- auto & vertex = vertices[x + (y * size)];
- vertex.pos
- = {resolution * (static_cast<int>(x) - offset), resolution * (static_cast<int>(y) - offset), -1.5};
- vertex.normal = up;
- vertex.texCoord = {x, y};
- }
- }
- // Add hills
- std::mt19937 gen(std::random_device {}());
- std::uniform_int_distribution<> rpos(2, size - 2);
- std::uniform_int_distribution<> rsize(10, 30);
- std::uniform_real_distribution<float> rheight(1, 3);
- for (int h = 0; h < 500;) {
- const glm::ivec2 hpos {rpos(gen), rpos(gen)};
- const glm::ivec2 hsize {rsize(gen), rsize(gen)};
- if (const auto lim1 = hpos - hsize; lim1.x > 0 && lim1.y > 0) {
- if (const auto lim2 = hpos + hsize; lim2.x < size && lim2.y < size) {
- const auto height = rheight(gen);
- const glm::ivec2 hsizesqrd {hsize.x * hsize.x, hsize.y * hsize.y};
- for (auto y = lim1.y; y < lim2.y; y += 1) {
- for (auto x = lim1.x; x < lim2.x; x += 1) {
- const auto dist {hpos - glm::ivec2 {x, y}};
- const glm::ivec2 distsqrd {dist.x * dist.x, dist.y * dist.y};
- const auto out {rdiv(sq(x - hpos.x), sq(hsize.x)) + rdiv(sq(y - hpos.y), sq(hsize.y))};
- if (out <= 1.0F) {
- auto & vertex
- = vertices[static_cast<std::size_t>(x) + (static_cast<std::size_t>(y) * size)];
- const auto m {1.F / (7.F * out - 8.F) + 1.F};
- vertex.pos.z += height * m;
- }
- }
- }
- h += 1;
- }
- }
- }
- finish(size, size, vertices);
+ generateMeshes();
}
-Terrain::Terrain(const std::string & fileName) :
- grass {Texture::cachedTexture.get("grass.png")}, water {Texture::cachedTexture.get("water.png")}
+void
+Terrain::generateMeshes()
{
- constexpr auto resolution {100};
-
- const Image map {fileName.c_str(), STBI_grey};
-
- std::vector<Vertex> vertices;
- vertices.reserve((map.width * map.height) + 4);
+ std::vector<unsigned int> indices;
+ const auto isize = geoData->getSize() - glm::uvec2 {1, 1};
+ indices.reserve(static_cast<std::size_t>(isize.x * isize.y) * 6);
- for (auto y = 0U; y < map.height; y += 1) {
- for (auto x = 0U; x < map.width; x += 1) {
- vertices.emplace_back(glm::vec3 {resolution * (x - (map.width / 2)), resolution * (y - (map.height / 2)),
- (static_cast<float>(map.data[x + (y * map.width)]) * 0.1F) - 1.5F},
- glm::vec2 {(x % 2) / 2.01, (y % 2) / 2.01}, up);
+ const auto limit = geoData->getLimit();
+ // Indices
+ constexpr std::array<glm::ivec2, 6> indices_offsets {{
+ {0, 0},
+ {1, 0},
+ {1, 1},
+ {0, 0},
+ {1, 1},
+ {0, 1},
+ }};
+ for (auto y = limit.first.y; y < limit.second.y; y += 1) {
+ for (auto x = limit.first.x; x < limit.second.x; x += 1) {
+ std::transform(indices_offsets.begin(), indices_offsets.end(), std::back_inserter(indices),
+ [this, x, y](const auto off) {
+ return geoData->at(x + off.x, y + off.y);
+ });
}
}
- finish(map.width, map.height, vertices);
-}
-
-void
-Terrain::finish(unsigned int width, unsigned int height, std::vector<Vertex> & vertices)
-{
- const auto tilesCount = (width - 1) * (height - 1);
- const auto trianglesCount = tilesCount * 2;
- const auto indicesCount = trianglesCount * 3;
- std::vector<unsigned int> indices;
- indices.reserve(indicesCount + 6);
- // Indices
- for (auto y = 0U; y < height - 1; y += 1) {
- for (auto x = 0U; x < width - 1; x += 1) {
- indices.push_back(x + (y * width));
- indices.push_back((x + 1) + (y * width));
- indices.push_back((x + 1) + ((y + 1) * width));
- indices.push_back(x + (y * width));
- indices.push_back((x + 1) + ((y + 1) * width));
- indices.push_back(x + ((y + 1) * width));
+ const auto nodes = geoData->getNodes();
+ const auto scale = geoData->getScale();
+ std::vector<Vertex> vertices;
+ vertices.reserve(nodes.size());
+ // Positions
+ for (auto y = limit.first.y; y <= limit.second.y; y += 1) {
+ for (auto x = limit.first.x; x <= limit.second.x; x += 1) {
+ const glm::vec2 xy {x, y};
+ vertices.emplace_back((xy * scale) ^ nodes[geoData->at(x, y)].height, xy, ::up);
}
}
// Normals
- auto v = [&vertices](unsigned int width, unsigned int x, unsigned int y) -> Vertex & {
- return vertices[x + (y * width)];
- };
-
- for (auto y = 1U; y < height - 1; y += 1) {
- for (auto x = 1U; x < width - 1; x += 1) {
- const auto a = v(width, x - 1, y).pos;
- const auto b = v(width, x, y - 1).pos;
- const auto c = v(width, x + 1, y).pos;
- const auto d = v(width, x, y + 1).pos;
- v(width, x, y).normal = -glm::normalize(glm::cross(b - d, a - c));
+ const glm::uvec2 size = geoData->getSize();
+ for (auto y = limit.first.y + 1; y < limit.second.y; y += 1) {
+ for (auto x = limit.first.x + 1; x < limit.second.x; x += 1) {
+ const auto n {geoData->at(x, y)};
+ const auto a = vertices[n - 1].pos;
+ const auto b = vertices[n - size.x].pos;
+ const auto c = vertices[n + 1].pos;
+ const auto d = vertices[n + size.x].pos;
+ vertices[n].normal = -glm::normalize(glm::cross(b - d, a - c));
}
}
meshes.create<Mesh>(vertices, indices);