test voxel structures generation
This commit is contained in:
parent
cba1a5c23e
commit
03ba7c9539
Binary file not shown.
@ -57,10 +57,24 @@ biomes = {
|
|||||||
|
|
||||||
function load_structures()
|
function load_structures()
|
||||||
local structures = {}
|
local structures = {}
|
||||||
table.insert(structures, generation.load_structure("core:default.files/tree0"))
|
local names = {"tree0"}
|
||||||
|
for i, name in ipairs(names) do
|
||||||
|
local filename = "core:default.files/"..name
|
||||||
|
debug.log("loading structure "..filename)
|
||||||
|
table.insert(structures, generation.load_structure(filename))
|
||||||
|
end
|
||||||
return structures
|
return structures
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function place_structures(x, z, w, d, seed)
|
||||||
|
local placements = {}
|
||||||
|
local px = math.random() * w
|
||||||
|
local py = 200;
|
||||||
|
local pz = math.random() * d
|
||||||
|
table.insert(placements, {0, {px, py, pz}})
|
||||||
|
return placements
|
||||||
|
end
|
||||||
|
|
||||||
local function _generate_heightmap(x, y, w, h, seed, s)
|
local function _generate_heightmap(x, y, w, h, seed, s)
|
||||||
local umap = Heightmap(w, h)
|
local umap = Heightmap(w, h)
|
||||||
local vmap = Heightmap(w, h)
|
local vmap = Heightmap(w, h)
|
||||||
|
|||||||
@ -43,6 +43,7 @@ public:
|
|||||||
lua::touserdata<lua::LuaVoxelStructure>(L, -1)) {
|
lua::touserdata<lua::LuaVoxelStructure>(L, -1)) {
|
||||||
structures.push_back(lstruct->getStructure());
|
structures.push_back(lstruct->getStructure());
|
||||||
}
|
}
|
||||||
|
lua::pop(L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,6 +98,40 @@ public:
|
|||||||
return maps;
|
return maps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<StructurePlacement> placeStructures(
|
||||||
|
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed
|
||||||
|
) override {
|
||||||
|
std::vector<StructurePlacement> placements;
|
||||||
|
|
||||||
|
auto L = lua::get_main_thread();
|
||||||
|
lua::stackguard _(L);
|
||||||
|
lua::pushenv(L, *env);
|
||||||
|
if (lua::getfield(L, "place_structures")) {
|
||||||
|
lua::pushivec_stack(L, offset);
|
||||||
|
lua::pushivec_stack(L, size);
|
||||||
|
lua::pushinteger(L, seed);
|
||||||
|
if (lua::call_nothrow(L, 5, 1)) {
|
||||||
|
int len = lua::objlen(L, -1);
|
||||||
|
for (int i = 1; i <= len; i++) {
|
||||||
|
lua::rawgeti(L, i);
|
||||||
|
|
||||||
|
lua::rawgeti(L, 1);
|
||||||
|
int structIndex = lua::tointeger(L, -1);
|
||||||
|
lua::pop(L);
|
||||||
|
|
||||||
|
lua::rawgeti(L, 2);
|
||||||
|
glm::ivec3 pos = lua::tovec3(L, -1);
|
||||||
|
|
||||||
|
lua::pop(L);
|
||||||
|
|
||||||
|
placements.emplace_back(structIndex, pos);
|
||||||
|
}
|
||||||
|
lua::pop(L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return placements;
|
||||||
|
}
|
||||||
|
|
||||||
void prepare(const Content* content) override {
|
void prepare(const Content* content) override {
|
||||||
for (auto& biome : biomes) {
|
for (auto& biome : biomes) {
|
||||||
for (auto& layer : biome.groundLayers.layers) {
|
for (auto& layer : biome.groundLayers.layers) {
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "typedefs.hpp"
|
#include "typedefs.hpp"
|
||||||
#include "maths/Heightmap.hpp"
|
#include "maths/Heightmap.hpp"
|
||||||
|
#include "StructurePlacement.hpp"
|
||||||
|
|
||||||
class Content;
|
class Content;
|
||||||
class VoxelStructure;
|
class VoxelStructure;
|
||||||
@ -114,6 +115,10 @@ public:
|
|||||||
virtual std::vector<std::shared_ptr<Heightmap>> generateParameterMaps(
|
virtual std::vector<std::shared_ptr<Heightmap>> generateParameterMaps(
|
||||||
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed) = 0;
|
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed) = 0;
|
||||||
|
|
||||||
|
virtual std::vector<StructurePlacement> placeStructures(
|
||||||
|
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed) = 0;
|
||||||
|
|
||||||
|
/// @brief Get generator biomes
|
||||||
virtual const std::vector<Biome>& getBiomes() const = 0;
|
virtual const std::vector<Biome>& getBiomes() const = 0;
|
||||||
|
|
||||||
/// @return Number of biome parameters, that biome choosing depending on
|
/// @return Number of biome parameters, that biome choosing depending on
|
||||||
|
|||||||
12
src/world/generator/StructurePlacement.hpp
Normal file
12
src/world/generator/StructurePlacement.hpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
struct StructurePlacement {
|
||||||
|
int structure;
|
||||||
|
|
||||||
|
glm::ivec3 position;
|
||||||
|
|
||||||
|
StructurePlacement(int structure, glm::ivec3 position)
|
||||||
|
: structure(structure), position(std::move(position)) {}
|
||||||
|
};
|
||||||
@ -40,6 +40,7 @@ std::unique_ptr<VoxelStructure> VoxelStructure::create(
|
|||||||
index = found->second;
|
index = found->second;
|
||||||
}
|
}
|
||||||
voxels[i].id = index;
|
voxels[i].id = index;
|
||||||
|
voxels[i].state = volVoxels[i].state;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_unique<VoxelStructure>(
|
return std::make_unique<VoxelStructure>(
|
||||||
@ -67,6 +68,11 @@ void VoxelStructure::deserialize(const dv::value& src) {
|
|||||||
size = glm::ivec3();
|
size = glm::ivec3();
|
||||||
dv::get_vec(src, "size", size);
|
dv::get_vec(src, "size", size);
|
||||||
|
|
||||||
|
const auto& namesArr = src["block-names"];
|
||||||
|
for (const auto& elem : namesArr) {
|
||||||
|
blockNames.push_back(elem.asString());
|
||||||
|
}
|
||||||
|
|
||||||
auto volume = size.x*size.y*size.z;
|
auto volume = size.x*size.y*size.z;
|
||||||
voxels.resize(volume);
|
voxels.resize(volume);
|
||||||
|
|
||||||
@ -81,7 +87,7 @@ void VoxelStructure::prepare(const Content& content) {
|
|||||||
auto volume = size.x*size.y*size.z;
|
auto volume = size.x*size.y*size.z;
|
||||||
voxelsRuntime.resize(volume);
|
voxelsRuntime.resize(volume);
|
||||||
for (size_t i = 0; i < volume; i++) {
|
for (size_t i = 0; i < volume; i++) {
|
||||||
const auto& name = blockNames[voxels[i].id];
|
const auto& name = blockNames.at(voxels[i].id);
|
||||||
voxelsRuntime[i].id = content.blocks.require(name).rt.id;
|
voxelsRuntime[i].id = content.blocks.require(name).rt.id;
|
||||||
voxelsRuntime[i].state = voxels[i].state;
|
voxelsRuntime[i].state = voxels[i].state;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<voxel>& getRuntimeVoxels() {
|
const std::vector<voxel>& getRuntimeVoxels() {
|
||||||
|
assert(!voxelsRuntime.empty());
|
||||||
return voxelsRuntime;
|
return voxelsRuntime;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
static debug::Logger logger("world-generator");
|
static debug::Logger logger("world-generator");
|
||||||
|
|
||||||
static inline constexpr uint MAX_PARAMETERS = 4;
|
static inline constexpr uint MAX_PARAMETERS = 4;
|
||||||
static inline constexpr uint MAX_CHUNK_PROTOTYPE_LEVELS = 3;
|
static inline constexpr uint MAX_CHUNK_PROTOTYPE_LEVELS = 5;
|
||||||
|
|
||||||
WorldGenerator::WorldGenerator(
|
WorldGenerator::WorldGenerator(
|
||||||
const GeneratorDef& def, const Content* content, uint64_t seed
|
const GeneratorDef& def, const Content* content, uint64_t seed
|
||||||
@ -44,14 +44,31 @@ WorldGenerator::WorldGenerator(
|
|||||||
if (found == prototypes.end()) {
|
if (found == prototypes.end()) {
|
||||||
throw std::runtime_error("prototype not found");
|
throw std::runtime_error("prototype not found");
|
||||||
}
|
}
|
||||||
generateHeightmap(found->second.get(), x, z);
|
generateStructures(requirePrototype(x, z), x, z);
|
||||||
|
});
|
||||||
|
surroundMap.setLevelCallback(3, [this](int const x, int const z) {
|
||||||
|
generateBiomes(requirePrototype(x, z), x, z);
|
||||||
|
});
|
||||||
|
surroundMap.setLevelCallback(4, [this](int const x, int const z) {
|
||||||
|
generateHeightmap(requirePrototype(x, z), x, z);
|
||||||
});
|
});
|
||||||
|
|
||||||
structures = def.script->loadStructures();
|
structures = def.script->loadStructures();
|
||||||
|
for (auto& structure : structures) {
|
||||||
|
structure->prepare(*content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldGenerator::~WorldGenerator() {}
|
WorldGenerator::~WorldGenerator() {}
|
||||||
|
|
||||||
|
ChunkPrototype& WorldGenerator::requirePrototype(int x, int z) {
|
||||||
|
const auto& found = prototypes.find({x, z});
|
||||||
|
if (found == prototypes.end()) {
|
||||||
|
throw std::runtime_error("prototype not found");
|
||||||
|
}
|
||||||
|
return *found->second;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void generate_pole(
|
static inline void generate_pole(
|
||||||
const BlocksLayers& layers,
|
const BlocksLayers& layers,
|
||||||
int top, int bottom,
|
int top, int bottom,
|
||||||
@ -112,6 +129,27 @@ static inline const Biome* choose_biome(
|
|||||||
std::unique_ptr<ChunkPrototype> WorldGenerator::generatePrototype(
|
std::unique_ptr<ChunkPrototype> WorldGenerator::generatePrototype(
|
||||||
int chunkX, int chunkZ
|
int chunkX, int chunkZ
|
||||||
) {
|
) {
|
||||||
|
return std::make_unique<ChunkPrototype>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldGenerator::generateStructures(
|
||||||
|
ChunkPrototype& prototype, int chunkX, int chunkZ
|
||||||
|
) {
|
||||||
|
if (prototype.level >= ChunkPrototypeLevel::STRUCTURES) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prototype.structures = def.script->placeStructures(
|
||||||
|
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed
|
||||||
|
);
|
||||||
|
prototype.level = ChunkPrototypeLevel::STRUCTURES;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldGenerator::generateBiomes(
|
||||||
|
ChunkPrototype& prototype, int chunkX, int chunkZ
|
||||||
|
) {
|
||||||
|
if (prototype.level >= ChunkPrototypeLevel::BIOMES) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto biomeParams = def.script->generateParameterMaps(
|
auto biomeParams = def.script->generateParameterMaps(
|
||||||
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed);
|
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed);
|
||||||
const auto& biomes = def.script->getBiomes();
|
const auto& biomes = def.script->getBiomes();
|
||||||
@ -123,21 +161,19 @@ std::unique_ptr<ChunkPrototype> WorldGenerator::generatePrototype(
|
|||||||
choose_biome(biomes, biomeParams, x, z);
|
choose_biome(biomes, biomeParams, x, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::make_unique<ChunkPrototype>(
|
prototype.biomes = std::move(chunkBiomes);
|
||||||
ChunkPrototypeLevel::BIOMES,
|
prototype.level = ChunkPrototypeLevel::BIOMES;
|
||||||
std::move(chunkBiomes),
|
|
||||||
nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldGenerator::generateHeightmap(
|
void WorldGenerator::generateHeightmap(
|
||||||
ChunkPrototype* prototype, int chunkX, int chunkZ
|
ChunkPrototype& prototype, int chunkX, int chunkZ
|
||||||
) {
|
) {
|
||||||
if (prototype->level >= ChunkPrototypeLevel::HEIGHTMAP) {
|
if (prototype.level >= ChunkPrototypeLevel::HEIGHTMAP) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
prototype->heightmap = def.script->generateHeightmap(
|
prototype.heightmap = def.script->generateHeightmap(
|
||||||
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed);
|
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed);
|
||||||
prototype->level = ChunkPrototypeLevel::HEIGHTMAP;
|
prototype.level = ChunkPrototypeLevel::HEIGHTMAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldGenerator::update(int centerX, int centerY, int loadDistance) {
|
void WorldGenerator::update(int centerX, int centerY, int loadDistance) {
|
||||||
@ -150,13 +186,8 @@ void WorldGenerator::update(int centerX, int centerY, int loadDistance) {
|
|||||||
void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) {
|
void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) {
|
||||||
surroundMap.completeAt(chunkX, chunkZ);
|
surroundMap.completeAt(chunkX, chunkZ);
|
||||||
|
|
||||||
const auto& found = prototypes.find({chunkX, chunkZ});
|
const auto& prototype = requirePrototype(chunkX, chunkZ);
|
||||||
if (found == prototypes.end()) {
|
const auto values = prototype.heightmap->getValues();
|
||||||
throw std::runtime_error("no prototype found");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto prototype = found->second.get();
|
|
||||||
const auto values = prototype->heightmap->getValues();
|
|
||||||
|
|
||||||
uint seaLevel = def.script->getSeaLevel();
|
uint seaLevel = def.script->getSeaLevel();
|
||||||
|
|
||||||
@ -165,7 +196,7 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) {
|
|||||||
PseudoRandom plantsRand;
|
PseudoRandom plantsRand;
|
||||||
plantsRand.setSeed(chunkX, chunkZ);
|
plantsRand.setSeed(chunkX, chunkZ);
|
||||||
|
|
||||||
const auto& biomes = prototype->biomes.get();
|
const auto& biomes = prototype.biomes.get();
|
||||||
for (uint z = 0; z < CHUNK_D; z++) {
|
for (uint z = 0; z < CHUNK_D; z++) {
|
||||||
for (uint x = 0; x < CHUNK_W; x++) {
|
for (uint x = 0; x < CHUNK_W; x++) {
|
||||||
const Biome* biome = biomes[z * CHUNK_W + x];
|
const Biome* biome = biomes[z * CHUNK_W + x];
|
||||||
@ -189,4 +220,34 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& placement : prototype.structures) {
|
||||||
|
if (placement.structure < 0 || placement.structure >= structures.size()) {
|
||||||
|
logger.error() << "invalid structure index " << placement.structure;
|
||||||
|
}
|
||||||
|
auto& structure = *structures[placement.structure];
|
||||||
|
auto& structVoxels = structure.getRuntimeVoxels();
|
||||||
|
const auto& offset = placement.position;
|
||||||
|
const auto& size = structure.getSize();
|
||||||
|
for (int y = 0; y < size.y; y++) {
|
||||||
|
int sy = y + offset.y;
|
||||||
|
if (sy < 0 || sy >= CHUNK_H) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int z = 0; z < size.z; z++) {
|
||||||
|
int sz = z + offset.z;
|
||||||
|
if (sz < 0 || sz >= CHUNK_D) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int x = 0; x < size.x; x++) {
|
||||||
|
int sx = x + offset.x;
|
||||||
|
if (sx < 0 || sx >= CHUNK_W) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
voxels[vox_index(sx, sy, sz)] =
|
||||||
|
structVoxels[vox_index(x, y, z, size.x, size.z)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#include "typedefs.hpp"
|
#include "typedefs.hpp"
|
||||||
#include "voxels/voxel.hpp"
|
#include "voxels/voxel.hpp"
|
||||||
#include "SurroundMap.hpp"
|
#include "SurroundMap.hpp"
|
||||||
|
#include "StructurePlacement.hpp"
|
||||||
|
|
||||||
class Content;
|
class Content;
|
||||||
struct GeneratorDef;
|
struct GeneratorDef;
|
||||||
@ -17,20 +18,11 @@ struct Biome;
|
|||||||
class VoxelStructure;
|
class VoxelStructure;
|
||||||
|
|
||||||
enum class ChunkPrototypeLevel {
|
enum class ChunkPrototypeLevel {
|
||||||
BIOMES, HEIGHTMAP
|
VOID=0, STRUCTURES, BIOMES, HEIGHTMAP
|
||||||
};
|
|
||||||
|
|
||||||
struct StructurePlacement {
|
|
||||||
VoxelStructure& structure;
|
|
||||||
|
|
||||||
glm::ivec3 position;
|
|
||||||
|
|
||||||
StructurePlacement(VoxelStructure& structure, glm::ivec3 position)
|
|
||||||
: structure(structure), position(std::move(position)) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ChunkPrototype {
|
struct ChunkPrototype {
|
||||||
ChunkPrototypeLevel level;
|
ChunkPrototypeLevel level = ChunkPrototypeLevel::VOID;
|
||||||
|
|
||||||
/// @brief chunk biomes matrix
|
/// @brief chunk biomes matrix
|
||||||
std::unique_ptr<const Biome*[]> biomes;
|
std::unique_ptr<const Biome*[]> biomes;
|
||||||
@ -39,14 +31,6 @@ struct ChunkPrototype {
|
|||||||
std::shared_ptr<Heightmap> heightmap;
|
std::shared_ptr<Heightmap> heightmap;
|
||||||
|
|
||||||
std::vector<StructurePlacement> structures;
|
std::vector<StructurePlacement> structures;
|
||||||
|
|
||||||
ChunkPrototype(
|
|
||||||
ChunkPrototypeLevel level,
|
|
||||||
std::unique_ptr<const Biome*[]> biomes,
|
|
||||||
std::shared_ptr<Heightmap> heightmap
|
|
||||||
) : level(level),
|
|
||||||
biomes(std::move(biomes)),
|
|
||||||
heightmap(std::move(heightmap)) {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief High-level world generation controller
|
/// @brief High-level world generation controller
|
||||||
@ -69,7 +53,13 @@ class WorldGenerator {
|
|||||||
/// @param z chunk position Y divided by CHUNK_D
|
/// @param z chunk position Y divided by CHUNK_D
|
||||||
std::unique_ptr<ChunkPrototype> generatePrototype(int x, int z);
|
std::unique_ptr<ChunkPrototype> generatePrototype(int x, int z);
|
||||||
|
|
||||||
void generateHeightmap(ChunkPrototype* prototype, int x, int z);
|
ChunkPrototype& requirePrototype(int x, int z);
|
||||||
|
|
||||||
|
void generateStructures(ChunkPrototype& prototype, int x, int z);
|
||||||
|
|
||||||
|
void generateBiomes(ChunkPrototype& prototype, int x, int z);
|
||||||
|
|
||||||
|
void generateHeightmap(ChunkPrototype& prototype, int x, int z);
|
||||||
public:
|
public:
|
||||||
WorldGenerator(
|
WorldGenerator(
|
||||||
const GeneratorDef& def,
|
const GeneratorDef& def,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user