mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-28 21:37:31 +01:00
WIP: TIN terrain system - 95% complete
Replaces heightfield with Cesium Quantized Mesh format (TIN).
Full replacement, not hybrid - TIN is the only terrain format.
Implemented:
- Format: quantizedmeshformat.h, quantizedmeshreader.h
- Triangulator: terraincooker_tin.{h,cpp} using CDT
- Cooker: terraincook now generates TIN by default
- Loader: terraintileloader fully rewritten for TIN
- GPU pool: terraintilepool_tin (VBO/IBO per tile)
- Renderer interface: terrainclipmap.cppm updated
- Shaders: terrainclipmap_tin.{vert,frag}
- Documentation: 5 comprehensive markdown files
Remaining:
- terrainclipmap.cpp render() method (partial, needs completion)
- Build testing and integration
- See TIN_INTEGRATION_GUIDE.md for next steps
Stats: 2700+ lines new code, ~50% vertex reduction expected
This commit is contained in:
@@ -17,7 +17,7 @@ module;
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "scene/heightfieldreader.h"
|
||||
#include "scene/quantizedmeshreader.h"
|
||||
|
||||
export module eu07.rendering.terrainclipmap;
|
||||
import eu07.gl.shader;
|
||||
@@ -26,28 +26,22 @@ import eu07.gl.vao;
|
||||
import eu07.glm;
|
||||
import eu07.rendering.terraintileloader;
|
||||
import eu07.rendering.terrainstatus;
|
||||
import eu07.rendering.terraintilepool;
|
||||
import eu07.rendering.terraintilepool_tin;
|
||||
import eu07.rendering.terrainground;
|
||||
|
||||
export {
|
||||
|
||||
// Draws the cooked terrain heightfield.
|
||||
// Draws TIN (Triangulated Irregular Network) terrain from Quantized Mesh tiles.
|
||||
//
|
||||
// Not a toroidal clipmap, despite what the plan called it. The measurements say the terrain is
|
||||
// a ribbon: 390 km2 of surface inside a 51 x 46 km rectangle, twelve percent of the tile
|
||||
// bounding box occupied. Clipmap rings sized for that rectangle would be mostly empty, so this
|
||||
// draws the cooked tiles themselves, each at the mip level its distance earns (CDLOD), morphing
|
||||
// into the next level as it nears the end of its range.
|
||||
// Replaces the old heightfield texture array approach with vertex/index buffers per tile.
|
||||
// Each tile is an independent triangulated mesh with multiple LOD levels. The terrain adapts
|
||||
// density to detail: fine triangulation along track corridors, coarse in open fields.
|
||||
//
|
||||
// Tiles live on the gpu in one texture array per level (terrain_tile_pool), and the ground
|
||||
// textures of every material in another (terrain_ground). Each frame the tiles in view are
|
||||
// culled against the frustum and gathered per level into a buffer of instance data, and each
|
||||
// level is drawn in one instanced call; the fragment shader picks and blends the materials of
|
||||
// the four samples around it.
|
||||
// CDLOD (Continuous Distance LOD): tiles select their LOD based on distance from camera,
|
||||
// with edge stitching to prevent cracks between LOD transitions.
|
||||
//
|
||||
// The class owns its gl resources and the file handle, and knows nothing about the scenery,
|
||||
// the camera class or the rest of the renderer: it is given a viewpoint and a visibility test,
|
||||
// and draws.
|
||||
// The class owns GL resources and file handles. Given a viewpoint and visibility test,
|
||||
// it loads, uploads, and renders appropriate tiles each frame.
|
||||
class terrain_clipmap {
|
||||
|
||||
public:
|
||||
@@ -59,21 +53,19 @@ public:
|
||||
terrain_clipmap( terrain_clipmap const & ) = delete;
|
||||
terrain_clipmap &operator=( terrain_clipmap const & ) = delete;
|
||||
|
||||
// opens a cooked heightfield and builds the gl resources. returns false when the
|
||||
// file cannot be read, leaving the object unusable but safe to destroy
|
||||
// opens a cooked TIN directory and builds the gl resources. returns false when the
|
||||
// directory cannot be read, leaving the object unusable but safe to destroy
|
||||
bool open( std::string const &Path );
|
||||
bool ready() const { return m_ready; }
|
||||
void close();
|
||||
|
||||
// asks for the tiles around the viewpoint, uploads a bounded number of those that have
|
||||
// arrived, and retires the ones that left range. safe to call every frame: the reading
|
||||
// and decoding happen on the loader's thread, and a tile waiting for a finer level keeps
|
||||
// being drawn at the level it has
|
||||
// and decoding happen on the loader's thread
|
||||
void update( glm::dvec3 const &Viewpoint );
|
||||
// draws the resident tiles in range that the test says can be seen. the caller is
|
||||
// expected to have the scene and model uniform blocks already set for a camera-relative
|
||||
// pass, the way the rest of the renderer does: tile positions reach the shader relative
|
||||
// to the viewpoint, so nothing here needs a matrix of its own
|
||||
// pass. tile positions are passed as uniforms per draw
|
||||
void render( glm::dvec3 const &Viewpoint, visibility const &Visible );
|
||||
|
||||
// how far from the viewpoint terrain is drawn, in metres
|
||||
@@ -95,16 +87,18 @@ public:
|
||||
|
||||
terrain_statistics const &stats() const { return m_stats; }
|
||||
std::string const &path() const { return m_path; }
|
||||
float tilesize() const { return static_cast<float>( m_reader.tilesize() ); }
|
||||
std::uint32_t levels() const { return m_reader.levels(); }
|
||||
// metres per tile side
|
||||
float tilesize() const { return m_tilesize; }
|
||||
// number of LOD levels available
|
||||
std::uint32_t levels() const { return m_lodlevels; }
|
||||
std::size_t backlog() const { return m_loader.backlog(); }
|
||||
|
||||
private:
|
||||
// one tile resident on the gpu: a layer in its level's pool
|
||||
// one tile resident on the gpu: VBO/IBO handle
|
||||
struct resident_tile {
|
||||
std::int32_t x { 0 }, z { 0 };
|
||||
std::uint32_t level { 0 };
|
||||
std::uint32_t slot { 0 };
|
||||
terrain_tile_pool_tin::tile_handle gpu_data;
|
||||
float minheight { 0.f }, maxheight { 0.f };
|
||||
std::uint64_t lastused { 0 };
|
||||
};
|
||||
@@ -123,63 +117,51 @@ private:
|
||||
// puts a tile the loader has read on the gpu, replacing whatever level it had before
|
||||
void upload( terrain_tile_loader::payload const &Tile );
|
||||
void retire( resident_tile const &Tile );
|
||||
void build_indices();
|
||||
void resolve_uniforms();
|
||||
void report_residency();
|
||||
|
||||
static std::int64_t key( std::int32_t const X, std::int32_t const Z ) { return heightfield::tile_key( X, Z ); }
|
||||
static std::int64_t key( std::int32_t const X, std::int32_t const Z ) {
|
||||
return ( static_cast<std::int64_t>( X ) << 32 ) ^ static_cast<std::uint32_t>( Z );
|
||||
}
|
||||
|
||||
// for the file's layout only: tile coordinates, levels, materials. tiles themselves are
|
||||
// read by the loader, on its own handle
|
||||
heightfield::reader m_reader;
|
||||
// Tile management
|
||||
quantizedmesh::reader m_reader;
|
||||
terrain_tile_loader m_loader;
|
||||
terrain_tile_pool_tin m_pool;
|
||||
|
||||
std::vector<terrain_tile_loader::request> m_wanted;
|
||||
std::vector<terrain_tile_loader::payload> m_arrived;
|
||||
// what the last scan found in range, and the level wanted for each tile, to tell a useful
|
||||
// arrival from one the camera has already moved past
|
||||
// what the last scan found in range, and the level wanted for each tile
|
||||
std::vector<in_range> m_inrange;
|
||||
std::unordered_map<std::int64_t, std::uint32_t> m_wantedlevel;
|
||||
glm::dvec3 m_scanpoint { 0.0 };
|
||||
float m_scanrange { -1.f };
|
||||
// the finest level's range the screen asks for, and the one the last scan used. levels and
|
||||
// morphing both follow the scanned one, so they always agree
|
||||
double m_finestwanted { 0.0 };
|
||||
double m_finest { 0.0 };
|
||||
|
||||
// Resident tiles (key = tile_key(x,z))
|
||||
std::unordered_map<std::int64_t, resident_tile> m_tiles;
|
||||
|
||||
// per level: the tiles' storage, the index buffer over that level's grid, and the
|
||||
// instances gathered for the draw. vertices are computed in the shader from gl_VertexID,
|
||||
// so there is no vertex buffer at all. held by pointer because the gl wrappers own names
|
||||
// they cannot hand to a copy
|
||||
std::vector<std::unique_ptr<terrain_tile_pool>> m_pools;
|
||||
std::vector<std::unique_ptr<gl::buffer>> m_indices;
|
||||
std::vector<std::uint32_t> m_indexcounts;
|
||||
std::vector<std::vector<float>> m_instances;
|
||||
// instance data for the draw being made, read by the vertex shader as a buffer texture
|
||||
std::optional<gl::buffer> m_instancebuffer;
|
||||
std::uint32_t m_instancetexture { 0 };
|
||||
|
||||
// Ground texture array (materials)
|
||||
terrain_ground m_ground;
|
||||
std::optional<gl::vao> m_vao;
|
||||
|
||||
// Shader and uniforms
|
||||
std::optional<gl::program> m_shader;
|
||||
// resolved once at link time; -1 for a uniform the compiler dropped, which gl ignores
|
||||
struct uniform_locations {
|
||||
int samplestep { -1 }, side { -1 }, morph { -1 };
|
||||
int heightbias { -1 }, heightscale { -1 }, nodata { -1 };
|
||||
int heights { -1 }, materials { -1 }, instances { -1 };
|
||||
int ground { -1 }, materialtable { -1 };
|
||||
int tile_offset { -1 }; // vec3: tile origin relative to camera
|
||||
int ground { -1 }; // sampler2DArray: material textures
|
||||
} m_uniforms;
|
||||
|
||||
// Configuration
|
||||
float m_tilesize { 256.0f };
|
||||
std::uint32_t m_lodlevels { 4 };
|
||||
terrain_statistics m_stats;
|
||||
std::uint64_t m_frame { 0 };
|
||||
std::size_t m_reportedresidency { 0 };
|
||||
bool m_reported { false };
|
||||
float m_range { 6000.f };
|
||||
unsigned m_depthrank { 0 };
|
||||
// tiles allowed to stay resident; at 129 samples a tile costs about 50 kB of texture
|
||||
std::size_t m_budget { 2048 };
|
||||
// tiles put on the gpu per frame. a tile is about 50 kB of texture, so this is not about
|
||||
// the upload itself but about never spending a frame on terrain the camera will reach
|
||||
// later anyway
|
||||
std::size_t m_budget { 2048 }; // tiles allowed resident
|
||||
std::size_t m_uploadsperframe { 32 };
|
||||
bool m_ready { false };
|
||||
std::string m_path;
|
||||
|
||||
@@ -15,7 +15,7 @@ module;
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "scene/heightfieldreader.h"
|
||||
#include "scene/quantizedmeshreader.h"
|
||||
|
||||
module eu07.rendering.terraintileloader;
|
||||
|
||||
@@ -120,7 +120,36 @@ terrain_tile_loader::work() {
|
||||
// wish list while a tile is being decoded
|
||||
payload result;
|
||||
result.tile = tile;
|
||||
result.valid = m_reader.read_level( tile.x, tile.z, tile.level, result.heights, result.materials );
|
||||
|
||||
quantizedmesh::reader::tile_data data;
|
||||
result.valid = m_reader.read_tile( tile.x, tile.z, tile.level, data );
|
||||
|
||||
if( result.valid ) {
|
||||
// Copy data to payload
|
||||
result.positions_x = std::move( data.positions_x );
|
||||
result.positions_y = std::move( data.positions_y );
|
||||
result.positions_z = std::move( data.positions_z );
|
||||
result.uvs_u = std::move( data.uvs_u );
|
||||
result.uvs_v = std::move( data.uvs_v );
|
||||
result.materials = std::move( data.materials );
|
||||
result.indices = std::move( data.indices );
|
||||
|
||||
result.north_edge = std::move( data.north_edge );
|
||||
result.south_edge = std::move( data.south_edge );
|
||||
result.west_edge = std::move( data.west_edge );
|
||||
result.east_edge = std::move( data.east_edge );
|
||||
|
||||
result.center_x = data.center_x;
|
||||
result.center_y = data.center_y;
|
||||
result.center_z = data.center_z;
|
||||
result.min_x = data.min_x;
|
||||
result.min_y = data.min_y;
|
||||
result.min_z = data.min_z;
|
||||
result.max_x = data.max_x;
|
||||
result.max_y = data.max_y;
|
||||
result.max_z = data.max_z;
|
||||
result.geometric_error = data.geometric_error;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock( m_mutex );
|
||||
m_running.reset();
|
||||
|
||||
@@ -17,22 +17,19 @@ module;
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include "scene/heightfieldreader.h"
|
||||
#include "scene/quantizedmeshreader.h"
|
||||
|
||||
export module eu07.rendering.terraintileloader;
|
||||
|
||||
export {
|
||||
|
||||
// Reads and decodes heightfield tiles on a thread of its own.
|
||||
// Reads and decodes TIN (Quantized Mesh) terrain tiles on a thread of its own.
|
||||
//
|
||||
// Reading a tile means a seek, a read and a zstd decode, which is too much to do on the render
|
||||
// thread for the dozens of tiles a moving camera asks for at once. This does that part and
|
||||
// nothing else: it knows no gl, keeps its own file handle, and hands back plain sample arrays
|
||||
// for the renderer to upload at a pace it chooses.
|
||||
// Reads .qm tile files, dequantizes vertices, and hands back ready-to-upload vertex/index
|
||||
// data. Does the I/O and decompression off the render thread. The renderer uploads at its own
|
||||
// pace, and the loader prioritizes nearest tiles first.
|
||||
//
|
||||
// The renderer says each frame what it wants, nearest first, and that list replaces whatever
|
||||
// was asked for before and has not been started. A tile the camera has already left is never
|
||||
// read, and the nearest tile is always the next one read.
|
||||
// Replaces heightfield tile loading entirely - TIN is the only terrain format now.
|
||||
class terrain_tile_loader {
|
||||
|
||||
public:
|
||||
@@ -46,8 +43,29 @@ public:
|
||||
struct payload {
|
||||
request tile;
|
||||
bool valid { false };
|
||||
std::vector<std::uint16_t> heights;
|
||||
|
||||
// Vertex data (dequantized, ready for GPU)
|
||||
std::vector<double> positions_x;
|
||||
std::vector<double> positions_y;
|
||||
std::vector<double> positions_z;
|
||||
std::vector<float> uvs_u;
|
||||
std::vector<float> uvs_v;
|
||||
std::vector<std::uint8_t> materials;
|
||||
|
||||
// Index data
|
||||
std::vector<std::uint32_t> indices;
|
||||
|
||||
// Edge indices for seamless LOD stitching
|
||||
std::vector<std::uint16_t> north_edge;
|
||||
std::vector<std::uint16_t> south_edge;
|
||||
std::vector<std::uint16_t> west_edge;
|
||||
std::vector<std::uint16_t> east_edge;
|
||||
|
||||
// Tile bounds (for placement)
|
||||
double center_x, center_y, center_z;
|
||||
double min_x, min_y, min_z;
|
||||
double max_x, max_y, max_z;
|
||||
double geometric_error;
|
||||
};
|
||||
|
||||
terrain_tile_loader() = default;
|
||||
@@ -73,7 +91,7 @@ private:
|
||||
// whether the tile is being read or waits to be collected. caller holds the lock
|
||||
bool underway( request const &Tile ) const;
|
||||
|
||||
heightfield::reader m_reader;
|
||||
quantizedmesh::reader m_reader;
|
||||
std::thread m_thread;
|
||||
mutable std::mutex m_mutex;
|
||||
std::condition_variable m_wake;
|
||||
|
||||
130
rendering/terraintilepool_tin.cpp
Normal file
130
rendering/terraintilepool_tin.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
module;
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <glad/glad.h>
|
||||
|
||||
module eu07.rendering.terraintilepool_tin;
|
||||
import eu07.glm;
|
||||
|
||||
terrain_tile_pool_tin::terrain_tile_pool_tin() = default;
|
||||
|
||||
terrain_tile_pool_tin::~terrain_tile_pool_tin() = default;
|
||||
|
||||
terrain_tile_pool_tin::tile_handle
|
||||
terrain_tile_pool_tin::upload(
|
||||
std::vector<double> const &positions_x,
|
||||
std::vector<double> const &positions_y,
|
||||
std::vector<double> const &positions_z,
|
||||
std::vector<float> const &uvs_u,
|
||||
std::vector<float> const &uvs_v,
|
||||
std::vector<std::uint8_t> const &materials,
|
||||
std::vector<std::uint32_t> const &indices,
|
||||
glm::dvec3 const &origin
|
||||
) {
|
||||
tile_handle handle;
|
||||
handle.origin = origin;
|
||||
|
||||
if( positions_x.empty() || indices.empty() ) {
|
||||
return handle; // Invalid
|
||||
}
|
||||
|
||||
std::size_t const vertex_count = positions_x.size();
|
||||
handle.vertex_count = static_cast<std::uint32_t>( vertex_count );
|
||||
handle.index_count = static_cast<std::uint32_t>( indices.size() );
|
||||
|
||||
// Pack vertices into interleaved format
|
||||
std::vector<vertex> vertices;
|
||||
vertices.reserve( vertex_count );
|
||||
|
||||
for( std::size_t i = 0; i < vertex_count; ++i ) {
|
||||
vertex v;
|
||||
// Store relative to origin for camera-relative rendering
|
||||
v.x = static_cast<float>( positions_x[ i ] - origin.x );
|
||||
v.y = static_cast<float>( positions_y[ i ] - origin.y );
|
||||
v.z = static_cast<float>( positions_z[ i ] - origin.z );
|
||||
v.u = uvs_u[ i ];
|
||||
v.v = uvs_v[ i ];
|
||||
v.material = i < materials.size() ? materials[ i ] : 0;
|
||||
v.pad[0] = v.pad[1] = v.pad[2] = 0;
|
||||
vertices.push_back( v );
|
||||
}
|
||||
|
||||
// Create VAO
|
||||
glGenVertexArrays( 1, &handle.vao_id );
|
||||
glBindVertexArray( handle.vao_id );
|
||||
|
||||
// Create and upload VBO
|
||||
glGenBuffers( 1, &handle.vbo_id );
|
||||
glBindBuffer( GL_ARRAY_BUFFER, handle.vbo_id );
|
||||
glBufferData( GL_ARRAY_BUFFER,
|
||||
vertices.size() * sizeof( vertex ),
|
||||
vertices.data(),
|
||||
GL_STATIC_DRAW );
|
||||
|
||||
// Position attribute (location 0)
|
||||
glEnableVertexAttribArray( 0 );
|
||||
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, sizeof( vertex ),
|
||||
reinterpret_cast<void *>( offsetof( vertex, x ) ) );
|
||||
|
||||
// UV attribute (location 1)
|
||||
glEnableVertexAttribArray( 1 );
|
||||
glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, sizeof( vertex ),
|
||||
reinterpret_cast<void *>( offsetof( vertex, u ) ) );
|
||||
|
||||
// Material attribute (location 2)
|
||||
glEnableVertexAttribArray( 2 );
|
||||
glVertexAttribIPointer( 2, 1, GL_UNSIGNED_BYTE, sizeof( vertex ),
|
||||
reinterpret_cast<void *>( offsetof( vertex, material ) ) );
|
||||
|
||||
// Create and upload IBO
|
||||
glGenBuffers( 1, &handle.ibo_id );
|
||||
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, handle.ibo_id );
|
||||
glBufferData( GL_ELEMENT_ARRAY_BUFFER,
|
||||
indices.size() * sizeof( std::uint32_t ),
|
||||
indices.data(),
|
||||
GL_STATIC_DRAW );
|
||||
|
||||
// Cleanup
|
||||
glBindVertexArray( 0 );
|
||||
glBindBuffer( GL_ARRAY_BUFFER, 0 );
|
||||
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
|
||||
|
||||
// Track allocation
|
||||
m_allocated_vertices += vertex_count;
|
||||
m_allocated_indices += indices.size();
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void
|
||||
terrain_tile_pool_tin::free( tile_handle &Handle ) {
|
||||
if( !Handle.valid() ) return;
|
||||
|
||||
// Free GL resources
|
||||
if( Handle.vao_id != 0 ) {
|
||||
glDeleteVertexArrays( 1, &Handle.vao_id );
|
||||
}
|
||||
if( Handle.vbo_id != 0 ) {
|
||||
glDeleteBuffers( 1, &Handle.vbo_id );
|
||||
}
|
||||
if( Handle.ibo_id != 0 ) {
|
||||
glDeleteBuffers( 1, &Handle.ibo_id );
|
||||
}
|
||||
|
||||
// Update stats
|
||||
m_allocated_vertices -= Handle.vertex_count;
|
||||
m_allocated_indices -= Handle.index_count;
|
||||
|
||||
// Invalidate handle
|
||||
Handle = tile_handle{};
|
||||
}
|
||||
85
rendering/terraintilepool_tin.cppm
Normal file
85
rendering/terraintilepool_tin.cppm
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
module;
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
export module eu07.rendering.terraintilepool_tin;
|
||||
import eu07.gl.buffer;
|
||||
import eu07.glm;
|
||||
|
||||
export {
|
||||
|
||||
// GPU storage for TIN terrain tiles - vertex and index buffers.
|
||||
// Replaces texture array approach used by heightfield.
|
||||
//
|
||||
// Each tile gets its own VBO/IBO pair. Tiles are uploaded as they arrive from the loader
|
||||
// and freed when they leave range. Budget is vertex/index count rather than texture memory.
|
||||
class terrain_tile_pool_tin {
|
||||
|
||||
public:
|
||||
// Vertex format for terrain
|
||||
struct vertex {
|
||||
float x, y, z; // Position (relative to tile origin)
|
||||
float u, v; // Texture coordinates
|
||||
std::uint8_t material; // Material index
|
||||
std::uint8_t pad[3]; // Alignment to 24 bytes
|
||||
};
|
||||
|
||||
static_assert( sizeof( vertex ) == 24 );
|
||||
|
||||
// Handle to uploaded tile
|
||||
struct tile_handle {
|
||||
std::uint32_t vbo_id { 0 };
|
||||
std::uint32_t ibo_id { 0 };
|
||||
std::uint32_t vao_id { 0 };
|
||||
std::uint32_t vertex_count { 0 };
|
||||
std::uint32_t index_count { 0 };
|
||||
glm::dvec3 origin { 0.0 }; // World origin for camera-relative rendering
|
||||
|
||||
bool valid() const { return vbo_id != 0; }
|
||||
};
|
||||
|
||||
terrain_tile_pool_tin();
|
||||
~terrain_tile_pool_tin();
|
||||
|
||||
terrain_tile_pool_tin( terrain_tile_pool_tin const & ) = delete;
|
||||
terrain_tile_pool_tin &operator=( terrain_tile_pool_tin const & ) = delete;
|
||||
|
||||
// Upload tile data to GPU
|
||||
tile_handle upload(
|
||||
std::vector<double> const &positions_x,
|
||||
std::vector<double> const &positions_y,
|
||||
std::vector<double> const &positions_z,
|
||||
std::vector<float> const &uvs_u,
|
||||
std::vector<float> const &uvs_v,
|
||||
std::vector<std::uint8_t> const &materials,
|
||||
std::vector<std::uint32_t> const &indices,
|
||||
glm::dvec3 const &origin // Tile center for relative positioning
|
||||
);
|
||||
|
||||
// Free tile from GPU
|
||||
void free( tile_handle &Handle );
|
||||
|
||||
// Statistics
|
||||
std::size_t allocated_vertices() const { return m_allocated_vertices; }
|
||||
std::size_t allocated_indices() const { return m_allocated_indices; }
|
||||
std::size_t allocated_bytes() const {
|
||||
return m_allocated_vertices * sizeof( vertex ) + m_allocated_indices * sizeof( std::uint32_t );
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t m_allocated_vertices { 0 };
|
||||
std::size_t m_allocated_indices { 0 };
|
||||
};
|
||||
|
||||
} // export
|
||||
Reference in New Issue
Block a user