/* * Copyright (C) 2021 Christopher J. Howard * * This file is part of Antkeeper source code. * * Antkeeper source code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper source code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper source code. If not, see . */ #include "relief-map.hpp" #include #include #include namespace cart { geom::mesh* map_elevation(const std::function& function, float scale, std::size_t subdivisions) { // Allocate terrain mesh geom::mesh* mesh = new geom::mesh(); // Determine vertex count and placement std::size_t columns = static_cast(std::pow(2, subdivisions)); std::size_t rows = columns; float uv_scale = 1.0f / static_cast(columns); //std::size_t vertex_count = (columns + 1) * (rows + 1); // Generate mesh vertices float3 position; float2 uv; for (std::size_t i = 0; i <= rows; ++i) { uv.y = static_cast(i) * uv_scale; position.z = (uv.y - 0.5f) * scale; for (std::size_t j = 0; j <= columns; ++j) { uv.x = static_cast(j) * uv_scale; position.x = (uv.x - 0.5f) * scale; position.y = function(uv.x, uv.y); mesh->add_vertex(position); } } // Function to eliminate duplicate edges std::map, geom::mesh::edge*> edge_map; auto add_or_find_edge = [&](geom::mesh::vertex* start, geom::mesh::vertex* end) -> geom::mesh::edge* { geom::mesh::edge* edge; if (auto it = edge_map.find({start->index, end->index}); it != edge_map.end()) { edge = it->second; } else { edge = mesh->add_edge(start, end); edge_map[{start->index, end->index}] = edge; edge_map[{end->index, start->index}] = edge->symmetric; } return edge; }; // Connect vertices with edges and faces const std::vector& vertices = mesh->get_vertices(); for (std::size_t i = 0; i < rows; ++i) { for (std::size_t j = 0; j < columns; ++j) { geom::mesh::vertex* a = vertices[i * (columns + 1) + j]; geom::mesh::vertex* b = vertices[(i + 1) * (columns + 1) + j]; geom::mesh::vertex* c = vertices[i * (columns + 1) + j + 1]; geom::mesh::vertex* d = vertices[(i + 1) * (columns + 1) + j + 1]; // +---+---+ // | \ | / | // |---+---| // | / | \ | // +---+---+ if ((j % 2) == (i % 2)) { geom::mesh::edge* ab = add_or_find_edge(a, b); geom::mesh::edge* bd = add_or_find_edge(b, d); geom::mesh::edge* da = add_or_find_edge(d, a); geom::mesh::edge* ca = add_or_find_edge(c, a); geom::mesh::edge* ad = da->symmetric; geom::mesh::edge* dc = add_or_find_edge(d, c); // a---c // | \ | // b---d mesh->add_face({ab, bd, da}); mesh->add_face({ca, ad, dc}); } else { geom::mesh::edge* ab = add_or_find_edge(a, b); geom::mesh::edge* bc = add_or_find_edge(b, c); geom::mesh::edge* ca = add_or_find_edge(c, a); geom::mesh::edge* cb = bc->symmetric; geom::mesh::edge* bd = add_or_find_edge(b, d); geom::mesh::edge* dc = add_or_find_edge(d, c); // a---c // | / | // b---d mesh->add_face({ab, bc, ca}); mesh->add_face({cb, bd, dc}); } } } return mesh; } } // namespace cart