mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 10:59:20 +02:00
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
159 lines
4.4 KiB
C++
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 ) );
|
|
}
|
|
}
|