17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 10:59:20 +02:00
Files
maszyna/rendering/terraintileloader.cpp
maj00r 5f34d68e6f 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
2026-09-17 23:02:13 +02:00

159 lines
4.4 KiB
C++

/*
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 <cstddef>
#include <mutex>
#include <string>
#include <thread>
#include <utility>
#include <vector>
#include "scene/quantizedmeshreader.h"
module eu07.rendering.terraintileloader;
terrain_tile_loader::~terrain_tile_loader() {
close();
}
bool
terrain_tile_loader::open( std::string const &Path ) {
close();
if( false == m_reader.open( Path ) ) { return false; }
m_stop = false;
m_thread = std::thread( &terrain_tile_loader::work, this );
return true;
}
void
terrain_tile_loader::close() {
if( true == m_thread.joinable() ) {
{
std::lock_guard<std::mutex> lock( m_mutex );
m_stop = true;
}
m_wake.notify_all();
m_thread.join();
}
std::lock_guard<std::mutex> lock( m_mutex );
m_pending.clear();
m_done.clear();
m_running.reset();
m_reader.close();
}
bool
terrain_tile_loader::underway( request const &Tile ) const {
if( ( m_running.has_value() ) && ( *m_running == Tile ) ) { return true; }
return std::any_of(
m_done.begin(), m_done.end(),
[ &Tile ]( payload const &Done ) { return Done.tile == Tile; } );
}
void
terrain_tile_loader::want( std::vector<request> const &Requests ) {
{
std::lock_guard<std::mutex> lock( m_mutex );
m_pending.clear();
for( auto const &tile : Requests ) {
if( false == underway( tile ) ) {
m_pending.push_back( tile );
}
}
}
m_wake.notify_one();
}
std::size_t
terrain_tile_loader::collect( std::vector<payload> &Out, std::size_t const Count ) {
std::unique_lock<std::mutex> lock( m_mutex );
std::size_t moved { 0 };
while( ( moved < Count ) && ( false == m_done.empty() ) ) {
Out.emplace_back( std::move( m_done.front() ) );
m_done.pop_front();
++moved;
}
lock.unlock();
if( moved > 0 ) {
// room was made; the thread may be waiting for it
m_wake.notify_one();
}
return moved;
}
std::size_t
terrain_tile_loader::backlog() const {
std::lock_guard<std::mutex> lock( m_mutex );
return m_pending.size() + m_done.size() + ( m_running.has_value() ? 1 : 0 );
}
void
terrain_tile_loader::work() {
while( true ) {
request tile;
{
std::unique_lock<std::mutex> lock( m_mutex );
m_wake.wait( lock, [ this ]() {
return m_stop || ( ( false == m_pending.empty() ) && ( m_done.size() < donelimit ) ); } );
if( true == m_stop ) { return; }
tile = m_pending.front();
m_pending.pop_front();
m_running = tile;
}
// the read itself happens outside the lock, so the render thread can replace the
// wish list while a tile is being decoded
payload result;
result.tile = tile;
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();
m_done.emplace_back( std::move( result ) );
}
}