Refactor generators
This commit is contained in:
parent
b7669df9ed
commit
5ac3a0037a
13
TODO.md
13
TODO.md
|
@ -29,13 +29,13 @@
|
|||
- [x] Offset
|
||||
- [ ] Rotation
|
||||
- [~] Planet
|
||||
- Render
|
||||
- [x] CubeSphere
|
||||
- [~] CubeSphere
|
||||
- [ ] Area corrected CubeSphere
|
||||
- [ ] Corrected Normals
|
||||
- [ ] Surface curvature
|
||||
- [ ] Curvature avare frustum
|
||||
- [ ] Healpix
|
||||
- [ ] Sphere
|
||||
- [ ] Healpix
|
||||
- [ ] Surface features
|
||||
- [ ] Biomes
|
||||
- https://imgur.com/kM8b5Zq
|
||||
|
@ -78,7 +78,8 @@
|
|||
- [ ] Environment mapping
|
||||
- [ ] Deferred
|
||||
- [ ] Cascaded shadow maps
|
||||
- [ ] RayCast
|
||||
- [ ] Vulkan
|
||||
- [ ] Ray Tracing
|
||||
- [~] Transparency
|
||||
- [x] Float precision problem
|
||||
|
||||
|
@ -98,5 +99,7 @@
|
|||
- [ ] Render with glBufferSubData
|
||||
- [x] Frustum Culling
|
||||
- [~] Occlusion Culling
|
||||
- Primitive raycast
|
||||
- [x] Primitive raycast
|
||||
- [ ] Iterator ray
|
||||
- [ ] Cast from chunk center
|
||||
- [x] Document
|
|
@ -15,11 +15,13 @@ namespace contouring {
|
|||
std::get<0>(it_a->second.first) = area->second->getOffset();
|
||||
std::get<1>(it_a->second.first) = area->second->getChunks().getRadius() * static_cast<long long>(CHUNK_LENGTH);
|
||||
const auto centerV = pos - std::get<0>(it_a->second.first).as_voxel();
|
||||
if (auto planet = std::get_if<world::Generator::Properties::planet>(
|
||||
&area->second->getGenerator().getProperties().shape)) {
|
||||
const auto dist = glm::max_axis(glm::abs(centerV));
|
||||
const auto surface = planet->height * planet->surface_roughness;
|
||||
std::get<2>(it_a->second.first) = std::clamp((dist - surface) / (std::get<1>(it_a->second.first) - surface), -0.1f, 1.f);
|
||||
{
|
||||
const auto params = area->second->getParams().properties;
|
||||
if (auto planet = std::get_if<world::generator::CubicPlanet::Params>(¶ms)) {
|
||||
const auto dist = glm::max_axis(glm::abs(centerV));
|
||||
const auto surface = planet->height * planet->surface_roughness;
|
||||
std::get<2>(it_a->second.first) = std::clamp((dist - surface) / (std::get<1>(it_a->second.first) - surface), -0.1f, 1.f);
|
||||
}
|
||||
}
|
||||
const auto center = glm::divide(centerV);
|
||||
auto &bfs = it_a->second.second;
|
||||
|
|
|
@ -136,11 +136,13 @@ namespace contouring {
|
|||
std::get<0>(it_a->second.first) = area->second->getOffset();
|
||||
std::get<1>(it_a->second.first) = area->second->getChunks().getRadius() * static_cast<long long>(CHUNK_LENGTH);
|
||||
const auto centerV = pos - std::get<0>(it_a->second.first).as_voxel();
|
||||
if (auto planet = std::get_if<world::Generator::Properties::planet>(
|
||||
&area->second->getGenerator().getProperties().shape)) {
|
||||
const auto dist = glm::max_axis(glm::abs(centerV));
|
||||
const auto surface = planet->height * (1.1+planet->surface_roughness);
|
||||
std::get<2>(it_a->second.first) = std::clamp<float>((dist - surface) / (std::get<1>(it_a->second.first) - surface), -0.1f, 1.f);
|
||||
{
|
||||
const auto params = area->second->getParams().properties;
|
||||
if (auto planet = std::get_if<world::generator::CubicPlanet::Params>(¶ms)) {
|
||||
const auto dist = glm::max_axis(glm::abs(centerV));
|
||||
const auto surface = planet->height * (1.1+planet->surface_roughness);
|
||||
std::get<2>(it_a->second.first) = std::clamp<float>((dist - surface) / (std::get<1>(it_a->second.first) - surface), -0.1f, 1.f);
|
||||
}
|
||||
}
|
||||
const auto center = glm::divide(centerV);
|
||||
auto &bfs = it_a->second.second;
|
||||
|
|
|
@ -96,7 +96,7 @@ namespace contouring {
|
|||
void FlatSurroundingBox::render(const surrounding::faces &surrounding, std::vector<buffer::PackedVertexData> &vertices) {
|
||||
const auto center = surrounding[surrounding::CENTER];
|
||||
vertices.clear();
|
||||
for (ushort i = 0; i < world::CHUNK_SIZE; i++) {
|
||||
for (ushort i = 0; i < CHUNK_SIZE; i++) {
|
||||
if (center->get(i).is_solid()) {
|
||||
Faces faces = !center->get(i).is_full() ? Faces::All :
|
||||
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Right)) & Faces::Right) |
|
||||
|
|
|
@ -27,15 +27,14 @@ namespace contouring::box {
|
|||
};
|
||||
|
||||
static void addQuad(std::vector<buffer::PackedVertexData> & out, glm::vec3 position, ushort material, Face face, glm::vec3 size) {
|
||||
constexpr auto HALF_MANTISSA = 10;
|
||||
for (auto vertex : g_quad_vertices) {
|
||||
const auto p = glm::vec3(g_cube_rotate[static_cast<int>(face)] * glm::vec4(vertex, 1)) * size + position;
|
||||
out.emplace_back(meshopt_quantizeHalf(p.x), meshopt_quantizeHalf(p.y),
|
||||
meshopt_quantizeHalf(p.z), material,
|
||||
meshopt_quantizeHalf(g_cube_normals[static_cast<int>(face)].x), meshopt_quantizeHalf(g_cube_normals[static_cast<int>(face)].y),
|
||||
meshopt_quantizeHalf(g_cube_normals[static_cast<int>(face)].z));
|
||||
}
|
||||
for (auto vertex : g_quad_vertices) {
|
||||
const auto p = glm::vec3(g_cube_rotate[static_cast<int>(face)] * glm::vec4(vertex, 1)) * size + position;
|
||||
out.emplace_back(meshopt_quantizeHalf(p.x), meshopt_quantizeHalf(p.y),
|
||||
meshopt_quantizeHalf(p.z), material,
|
||||
meshopt_quantizeHalf(g_cube_normals[static_cast<int>(face)].x), meshopt_quantizeHalf(g_cube_normals[static_cast<int>(face)].y),
|
||||
meshopt_quantizeHalf(g_cube_normals[static_cast<int>(face)].z));
|
||||
}
|
||||
}
|
||||
|
||||
static void addCube(std::vector<buffer::PackedVertexData>& out, glm::vec3 position, uint material, Faces faces = Faces::All, glm::vec3 size = glm::vec3(1)) {
|
||||
if (faces && Faces::Right)
|
||||
|
|
|
@ -70,4 +70,9 @@ namespace glm {
|
|||
constexpr T inline max_axis(const vec<3, T> &v) {
|
||||
return std::max({v.x, v.y, v.z});
|
||||
}
|
||||
ivec3 inline inormalize(const ivec3 &v) {
|
||||
const auto a = glm::abs(v);
|
||||
return a.x >= a.y ? (a.x >= a.z ? ivec3(glm::sign(v.x), 0, 0) : ivec3(0, 0, glm::sign(v.z))) :
|
||||
(a.y >= a.z ? ivec3(0, glm::sign(v.y), 0) : ivec3(0, 0, glm::sign(v.z)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,8 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
ImGui::SameLine();
|
||||
if(options.renderer.main.curvature) {
|
||||
changeRenderer |= ImGui::Checkbox("Depth", &options.renderer.main.curv_depth);
|
||||
if(ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("Planets may look way bigger than expected without it");
|
||||
} else {
|
||||
ImGui::TextDisabled("Depth");
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <shared_mutex_guarded.h>
|
||||
using namespace libguarded;
|
||||
#include "region/index.hpp"
|
||||
#include "Generator.hpp"
|
||||
#include "generator.hpp"
|
||||
#include "../data/geometry/IBox.hpp"
|
||||
|
||||
namespace world {
|
||||
|
@ -34,11 +34,11 @@ namespace world {
|
|||
struct params {
|
||||
voxel_pos center;
|
||||
int radius;
|
||||
Generator::Properties properties;
|
||||
generator::params properties;
|
||||
};
|
||||
|
||||
/// radius: size in chunk (length = radius * 2 + 1)
|
||||
Area(const params& p): center(p.center), chunks(p.radius), generator(p.properties) { }
|
||||
Area(const params& p): center(p.center), chunks(p.radius), generator(generator::load(p.properties)), generator_properties(p.properties) { }
|
||||
|
||||
inline const area_pos &getOffset() const { return center; }
|
||||
inline geometry::IBox getBounding() const {
|
||||
|
@ -59,9 +59,9 @@ namespace world {
|
|||
std::shared_ptr<Region> getRegion(const std::string& folderPath, const area_<region_pos> &);
|
||||
shared_guarded<regions_t>::handle getRegions() { return regions.lock(); }
|
||||
|
||||
inline Generator &getGenerator() { return generator; }
|
||||
inline const std::unique_ptr<generator::Abstract> &getGenerator() { return generator; }
|
||||
|
||||
inline params getParams() const { return params{center.as_voxel(), chunks.getRadius(), generator.getProperties()}; }
|
||||
inline params getParams() const { return params{center.as_voxel(), chunks.getRadius(), generator_properties}; }
|
||||
|
||||
private:
|
||||
area_pos center;
|
||||
|
@ -70,6 +70,7 @@ namespace world {
|
|||
ChunkContainer chunks;
|
||||
shared_guarded<regions_t> regions;
|
||||
|
||||
Generator generator;
|
||||
std::unique_ptr<generator::Abstract> generator;
|
||||
const generator::params generator_properties; //MAYBE: useless copy
|
||||
};
|
||||
}
|
|
@ -1,35 +1,12 @@
|
|||
#include "Chunk.hpp"
|
||||
|
||||
#include "materials.hpp"
|
||||
#include <algorithm>
|
||||
#include "../data/math.hpp"
|
||||
|
||||
using namespace world;
|
||||
|
||||
Chunk::Chunk(const chunk_pos& pos, Generator& rnd) {
|
||||
const auto &p = rnd.getProperties();
|
||||
if(!(std::holds_alternative<Generator::Properties::cheese>(p.shape) || std::holds_alternative<Generator::Properties::planet>(p.shape)))
|
||||
return;
|
||||
|
||||
const auto &cheese = std::holds_alternative<Generator::Properties::cheese>(p.shape) ? std::get<Generator::Properties::cheese>(p.shape) :
|
||||
std::get<Generator::Properties::planet>(p.shape);
|
||||
|
||||
const auto [densitySet, materialSet] = rnd.getChunk(pos, CHUNK_LENGTH);
|
||||
const auto verticalDensity = [p, pos](glm::idx i){
|
||||
if(const auto planet = std::get_if<Generator::Properties::planet>(&p.shape)) {
|
||||
const auto heightRatio = static_cast<float>(glm::max_axis(glm::abs(glm::multiply(pos) + glm::llvec3(glm::fromIdx(i)))) - planet->height) / planet->height;
|
||||
return heightRatio / (heightRatio >= 0 ? planet->surface_roughness : planet->cave_depth);
|
||||
}
|
||||
return 0.f;
|
||||
};
|
||||
for (size_t i = 0; i < CHUNK_SIZE; i++) {
|
||||
const auto density = std::clamp((densitySet[i] + cheese.density - verticalDensity(i)) * cheese.granularity, 0.f, 1.f) * Voxel::DENSITY_MAX;
|
||||
const auto material = density > 0 ? 1 + std::clamp(static_cast<int>(std::lrint((materialSet[i] + 1) / 2 * (materials::count - 2))),
|
||||
0, materials::count - 2) : 0; //NOTE: map (approx -1, 1) to (1, mat_max)
|
||||
voxels[i] = Voxel(material, density);
|
||||
}
|
||||
rnd.free(densitySet);
|
||||
rnd.free(materialSet);
|
||||
Chunk::Chunk(const chunk_pos& pos, const std::unique_ptr<generator::Abstract>& rnd) {
|
||||
rnd->generate(pos, voxels);
|
||||
}
|
||||
#include <iostream>
|
||||
Chunk::Chunk(std::istream& str, bool rle) {
|
||||
|
|
|
@ -2,23 +2,20 @@
|
|||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include "Generator.hpp"
|
||||
#include "generator.hpp"
|
||||
#include "Voxel.hpp"
|
||||
#include "../data/geometry/Faces.hpp"
|
||||
#include "../data/math.hpp"
|
||||
|
||||
/// Chunk length
|
||||
namespace world {
|
||||
const auto CHUNK_LENGTH2 = CHUNK_LENGTH * CHUNK_LENGTH;
|
||||
const auto CHUNK_SIZE = CHUNK_LENGTH2 * CHUNK_LENGTH;
|
||||
|
||||
constexpr auto RLE = true; //NOTE: only 2.7% gain after zstd
|
||||
constexpr auto RLE = true; //NOTE: only ~2.5% gain after zstd
|
||||
using namespace geometry;
|
||||
/// World part as linear 3d voxel array
|
||||
class Chunk {
|
||||
public:
|
||||
Chunk() {}
|
||||
Chunk(const chunk_pos& pos, Generator& rnd);
|
||||
Chunk(const chunk_pos &pos, const std::unique_ptr<generator::Abstract> &rnd);
|
||||
Chunk(std::istream& str, bool rle = RLE);
|
||||
~Chunk();
|
||||
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#if HASTY
|
||||
#include <hastyNoise.h>
|
||||
#else
|
||||
#include <FastNoiseSIMD.h>
|
||||
#endif
|
||||
#include <tuple>
|
||||
#include <variant>
|
||||
#include "position.h"
|
||||
|
||||
namespace world {
|
||||
/// Noise generator
|
||||
class Generator {
|
||||
public:
|
||||
/// Generation caracteristics
|
||||
struct Properties {
|
||||
/// Default cheese
|
||||
Properties(int seed = 42): shape(cheese()), density(noise(seed)), material(noise(seed * 5, .1)) { }
|
||||
/// Default planet
|
||||
Properties(voxel_pos::value_type height, int seed = 42): shape(planet(height)), density(seed), material(seed * 5, .1) { }
|
||||
|
||||
/// Endless cave network
|
||||
struct cheese {
|
||||
cheese(float density = 0, float gran = 30): density(density), granularity(gran) { }
|
||||
/// Offset density overrage
|
||||
float density;
|
||||
/// Speed of density change
|
||||
float granularity;
|
||||
};
|
||||
// Cube planet
|
||||
struct planet: cheese {
|
||||
planet(voxel_pos::value_type height, float surface_roughness = .1, float cave_depth = .2, float density = 0, float gran = 30): cheese(density, gran),
|
||||
height(height), surface_roughness(surface_roughness), cave_depth(cave_depth) { }
|
||||
/// Sea level (minimal density)
|
||||
voxel_pos::value_type height;
|
||||
/// Density decrease over height
|
||||
float surface_roughness;
|
||||
/// Density decrease under height
|
||||
float cave_depth;
|
||||
};
|
||||
std::variant<cheese, planet> shape;
|
||||
struct noise {
|
||||
noise(int seed, float freq = .01): seed(seed), frequency(freq) { }
|
||||
int seed;
|
||||
float frequency;
|
||||
};
|
||||
noise density;
|
||||
noise material;
|
||||
};
|
||||
using set = float *;
|
||||
#if HASTY
|
||||
using noise = std::unique_ptr<HastyNoise::NoiseSIMD>;
|
||||
#else
|
||||
using noise = FastNoiseSIMD *;
|
||||
#endif
|
||||
Generator(const Properties& properties): properties(properties) {
|
||||
#if HASTY
|
||||
printf("double!!!\n");
|
||||
const size_t fastestSimd = HastyNoise::GetFastestSIMD();
|
||||
densityNoise = HastyNoise::CreateNoise(seed, fastestSimd);
|
||||
materialNoise = HastyNoise::CreateNoise(seed * 5, fastestSimd);
|
||||
materialNoise->SetNoiseType(HastyNoise::NoiseType::Cellular); // NOTE: probably heavy
|
||||
materialNoise->SetCellularReturnType(HastyNoise::CellularReturnType::Value);
|
||||
materialNoise->SetCellularDistanceFunction(HastyNoise::CellularDistance::Natural);
|
||||
materialNoise->SetFrequency(.1);
|
||||
#else
|
||||
densityNoise = FastNoiseSIMD::NewFastNoiseSIMD(properties.density.seed);
|
||||
densityNoise->SetFrequency(properties.density.frequency);
|
||||
materialNoise = FastNoiseSIMD::NewFastNoiseSIMD(properties.material.seed);
|
||||
materialNoise->SetNoiseType(FastNoiseSIMD::Cellular); // NOTE: probably heavy
|
||||
materialNoise->SetCellularReturnType(FastNoiseSIMD::CellValue);
|
||||
materialNoise->SetCellularDistanceFunction(FastNoiseSIMD::Natural);
|
||||
materialNoise->SetFrequency(properties.material.frequency);
|
||||
#endif
|
||||
}
|
||||
~Generator() {
|
||||
#if !HASTY
|
||||
delete densityNoise;
|
||||
delete materialNoise;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Get block of given size with index pos.
|
||||
/// @note owning pointers, call free(set set)
|
||||
inline std::pair<set, set> getChunk(const chunk_pos& pos, int size) {
|
||||
auto pair = std::make_pair(
|
||||
densityNoise->GetNoiseSet(pos.x * size, pos.y * size, pos.z * size, size, size, size),
|
||||
materialNoise->GetNoiseSet(pos.x * size, pos.y * size, pos.z * size, size, size, size)
|
||||
);
|
||||
#if HASTY
|
||||
return {pair.first.release(), pair.second.release()};
|
||||
#else
|
||||
return pair;
|
||||
#endif
|
||||
}
|
||||
static inline void free(set set) {
|
||||
#if HASTY
|
||||
HastyNoise::SetDeleter()(set);
|
||||
#else
|
||||
FastNoiseSIMD::FreeNoiseSet(set);
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr inline const Properties& getProperties() const { return properties; }
|
||||
|
||||
private:
|
||||
Properties properties;
|
||||
noise densityNoise;
|
||||
noise materialNoise;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
#pragma once
|
||||
|
||||
#if HASTY
|
||||
#include <hastyNoise.h>
|
||||
#else
|
||||
#include <FastNoiseSIMD.h>
|
||||
#endif
|
||||
#include <memory>
|
||||
#include "position.h"
|
||||
|
||||
namespace world {
|
||||
/// Noise handler
|
||||
class Noise {
|
||||
public:
|
||||
#if HASTY
|
||||
using handle = HastyNoise::NoiseSIMD;
|
||||
using set = std::unique_ptr<float>;
|
||||
#else
|
||||
using handle = FastNoiseSIMD;
|
||||
struct fast_set_deleter {
|
||||
constexpr fast_set_deleter() noexcept = default;
|
||||
|
||||
void operator()(float* set) const {
|
||||
FastNoiseSIMD::FreeNoiseSet(set);
|
||||
}
|
||||
};
|
||||
using set = std::unique_ptr<float, fast_set_deleter>;
|
||||
#endif
|
||||
|
||||
struct Base {
|
||||
int seed = 1337;
|
||||
float frequency = .01f;
|
||||
};
|
||||
struct Simplex: Base {
|
||||
Simplex(int _seed, float _frequency) {
|
||||
seed = _seed;
|
||||
frequency = _frequency;
|
||||
}
|
||||
};
|
||||
struct SimplexFractal: Simplex {
|
||||
SimplexFractal(int seed, float frequency = .01f, int octaves = 3, float lacunarity = 2.0f, float gain = .5f):
|
||||
Simplex(seed, frequency), octaves(octaves), lacunarity(lacunarity), gain(gain) { }
|
||||
int octaves;
|
||||
float lacunarity;
|
||||
float gain;
|
||||
//FractalType m_fractalType = FBM;
|
||||
};
|
||||
struct Cellular: Base {
|
||||
Cellular(int _seed, float _frequency) {
|
||||
seed = _seed;
|
||||
frequency = _frequency;
|
||||
}
|
||||
//MAYBE: add options
|
||||
};
|
||||
|
||||
Noise(Simplex s): Noise(s, type::Simplex) { }
|
||||
Noise(SimplexFractal sf): Noise(sf, type::SimplexFractal) {
|
||||
noise->SetFractalGain(sf.gain);
|
||||
noise->SetFractalLacunarity(sf.lacunarity);
|
||||
noise->SetFractalOctaves(sf.octaves);
|
||||
//noise->SetFractalType();
|
||||
}
|
||||
Noise(Cellular c): Noise(c, type::Cellular) {
|
||||
#if HASTY
|
||||
noise->SetCellularReturnType(HastyNoise::CellularReturnType::Value);
|
||||
noise->SetCellularDistanceFunction(HastyNoise::CellularDistance::Natural);
|
||||
#else
|
||||
noise->SetCellularReturnType(FastNoiseSIMD::CellValue);
|
||||
noise->SetCellularDistanceFunction(FastNoiseSIMD::Natural);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Get block of given size with index pos.
|
||||
inline set Get(const chunk_pos& pos, int size) {
|
||||
#if HASTY
|
||||
return noise->GetNoiseSet(pos.x * size, pos.y * size, pos.z * size, size, size, size);
|
||||
#else
|
||||
return std::unique_ptr<float, fast_set_deleter>(noise->GetNoiseSet(pos.x * size, pos.y * size, pos.z * size, size, size, size), fast_set_deleter());
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
enum class type {
|
||||
SimplexFractal, Simplex, Cellular
|
||||
};
|
||||
|
||||
#if HASTY
|
||||
static HastyNoise::NoiseType ConvertType(type t) {
|
||||
switch(t) {
|
||||
case type::Simplex:
|
||||
return HastyNoise::NoiseType::Simplex;
|
||||
case type::SimplexFractal:
|
||||
return HastyNoise::NoiseType::SimplexFractal;
|
||||
case type::Cellular:
|
||||
return HastyNoise::NoiseType::Cellular;
|
||||
}
|
||||
return HastyNoise::NoiseType::Simplex;
|
||||
}
|
||||
#else
|
||||
static FastNoiseSIMD::NoiseType ConvertType(type t) {
|
||||
switch(t) {
|
||||
case type::Simplex:
|
||||
return FastNoiseSIMD::NoiseType::Simplex;
|
||||
case type::SimplexFractal:
|
||||
return FastNoiseSIMD::NoiseType::SimplexFractal;
|
||||
case type::Cellular:
|
||||
return FastNoiseSIMD::NoiseType::Cellular;
|
||||
}
|
||||
return FastNoiseSIMD::NoiseType::Simplex;
|
||||
}
|
||||
#endif
|
||||
|
||||
Noise(Base p, type t) {
|
||||
#if HASTY
|
||||
const size_t fastestSimd = HastyNoise::GetFastestSIMD();
|
||||
noise = HastyNoise::CreateNoise(p.seed, fastestSimd);
|
||||
#else
|
||||
noise = std::unique_ptr<FastNoiseSIMD>(FastNoiseSIMD::NewFastNoiseSIMD(p.seed));
|
||||
#endif
|
||||
noise->SetNoiseType(ConvertType(t));
|
||||
noise->SetFrequency(p.frequency);
|
||||
}
|
||||
|
||||
std::unique_ptr<handle> noise;
|
||||
};
|
||||
}
|
|
@ -31,12 +31,12 @@ Universe::Universe(const Universe::options &options): dicts("content/zstd.dict"
|
|||
while(!index.eof()) {
|
||||
size_t id = UINT32_MAX;
|
||||
index.read(reinterpret_cast<char *>(&id), sizeof(size_t));
|
||||
Area::params params{voxel_pos(0), 0, Generator::Properties(0)};
|
||||
Area::params params{voxel_pos(0), 0, generator::params()};
|
||||
index.read(reinterpret_cast<char *>(¶ms.center.x), sizeof(voxel_pos::value_type));
|
||||
index.read(reinterpret_cast<char *>(¶ms.center.y), sizeof(voxel_pos::value_type));
|
||||
index.read(reinterpret_cast<char *>(¶ms.center.z), sizeof(voxel_pos::value_type));
|
||||
index.read(reinterpret_cast<char *>(¶ms.radius), sizeof(int));
|
||||
index.read(reinterpret_cast<char *>(¶ms.properties), sizeof(Generator::Properties));
|
||||
index.read(reinterpret_cast<char *>(¶ms.properties), sizeof(generator::params));
|
||||
[[maybe_unused]]
|
||||
auto ok = tmp.emplace(id, params).second;
|
||||
assert(ok && "Duplicated area");
|
||||
|
@ -49,8 +49,9 @@ Universe::Universe(const Universe::options &options): dicts("content/zstd.dict"
|
|||
LOG_E("No index file!!! Probably a new world...");
|
||||
//TODO: generate universe
|
||||
const auto radius = 1 << 4;
|
||||
far_areas.emplace(Area::params{glm::multiply(voxel_pos(radius, 0, 0)), radius, Generator::Properties(radius * CHUNK_LENGTH * 3 / 4, 42)});
|
||||
//far_areas.emplace(Area::params{voxel_pos(0), 1 << 20, Generator::Properties(42)});
|
||||
far_areas.emplace(Area::params{glm::multiply(voxel_pos(radius, 0, 0)), radius,
|
||||
generator::params(std::in_place_type<generator::CubicPlanet::Params>, radius * CHUNK_LENGTH * 3 / 4, 42)});
|
||||
//far_areas.emplace(Area::params{voxel_pos(0), 1 << 20, generator::params(std::in_place_type<generator::Cave::Params>, 42)});
|
||||
}
|
||||
index.close();
|
||||
}
|
||||
|
@ -151,7 +152,7 @@ void Universe::saveAreas() const {
|
|||
index.write(reinterpret_cast<char *>(¶ms.center.y), sizeof(voxel_pos::value_type));
|
||||
index.write(reinterpret_cast<char *>(¶ms.center.z), sizeof(voxel_pos::value_type));
|
||||
index.write(reinterpret_cast<char *>(¶ms.radius), sizeof(int));
|
||||
index.write(reinterpret_cast<char *>(¶ms.properties), sizeof(Generator::Properties)); // MAYBE: use binary structured format (protobuf/messagebuf)
|
||||
index.write(reinterpret_cast<char *>(¶ms.properties), sizeof(generator::params)); // MAYBE: use binary structured format (protobuf/msgpack)
|
||||
};
|
||||
for(const auto& area: areas) {
|
||||
write(area.first, area.second->getParams());
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
#include "Noise.hpp"
|
||||
#include "materials.hpp"
|
||||
#include "Voxel.hpp"
|
||||
#include "../data/math.hpp"
|
||||
|
||||
namespace world::generator {
|
||||
|
||||
/// Abstract Noise generator
|
||||
class Abstract {
|
||||
public:
|
||||
/// Generate chunk voxels
|
||||
/// MAYBE: use template to avoid virtual
|
||||
virtual void generate(const chunk_pos &at, std::array<Voxel, CHUNK_SIZE> &out) = 0;
|
||||
};
|
||||
|
||||
// Generate empty space
|
||||
class Void: public Abstract {
|
||||
public:
|
||||
struct Params { };
|
||||
Void() = default;
|
||||
|
||||
void generate(const chunk_pos &, std::array<Voxel, CHUNK_SIZE> &out) override {
|
||||
out.fill(Voxel());
|
||||
}
|
||||
};
|
||||
|
||||
/// Endless cave network
|
||||
class Cave: public Abstract {
|
||||
public:
|
||||
struct Params {
|
||||
Params(int seed = 42, float density = 0, float gran = 30): seed(seed), density(density), granularity(gran) { }
|
||||
|
||||
/// Random generator start
|
||||
int seed;
|
||||
/// Offset density overrage
|
||||
float density;
|
||||
/// Speed of density change
|
||||
float granularity;
|
||||
};
|
||||
Cave(const Params p): params(p), density(Noise::SimplexFractal(p.seed)), material(Noise::Cellular(p.seed * 5, .1)) { }
|
||||
|
||||
void generate(const chunk_pos &pos, std::array<Voxel, CHUNK_SIZE> &out) override {
|
||||
auto densitySet = density.Get(pos, CHUNK_LENGTH);
|
||||
auto materialSet = material.Get(pos, CHUNK_LENGTH);
|
||||
for (size_t i = 0; i < CHUNK_SIZE; i++) {
|
||||
const auto density = std::clamp((densitySet.get()[i] + params.density) * params.granularity, 0.f, 1.f) * Voxel::DENSITY_MAX;
|
||||
const auto material = density > 0 ? 1 + std::clamp(static_cast<int>(std::lrint((materialSet.get()[i] + 1) / 2 * (materials::count - 2))),
|
||||
0, materials::count - 2) : 0; //NOTE: map (approx -1, 1) to (1, mat_max)
|
||||
out[i] = Voxel(material, density);
|
||||
}
|
||||
}
|
||||
private:
|
||||
Params params;
|
||||
Noise density;
|
||||
Noise material;
|
||||
};
|
||||
|
||||
enum class PlanetShape { Cube, Sphere };
|
||||
|
||||
/// Abstract shaped planet generator
|
||||
template <PlanetShape PS>
|
||||
class Planet: public Abstract {
|
||||
public:
|
||||
struct Params: Cave::Params {
|
||||
Params(voxel_pos::value_type height, int seed = 42, float surface_roughness = .1, float cave_depth = .2, float density = 0, float gran = 30):
|
||||
Cave::Params(seed, density, gran), height(height), surface_roughness(surface_roughness), cave_depth(cave_depth) { }
|
||||
|
||||
/// Sea level (minimal density)
|
||||
voxel_pos::value_type height;
|
||||
/// Density decrease over height
|
||||
float surface_roughness;
|
||||
/// Density decrease under height
|
||||
float cave_depth;
|
||||
};
|
||||
Planet(const Params p) : params(p), density(Noise::SimplexFractal(p.seed)), material(Noise::Cellular(p.seed * 5, .1)) {}
|
||||
|
||||
void generate(const chunk_pos &pos, std::array<Voxel, CHUNK_SIZE> &out) override {
|
||||
auto densitySet = density.Get(pos, CHUNK_LENGTH);
|
||||
auto materialSet = material.Get(pos, CHUNK_LENGTH);
|
||||
const auto verticalDensity = [this, pos](glm::idx i) {
|
||||
const auto heightRatio = static_cast<float>(getHeight(glm::multiply(pos) + glm::llvec3(glm::fromIdx(i))) - params.height) / params.height;
|
||||
return heightRatio / (heightRatio >= 0 ? params.surface_roughness : params.cave_depth);
|
||||
};
|
||||
for (size_t i = 0; i < CHUNK_SIZE; i++) {
|
||||
const auto density = std::clamp((densitySet.get()[i] + params.density - verticalDensity(i)) * params.granularity, 0.f, 1.f) * Voxel::DENSITY_MAX;
|
||||
const auto material = density > 0 ? 1 + std::clamp(static_cast<int>(std::lrint((materialSet.get()[i] + 1) / 2 * (materials::count - 2))),
|
||||
0, materials::count - 2) : 0; //NOTE: map (approx -1, 1) to (1, mat_max)
|
||||
out[i] = Voxel(material, density);
|
||||
}
|
||||
}
|
||||
private:
|
||||
static constexpr PlanetShape shape = PS;
|
||||
static constexpr voxel_pos::value_type getHeight(const voxel_pos &p) {
|
||||
if constexpr(shape == PlanetShape::Cube) {
|
||||
return glm::max_axis(glm::abs(p));
|
||||
} else {
|
||||
return glm::length(glm::dvec3(p));
|
||||
}
|
||||
}
|
||||
Params params;
|
||||
Noise density;
|
||||
Noise material;
|
||||
};
|
||||
using CubicPlanet = Planet<PlanetShape::Cube>;
|
||||
using RoundPlanet = Planet<PlanetShape::Sphere>;
|
||||
|
||||
using params = std::variant<Void::Params, Cave::Params, CubicPlanet::Params, RoundPlanet::Params>;
|
||||
inline std::unique_ptr<Abstract> load(const params &p) {
|
||||
const auto get_new = [](const params &p) -> Abstract* {
|
||||
if(std::holds_alternative<Void::Params>(p)) {
|
||||
return new Void();
|
||||
} else if(const auto c = std::get_if<Cave::Params>(&p)) {
|
||||
return new Cave(*c);
|
||||
} else if(const auto pc = std::get_if<CubicPlanet::Params>(&p)) {
|
||||
return new CubicPlanet(*pc);
|
||||
} else if(const auto ps = std::get_if<RoundPlanet::Params>(&p)) {
|
||||
return new RoundPlanet(*ps);
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
return std::unique_ptr<Abstract>(get_new(p));
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
#include "../data/generational.hpp"
|
||||
|
||||
const auto CHUNK_LENGTH = glm::IDX_LENGTH;
|
||||
const auto CHUNK_SIZE = CHUNK_LENGTH * CHUNK_LENGTH * CHUNK_LENGTH;
|
||||
const auto REGION_LENGTH = glm::IDX_LENGTH;
|
||||
|
||||
using voxel_pos = glm::llvec3;
|
||||
|
|
|
@ -27,7 +27,7 @@ const auto RANGE = 1 << 18;
|
|||
int main(int /*unused*/, char * /*unused*/[])
|
||||
{
|
||||
std::srand(std::time(nullptr));
|
||||
world::Generator generator(std::rand());
|
||||
auto generator = world::generator::load(world::generator::Cave::Params(std::rand()));
|
||||
std::vector<char> samples;
|
||||
samples.reserve(SIZE * SAMPLES);
|
||||
std::vector<size_t> sizes;
|
||||
|
|
Loading…
Reference in New Issue