Commit dc7c70d8 authored by Shu's avatar Shu 🍠
Browse files

Planet properties

parent e7d34b82
......@@ -28,7 +28,7 @@
- [x] Area
- [x] Offset
- [ ] Rotation
- [ ] Planet
- [~] Planet
- [ ] CubicSphere
- [ ] Healpix
- [ ] Galaxy
......@@ -46,7 +46,7 @@
- [ ] ZeroMQ
- [~] Workers
- [x] Basic
- [ ] Use system infos
- [x] Use system infos
- [ ] Pool
- [x] Logger
- [ ] FastNoiseSIMD / HastyNoise double precision
......
......@@ -7,12 +7,21 @@ namespace glm {
constexpr ivec3 inline iround(const vec3& p) {
return ivec3(std::round<int>(p.x), std::round<int>(p.y), std::round<int>(p.z));
}
constexpr long inline length2(const ivec3& a) {
constexpr float inline length2(const vec3& a) {
return a.x * a.x + a.y * a.y + a.z * a.z;
}
constexpr long inline length2(const lvec3& a) {
return a.x * a.x + a.y * a.y + a.z * a.z;
}
constexpr long long inline length2(const llvec3& a) {
return a.x * a.x + a.y * a.y + a.z * a.z;
}
constexpr long inline pow2(int v) {
return v * v;
}
constexpr long long inline pow2(long v) {
return v * v;
}
constexpr ivec3 inline diff(const ivec3& a, const ivec3& b) {
return glm::abs(glm::abs(a) - glm::abs(b));
}
......@@ -57,4 +66,8 @@ namespace glm {
constexpr std::pair<lvec3, idx> inline splitIdx(const llvec3 &value, const ucvec3 &m = ucvec3(IDX_LENGTH)) {
return {divide(value, m), toIdx(rem(value.x, m.x), rem(value.y, m.y), rem(value.z, m.z))};
}
template <typename T>
constexpr T inline max_axis(const vec<3, T> &v) {
return std::max({v.x, v.y, v.z});
}
}
......@@ -34,11 +34,11 @@ namespace world {
struct params {
voxel_pos center;
int radius;
int seed = 42;
Generator::Properties properties;
};
/// radius: size in chunk (length = radius * 2 + 1)
Area(const params& p): center(p.center), chunks(p.radius), generator(p.seed) { }
Area(const params& p): center(p.center), chunks(p.radius), generator(p.properties) { }
inline const area_pos &getOffset() const { return center; }
inline geometry::IBox getBounding() const {
......@@ -61,7 +61,7 @@ namespace world {
inline Generator &getGenerator() { return generator; }
inline params getParams() const { return params{center.as_voxel(), chunks.getRadius(), generator.getSeed()}; }
inline params getParams() const { return params{center.as_voxel(), chunks.getRadius(), generator.getProperties()}; }
private:
area_pos center;
......
......@@ -6,16 +6,24 @@
using namespace world;
constexpr auto DENSITY = 0.f;
constexpr auto GRANULARITY = 30.f;
constexpr auto HEIGHT = 2;
Chunk::Chunk(const chunk_pos& pos, Generator& rnd) {
const auto [densitySet, materialSet] = rnd.getChunk(pos, CHUNK_LENGTH);
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 height = std::max(0l, pos.y * CHUNK_LENGTH + glm::fromIdx(i).y);
const auto density = std::clamp((densitySet[i] + DENSITY) * GRANULARITY - height / HEIGHT, 0.f, 1.f) * Voxel::DENSITY_MAX;
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);
......
......@@ -6,19 +6,55 @@
#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(int seed = 42): seed(seed) {
Generator(const Properties& properties): properties(properties) {
#if HASTY
printf("double!!!\n");
const size_t fastestSimd = HastyNoise::GetFastestSIMD();
......@@ -29,12 +65,13 @@ namespace world {
materialNoise->SetCellularDistanceFunction(HastyNoise::CellularDistance::Natural);
materialNoise->SetFrequency(.1);
#else
densityNoise = FastNoiseSIMD::NewFastNoiseSIMD(seed);
materialNoise = FastNoiseSIMD::NewFastNoiseSIMD(seed * 5);
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(.1);
materialNoise->SetFrequency(properties.material.frequency);
#endif
}
~Generator() {
......@@ -65,10 +102,10 @@ namespace world {
#endif
}
inline int getSeed() const { return seed; }
constexpr inline const Properties& getProperties() const { return properties; }
private:
int seed;
Properties properties;
noise densityNoise;
noise materialNoise;
};
......
......@@ -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};
Area::params params{voxel_pos(0), 0, Generator::Properties(0)};
index.read(reinterpret_cast<char *>(&params.center.x), sizeof(voxel_pos::value_type));
index.read(reinterpret_cast<char *>(&params.center.y), sizeof(voxel_pos::value_type));
index.read(reinterpret_cast<char *>(&params.center.z), sizeof(voxel_pos::value_type));
index.read(reinterpret_cast<char *>(&params.radius), sizeof(int));
index.read(reinterpret_cast<char *>(&params.seed), sizeof(int));
index.read(reinterpret_cast<char *>(&params.properties), sizeof(Generator::Properties));
[[maybe_unused]]
auto ok = tmp.emplace(id, params).second;
assert(ok && "Duplicated area");
......@@ -48,8 +48,8 @@ Universe::Universe(const Universe::options &options): dicts("content/zstd.dict"
} else {
LOG_E("No index file!!! Probably a new world...");
//TODO: generate universe
far_areas.emplace(Area::params{voxel_pos(0), 1 << 20});
//far_areas.emplace(Area::params{voxel_pos(0), 1, 43});
const auto radius = 1 << 4;
far_areas.emplace(Area::params{glm::multiply(voxel_pos(radius)), radius, Generator::Properties(radius * CHUNK_LENGTH * 3 / 4, 42)});
}
index.close();
}
......@@ -150,7 +150,7 @@ void Universe::saveAreas() const {
index.write(reinterpret_cast<char *>(&params.center.y), sizeof(voxel_pos::value_type));
index.write(reinterpret_cast<char *>(&params.center.z), sizeof(voxel_pos::value_type));
index.write(reinterpret_cast<char *>(&params.radius), sizeof(int));
index.write(reinterpret_cast<char *>(&params.seed), sizeof(int));
index.write(reinterpret_cast<char *>(&params.properties), sizeof(Generator::Properties)); // MAYBE: use binary structured format (protobuf/messagebuf)
};
for(const auto& area: areas) {
write(area.first, area.second->getParams());
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment