mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-17 23:39:18 +02:00
117 lines
4.7 KiB
C++
117 lines
4.7 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/.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <glm/glm.hpp>
|
|
|
|
#include "editor/editorTerrain.hpp"
|
|
|
|
// Streams editable terrain chunks around the camera for an effectively unbounded world.
|
|
//
|
|
// Phase 1: keeps a ring of resident chunks (each an editor_terrain mesh) within a radius of the
|
|
// camera; chunks entering the radius are built, chunks leaving it are destroyed (the renderer's
|
|
// geometry GC reclaims their GPU memory). Heights are flat + a gentle procedural roll so streaming
|
|
// is observable. Phase 2 will add 16-bit on-disk chunk paging, per-chunk flag bits and persistence.
|
|
class terrain_streamer
|
|
{
|
|
public:
|
|
using chunk_key = std::pair<int, int>; // (cx, cz) chunk coordinate
|
|
|
|
terrain_streamer() = default;
|
|
|
|
void active(bool State) { m_active = State; }
|
|
bool active() const { return m_active; }
|
|
|
|
// per-chunk configuration (applied to chunks built from now on)
|
|
void configure(int Cells, float CellSize, int Radius, float BaseHeight, std::string const &Texture);
|
|
void simplify(bool Auto, float Error) { m_auto_optimize = Auto; m_simplify_error = Error; }
|
|
// safe to change while resident (only affects how far chunks load/unload)
|
|
void radius(int Radius) { m_radius = Radius < 0 ? 0 : Radius; }
|
|
// persist edited chunks to disk on unload, and load them back instead of regenerating
|
|
void persist(bool Enable) { m_persist = Enable; }
|
|
void directory(std::string const &Dir)
|
|
{
|
|
if (!Dir.empty() && Dir != m_dir)
|
|
{
|
|
m_dir = Dir;
|
|
m_known.clear(); // existence cache is per-folder; drop it when the folder changes
|
|
}
|
|
}
|
|
std::string const &directory() const { return m_dir; }
|
|
|
|
// loads/unloads chunks so the resident set matches the radius around CameraPos
|
|
void update(glm::dvec3 const &CameraPos);
|
|
// drops all resident chunks (e.g. when streaming is switched off), saving edits first
|
|
void clear();
|
|
// hard reset used when a new scenery loads: drops everything WITHOUT touching scene sections
|
|
// (the old region is being torn down, so its section pointers are already dangling)
|
|
void reset();
|
|
|
|
// appends raw pointers to every resident chunk (for sculpt / snap / optimize routing)
|
|
void collect(std::vector<editor_terrain *> &Out) const;
|
|
// resident chunk whose footprint covers (X,Z), or nullptr
|
|
editor_terrain *terrain_at(double X, double Z) const;
|
|
|
|
// authoring: create a flat chunk at (Cx,Cz), make it resident and persist it to disk
|
|
void add_chunk(int Cx, int Cz);
|
|
// authoring: delete the chunk at (Cx,Cz) from memory and disk
|
|
void remove_chunk(int Cx, int Cz);
|
|
// persist an externally-authored chunk (e.g. a manual grid chunk being handed over to streaming)
|
|
void save_chunk(int Cx, int Cz, editor_terrain const &Terrain);
|
|
// chunk coordinate covering (X,Z)
|
|
chunk_key key_for(double X, double Z) const { return key_at(X, Z); }
|
|
|
|
std::size_t resident() const { return m_chunks.size(); }
|
|
float chunk_world_size() const { return m_cells * m_cellsize; }
|
|
int cells() const { return m_cells; }
|
|
float cellsize() const { return m_cellsize; }
|
|
int radius() const { return m_radius; }
|
|
|
|
// writes every resident, edited chunk to disk (without unloading) - used on save
|
|
void flush();
|
|
|
|
private:
|
|
// per-chunk state bits cached so we don't stat the filesystem repeatedly
|
|
enum chunk_flag : uint8_t
|
|
{
|
|
cf_exists_on_disk = 1u << 0, // a saved 16-bit chunk file exists
|
|
};
|
|
|
|
chunk_key key_at(double X, double Z) const;
|
|
glm::dvec3 chunk_centre(int Cx, int Cz) const;
|
|
std::string chunk_path(int Cx, int Cz) const;
|
|
bool chunk_on_disk(chunk_key const &Key); // cached existence test
|
|
bool load_heights(int Cx, int Cz, std::vector<float> &Out) const; // reads a 16-bit chunk file
|
|
void save_heights(int Cx, int Cz, editor_terrain const &Terrain); // writes a 16-bit chunk file
|
|
|
|
bool m_active{false};
|
|
int m_cells{32};
|
|
float m_cellsize{2.0f};
|
|
int m_radius{2}; // chunks loaded around the camera (Chebyshev radius)
|
|
float m_baseheight{0.0f};
|
|
std::string m_texture;
|
|
bool m_auto_optimize{true};
|
|
float m_simplify_error{0.5f};
|
|
bool m_persist{true};
|
|
std::string m_dir{"editor_terrain"}; // folder for 16-bit chunk files
|
|
|
|
std::map<chunk_key, std::unique_ptr<editor_terrain>> m_chunks;
|
|
std::map<chunk_key, std::uint8_t> m_known; // cached per-chunk flag bits
|
|
};
|
|
|
|
// single, simulation-level streamer instance shared by the editor (authoring) and the scenery
|
|
// loader (so streamed terrain renders in every mode, including the driver). loaded from the
|
|
// `editorterrain` scenery directive and updated each frame with the active camera.
|
|
extern terrain_streamer EditorTerrain;
|