MapGen rewrite pt. 1 - has DensityBehavior code.
parent
4b3a3b36bc
commit
3c560c8ca2
|
@ -3,6 +3,7 @@
|
|||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
<component name="CidrRootsConfiguration">
|
||||
<sourceRoots>
|
||||
<file path="$PROJECT_DIR$/assets" />
|
||||
<file path="$PROJECT_DIR$/src" />
|
||||
<file path="$PROJECT_DIR$/subgames" />
|
||||
<file path="$PROJECT_DIR$/test" />
|
||||
|
|
|
@ -30,10 +30,12 @@ out VS_OUT {
|
|||
vec3 unpackFloat(float src) { return vec3(fract(src) * 2.0f - 1.0f, fract(src * 256.f) * 2.0f - 1.0f, fract(src * 65536.f) * 2.0f - 1.0f); }
|
||||
|
||||
void main() {
|
||||
float sunlightIntensity = 1;
|
||||
vec3 blockLightColor = (aLight.xyz / MAX_BLOCKLIGHT) * vec3(1 + sunlightIntensity / 4);
|
||||
vec3 sunlightColor = clamp(sunlightIntensity * 1.25 * vec3(1, 1, 1) * (aLight.w / 15.0), 0, 1);
|
||||
vec3 light = vec3(max(sunlightColor.x, blockLightColor.x), max(sunlightColor.y, blockLightColor.y), max(sunlightColor.z, blockLightColor.z));
|
||||
// float sunlightIntensity = 1;
|
||||
// vec3 blockLightColor = (aLight.xyz / MAX_BLOCKLIGHT) * vec3(1 + sunlightIntensity / 4);
|
||||
// vec3 sunlightColor = clamp(sunlightIntensity * 1.25 * vec3(1, 1, 1) * (aLight.w / 15.0), 0, 1);
|
||||
// vec3 light = vec3(max(sunlightColor.x, blockLightColor.x), max(sunlightColor.y, blockLightColor.y), max(sunlightColor.z, blockLightColor.z));
|
||||
|
||||
vec3 light = vec3(1, 1, 1);
|
||||
|
||||
vs_out.pos = aPos;
|
||||
vs_out.normal = unpackFloat(aNormal);
|
||||
|
|
|
@ -69,9 +69,8 @@ set(ZEPHA_SRC
|
|||
game/hud/components/basic/GuiRect.cpp
|
||||
game/hud/components/basic/GuiRect.h
|
||||
game/hud/components/basic/GuiGraph.cpp
|
||||
game/hud/components/basic/GuiGraph.h
|
||||
def/gen/MapGenJob.h
|
||||
util/Interp.h
|
||||
game/hud/components/basic/GuiGraph.h
|
||||
util/Interp.h
|
||||
def/gen/NoiseSample.cpp
|
||||
def/gen/NoiseSample.h
|
||||
game/graph/frustum/Frustum.cpp
|
||||
|
|
|
@ -2,13 +2,11 @@
|
|||
// Created by aurailus on 28/01/19.
|
||||
//
|
||||
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
|
||||
#include "MapGen.h"
|
||||
|
||||
#include "BiomeDef.h"
|
||||
#include "MapGenJob.h"
|
||||
#include "BiomeAtlas.h"
|
||||
#include "MapGenProps.h"
|
||||
#include "NoiseSample.h"
|
||||
|
@ -17,321 +15,332 @@
|
|||
#include "../../world/chunk/Chunk.h"
|
||||
#include "../../game/scene/world/Schematic.h"
|
||||
|
||||
MapGen::MapGen(unsigned int seed, DefinitionAtlas& defs, BiomeAtlas& biomes, std::shared_ptr<MapGenProps> props) :
|
||||
seed(seed),
|
||||
MapGen::MapGen(DefinitionAtlas& defs, BiomeAtlas& biomes, unsigned int seed) :
|
||||
defs(defs),
|
||||
props(props),
|
||||
biomes(biomes) {}
|
||||
biomes(biomes),
|
||||
props(seed) {}
|
||||
|
||||
MapGen::chunk_partials_map MapGen::generateMapBlock(glm::ivec3 mbPos) {
|
||||
chunk_partials_map chunks {};
|
||||
|
||||
for (short i = 3; i >= 0; i--) {
|
||||
for (short j = 0; j < 4; j++) {
|
||||
for (short k = 0; k < 4; k++) {
|
||||
glm::ivec3 pos = glm::ivec3(j, i, k) + (mbPos * 4);
|
||||
generateChunk(chunks, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generateSunlight(chunks, mbPos);
|
||||
|
||||
for (auto& chunk : chunks) {
|
||||
// Delete MapGenJobs
|
||||
delete chunk.second.first;
|
||||
chunk.second.first = nullptr;
|
||||
}
|
||||
|
||||
return chunks;
|
||||
std::unique_ptr<MapGen::ChunkMap> MapGen::generateChunk(glm::ivec3 pos) {
|
||||
return generateArea(pos);
|
||||
}
|
||||
|
||||
void MapGen::generateChunk(chunk_partials_map& chunks, glm::ivec3 worldPos) {
|
||||
if (chunks.count(worldPos) == 0) chunks.insert(std::pair<glm::ivec3, chunk_partial>{worldPos, {new MapGenJob(), new Chunk()}});
|
||||
auto& chunk = chunks.at(worldPos);
|
||||
chunk.second->pos = worldPos;
|
||||
|
||||
buildDensityMap(chunk.first, worldPos);
|
||||
buildElevationMap(chunks, chunk);
|
||||
|
||||
generateBlocks(chunk);
|
||||
generateStructures(chunks, chunk);
|
||||
|
||||
chunk.second->recalculateRenderableBlocks();
|
||||
chunk.second->generated = true;
|
||||
std::unique_ptr<MapGen::ChunkMap> MapGen::generateMapBlock(glm::ivec3 pos) {
|
||||
return generateArea(Space::Chunk::world::fromMapBlock(pos), 4);
|
||||
}
|
||||
|
||||
void MapGen::buildDensityMap(MapGenJob* job, glm::ivec3 worldPos) {
|
||||
job->temperature = {}; job->humidity = {}; job->roughness = {};
|
||||
std::unique_ptr<MapGen::ChunkMap> MapGen::generateArea(glm::ivec3 origin, unsigned int size) {
|
||||
Job job(origin, size);
|
||||
|
||||
job->temperature.fill([&](glm::ivec3 pos) {
|
||||
return props->temperature.GetValue(worldPos.x + pos.x / 16.f, 0, worldPos.z + pos.z / 16.f); }, 4);
|
||||
job->humidity.fill([&](glm::ivec3 pos) {
|
||||
return props->humidity.GetValue(worldPos.x + pos.x / 16.f, 0, worldPos.z + pos.z / 16.f); }, 4);
|
||||
job->roughness.fill([&](glm::ivec3 pos) {
|
||||
return props->roughness.GetValue(worldPos.x + pos.x / 16.f, 0, worldPos.z + pos.z / 16.f); }, 4);
|
||||
// Build Biome Prop Maps
|
||||
|
||||
NoiseSample volume = {}, heightmap = {};
|
||||
const auto fill = [&](const noise::module::Module& s) {
|
||||
return [&](glm::vec3 pos) {
|
||||
glm::vec3 worldPos = glm::vec3(job.pos) + pos * static_cast<float>(job.size);
|
||||
return s.GetValue(worldPos.x, 0, worldPos.z);
|
||||
};
|
||||
};
|
||||
|
||||
volume.fill([&](glm::ivec3 pos) {
|
||||
auto& biome = biomes.getBiomeAt(job->temperature.get(pos), job->humidity.get(pos), job->roughness.get(pos));
|
||||
return biome.volume[biome.volume.size() - 1]->GetValue(worldPos.x + pos.x / 16.f, worldPos.y + pos.y / 16.f, worldPos.z + pos.z / 16.f);
|
||||
}, {4, 4});
|
||||
job.temperature.populate(fill(props.temperature));
|
||||
job.roughness.populate(fill(props.roughness));
|
||||
job.humidity.populate(fill(props.humidity));
|
||||
|
||||
heightmap.fill([&](glm::ivec3 pos) {
|
||||
auto& biome = biomes.getBiomeAt(job->temperature.get(pos), job->humidity.get(pos), job->roughness.get(pos));
|
||||
return biome.heightmap[biome.heightmap.size() - 1]->GetValue(worldPos.x + pos.x / 16.f, 0, worldPos.z + pos.z / 16.f);
|
||||
}, 4);
|
||||
// Generate Biome Topmap
|
||||
|
||||
glm::ivec3 lp;
|
||||
for (int m = 0; m < 4096; m++) {
|
||||
Vec::indAssignVec(m, lp);
|
||||
job->density[m] = (volume.get(lp) + heightmap.get(lp)) - (lp.y + worldPos.y * 16);
|
||||
}
|
||||
}
|
||||
std::vector<unsigned int> biomeMap {};
|
||||
biomeMap.resize((job.size * 16 + 1) * (job.size * 16 + 1));
|
||||
|
||||
void MapGen::buildElevationMap(chunk_partials_map& chunks, chunk_partial& chunk) {
|
||||
glm::ivec3 worldPos = chunk.second->pos;
|
||||
for (unsigned short i = 0; i < biomeMap.size(); i++) {
|
||||
glm::vec3 indPos = { i / (job.size * 16 + 1), 0, i % (job.size * 16 + 1)};
|
||||
glm::vec3 queryPos = indPos / 16.f / static_cast<float>(job.size);
|
||||
|
||||
MapGenJob* upperJob = nullptr;
|
||||
bool createdUpperJob = false;
|
||||
biomeMap[i] = this->biomes.getBiomeAt(job.temperature.get(queryPos),
|
||||
job.humidity.get(queryPos), job.roughness.get(queryPos)).index;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
const int x = i % 16;
|
||||
const int z = i / 16;
|
||||
// Generate Heightmap
|
||||
|
||||
short depth = 16;
|
||||
job.heightmap.populate([&](glm::vec3 pos) {
|
||||
glm::ivec3 blockPos = glm::ivec3(pos * 16.f * static_cast<float>(job.size));
|
||||
auto& biome = biomes.biomeFromId(biomeMap.at(blockPos.x * (job.size * 16 + 1) + blockPos.z));
|
||||
glm::vec3 worldPos = glm::vec3(job.pos) + pos * static_cast<float>(job.size);
|
||||
return biome.heightmap[biome.heightmap.size() - 1]->GetValue(worldPos.x, 0, worldPos.z);
|
||||
});
|
||||
|
||||
if (chunk.first->density[Space::Block::index({x, 15, z})] > 0) {
|
||||
if (!upperJob) {
|
||||
glm::ivec3 rel = worldPos + glm::ivec3 {0, 1, 0};
|
||||
if (chunks.count(rel) != 0) upperJob = chunks.at(rel).first;
|
||||
else {
|
||||
upperJob = new MapGenJob();
|
||||
buildDensityMap(upperJob, rel);
|
||||
createdUpperJob = true;
|
||||
// Determine Density Fill Behavior
|
||||
|
||||
int chunksBelowHeightmap = 0;
|
||||
for (unsigned int i = 0; i < job.size; i++) {
|
||||
for (unsigned int j = 0; j < job.size; j++) {
|
||||
glm::vec3 queryPos = {i / static_cast<float>(job.size), 0, i / static_cast<float>(job.size)};
|
||||
if (job.heightmap.get(queryPos) / 16 > job.pos.y + static_cast<int>(job.size) - 1) chunksBelowHeightmap++;
|
||||
}
|
||||
}
|
||||
// bool densityFillBehavior = chunksBelowHeightmap >= pow(job.size, 2) / 4;
|
||||
bool densityFillBehavior = true;
|
||||
if (densityFillBehavior) job.volume = NoiseSample({job.size * TERP, (job.size + 1) * TERP}, {1, 1.25});
|
||||
|
||||
job.volume.populate([&](glm::vec3 pos) {
|
||||
glm::ivec3 blockPos = glm::ivec3(pos * 16.f * static_cast<float>(job.size));
|
||||
auto& biome = biomes.biomeFromId(biomeMap.at(blockPos.x * (job.size * 16 + 1) + blockPos.z));
|
||||
glm::vec3 worldPos = glm::vec3(job.pos) + pos * static_cast<float>(job.size);
|
||||
return biome.volume[biome.volume.size() - 1]->GetValue(worldPos.x, worldPos.y, worldPos.z);
|
||||
});
|
||||
|
||||
// Generate Chunks
|
||||
|
||||
glm::ivec3 pos {};
|
||||
for (pos.x = 0; pos.x < job.size; pos.x++)
|
||||
for (pos.z = 0; pos.z < job.size; pos.z++) {
|
||||
std::unique_ptr<ChunkData> densityAbove = nullptr;
|
||||
for (pos.y = job.size - (densityFillBehavior ? 0 : 1); pos.y >= 0; pos.y--) {
|
||||
if (pos.y == job.size) {
|
||||
densityAbove = populateChunkDensity(job, pos);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<ChunkData> density = populateChunkDensity(job, pos);
|
||||
|
||||
std::unique_ptr<ChunkData> depth = populateChunkDepth(job, pos, density, std::move(densityAbove));
|
||||
|
||||
populateChunk(job, pos, biomeMap, *depth);
|
||||
|
||||
densityAbove = std::move(density);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (upperJob->density[Space::Block::index({ x, j, z })] <= 0) {
|
||||
depth = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else depth = 0;
|
||||
// generateSunlight(chunks, mbPos);
|
||||
|
||||
for (int y = 15; y >= 0; y--) {
|
||||
int ind = Space::Block::index({ x, y, z });
|
||||
depth = (chunk.first->density[ind] > 0 ? std::min(depth + 1, 16) : 0);
|
||||
chunk.first->depth[ind] = depth + (chunk.first->density[ind] - static_cast<int>(chunk.first->density[ind]));
|
||||
}
|
||||
}
|
||||
|
||||
if (createdUpperJob) delete upperJob;
|
||||
return std::move(job.chunks);
|
||||
}
|
||||
|
||||
void MapGen::generateBlocks(chunk_partial& chunk) {
|
||||
std::unique_ptr<Chunk> dupe = nullptr;
|
||||
if (chunk.second->partial) dupe = std::make_unique<Chunk>(*chunk.second);
|
||||
std::unique_ptr<MapGen::ChunkData> MapGen::populateChunkDensity(MapGen::Job &job, glm::ivec3 localPos) {
|
||||
auto data = std::make_unique<ChunkData>();
|
||||
|
||||
chunk.second->blocks = {};
|
||||
chunk.second->biomes = {};
|
||||
|
||||
std::array<std::array<unsigned short, 16>, 16> biomeArray {};
|
||||
for (unsigned short x = 0; x < 16; x++) {
|
||||
biomeArray[x] = {};
|
||||
for (unsigned short z = 0; z < 16; z++) {
|
||||
glm::ivec3 lp = {x, 0, z};
|
||||
biomeArray[x][z] = biomes.getBiomeAt(
|
||||
chunk.first->temperature.get(lp),
|
||||
chunk.first->humidity.get(lp),
|
||||
chunk.first->roughness.get(lp)).index;
|
||||
}
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
glm::ivec3 indPos = Space::Block::fromIndex(i);
|
||||
glm::vec3 queryPos = (glm::vec3(localPos) + glm::vec3(indPos) / 16.f) / static_cast<float>(job.size);
|
||||
(*data)[i] = (job.volume.get(queryPos) + job.heightmap.get({queryPos.x, 0, queryPos.z})) - ((job.pos.y + localPos.y) * 16 + indPos.y);
|
||||
}
|
||||
|
||||
for (unsigned short m = 0; m < 4096; m++) {
|
||||
glm::ivec3 lp = Space::Block::fromIndex(m);
|
||||
auto& biome = biomes.biomeFromId(biomeArray[lp.x][lp.z]);
|
||||
|
||||
unsigned int storedBlock = (chunk.second->blocks.size() <= 0 ? -1 : chunk.second->blocks[chunk.second->blocks.size() - 1]);
|
||||
unsigned int storedBiome = (chunk.second->biomes.size() <= 0 ? -1 : chunk.second->biomes[chunk.second->biomes.size() - 1]);
|
||||
|
||||
if (biome.index != storedBiome) {
|
||||
chunk.second->biomes.emplace_back(m);
|
||||
chunk.second->biomes.emplace_back(biome.index);
|
||||
}
|
||||
|
||||
int d = std::floor(chunk.first->depth[m]);
|
||||
unsigned int targetBlock
|
||||
= d <= 1 ? DefinitionAtlas::AIR
|
||||
: d <= 2 ? biome.topBlock
|
||||
: d <= 4 ? biome.soilBlock
|
||||
: biome.rockBlock;
|
||||
|
||||
if (targetBlock != storedBlock) {
|
||||
chunk.second->blocks.emplace_back(m);
|
||||
chunk.second->blocks.emplace_back(targetBlock);
|
||||
}
|
||||
}
|
||||
|
||||
if (dupe) for (unsigned short i = 0; i < 4096; i++) {
|
||||
unsigned int b = dupe->getBlock(i);
|
||||
if (b != DefinitionAtlas::INVALID) chunk.second->setBlock(i, b);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void MapGen::generateStructures(chunk_partials_map& chunks, chunk_partial& chunk) {
|
||||
std::default_random_engine generator(chunk.second->pos.x + chunk.second->pos.y * 30 + chunk.second->pos.z * 3.5);
|
||||
std::uniform_real_distribution<float> distribution(0, 1);
|
||||
|
||||
glm::ivec3 wp = chunk.second->pos;
|
||||
glm::ivec3 lp;
|
||||
std::unique_ptr<MapGen::ChunkData> MapGen::populateChunkDepth(Job& job, glm::ivec3 localPos, std::unique_ptr<ChunkData>& chunkDensity, std::unique_ptr<ChunkData> chunkDensityAbove) {
|
||||
auto data = std::make_unique<ChunkData>();
|
||||
|
||||
for (unsigned short i = 0; i < 256; i++) {
|
||||
unsigned short x = i / 16;
|
||||
unsigned short z = i % 16;
|
||||
glm::ivec2 pos = { i / 16, i % 16 };
|
||||
short depth = 16;
|
||||
|
||||
if (distribution(generator) > 0.97) {
|
||||
for (unsigned short y = 0; y < 16; y++) {
|
||||
lp = {x, y, z};
|
||||
unsigned short ind = Space::Block::index(lp);
|
||||
|
||||
if (chunk.first->depth[ind] > 0 && chunk.first->depth[ind] <= 1.1) {
|
||||
|
||||
glm::ivec3 off = {};
|
||||
glm::ivec3 p = wp * 16 + lp;
|
||||
|
||||
auto biome = biomes.biomeFromId(chunk.second->getBiome(ind));
|
||||
auto schematic = biome.schematics.size() > 0 ? biome.schematics[0] : nullptr;
|
||||
|
||||
if (schematic != nullptr) {
|
||||
if (!schematic->processed) schematic->process(defs);
|
||||
for (unsigned int j = 0; j < schematic->length(); j++) {
|
||||
schematic->assignOffset(j, off);
|
||||
setBlock(p + off - schematic->origin, schematic->blocks[j], chunks);
|
||||
}
|
||||
}
|
||||
if ((*chunkDensity)[Space::Block::index({pos.x, 15, pos.y})] > 0) {
|
||||
for (unsigned char j = 0; j < 16; j++) {
|
||||
if ((*chunkDensityAbove)[Space::Block::index({pos.x, j, pos.y})] <= 0) {
|
||||
depth = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
depth = 0;
|
||||
}
|
||||
|
||||
void MapGen::generateSunlight(MapGen::chunk_partials_map &chunks, glm::ivec3 mbPos) {
|
||||
std::queue<SunlightNode> sunlightQueue;
|
||||
|
||||
glm::ivec3 c {};
|
||||
for (c.x = 0; c.x < 4; c.x++) {
|
||||
for (c.z = 0; c.z < 4; c.z++) {
|
||||
c.y = 3;
|
||||
Chunk* chunk = chunks[mbPos * 4 + c].second;
|
||||
|
||||
glm::ivec3 b {};
|
||||
for (b.x = 0; b.x < 16; b.x++) {
|
||||
for (b.z = 0; b.z < 16; b.z++) {
|
||||
b.y = 15;
|
||||
|
||||
while (true) {
|
||||
unsigned int ind = Space::Block::index(b);
|
||||
if (defs.blockFromId(chunk->getBlock(ind)).lightPropagates) {
|
||||
chunk->setLight(ind, 3, 15);
|
||||
sunlightQueue.emplace(ind, chunk);
|
||||
}
|
||||
else {
|
||||
c.y = 3;
|
||||
chunk = chunks[mbPos * 4 + c].second;
|
||||
break;
|
||||
}
|
||||
|
||||
b.y--;
|
||||
if (b.y < 0) {
|
||||
b.y = 15;
|
||||
c.y = c.y ? c.y - 1 : 3;
|
||||
chunk = chunks[mbPos * 4 + c].second;
|
||||
if (c.y == 3) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (char y = 15; y >= 0; y--) {
|
||||
unsigned int ind = Space::Block::index({pos.x, y, pos.y});
|
||||
depth = ((*chunkDensity)[ind] > 0 ? std::min(depth + 1, 16) : 0);
|
||||
(*data)[ind] = depth + ((*chunkDensity)[ind] - static_cast<int>((*chunkDensity)[ind]));
|
||||
}
|
||||
}
|
||||
|
||||
propogateSunlightNodes(chunks, sunlightQueue);
|
||||
return data;
|
||||
}
|
||||
|
||||
bool MapGen::containsWorldPos(Chunk *chunk, glm::ivec3 pos) {
|
||||
return chunk && Space::Chunk::world::fromBlock(pos) == chunk->pos;
|
||||
}
|
||||
void MapGen::populateChunk(Job& job, glm::ivec3 localPos, std::vector<unsigned int> biomeMap, ChunkData& depthMap) {
|
||||
glm::ivec3 chunkPos = job.pos + localPos;
|
||||
auto& chunk = *(*job.chunks->emplace(chunkPos, std::make_shared<Chunk>(chunkPos)).first).second;
|
||||
|
||||
void MapGen::propogateSunlightNodes(MapGen::chunk_partials_map &chunks, std::queue<SunlightNode> &queue) {
|
||||
while (!queue.empty()) {
|
||||
SunlightNode& node = queue.front();
|
||||
unsigned int cBlockID = -1;
|
||||
unsigned int cBiomeID = -1;
|
||||
|
||||
unsigned char lightLevel = node.chunk->getLight(node.index, 3);
|
||||
glm::ivec3 worldPos = node.chunk->pos * 16 + Space::Block::fromIndex(node.index);
|
||||
for (unsigned short i = 0; i < 4096; i++) {
|
||||
glm::ivec3 indPos = Space::Block::fromIndex(i);
|
||||
|
||||
for (const auto& i : Vec::adj) {
|
||||
glm::ivec3 check = worldPos + i;
|
||||
unsigned int biomeID = biomeMap[(localPos.x * 16 + indPos.x) * (job.size * 16 + 1) + (localPos.z * 16 + indPos.z)];
|
||||
auto& biome = this->biomes.biomeFromId(biomeID);
|
||||
|
||||
Chunk* chunk;
|
||||
if (containsWorldPos(node.chunk, check)) chunk = node.chunk;
|
||||
else {
|
||||
glm::ivec3 worldPos = Space::Chunk::world::fromBlock(check);
|
||||
if (!chunks.count(worldPos)) continue;
|
||||
chunk = chunks[worldPos].second;
|
||||
if (!chunk) continue;
|
||||
}
|
||||
float depth = depthMap[i];
|
||||
unsigned int blockID
|
||||
= depth <= 1 ? DefinitionAtlas::AIR
|
||||
: depth <= 2 ? biome.topBlock
|
||||
: depth <= 4 ? biome.soilBlock
|
||||
: biome.rockBlock;
|
||||
|
||||
auto ind = Space::Block::index(check);
|
||||
if (defs.blockFromId(chunk->getBlock(ind)).lightPropagates && chunk->getLight(ind, 3) + 2 <= lightLevel) {
|
||||
chunk->setLight(ind, 3, lightLevel - static_cast<int>(!(lightLevel == 15 && i.y == -1)));
|
||||
queue.emplace(ind, chunk);
|
||||
}
|
||||
if (biomeID != cBiomeID) {
|
||||
chunk.biomes.emplace_back(i);
|
||||
chunk.biomes.emplace_back(biomeID);
|
||||
cBiomeID = biomeID;
|
||||
}
|
||||
|
||||
queue.pop();
|
||||
if (blockID != cBlockID) {
|
||||
chunk.blocks.emplace_back(i);
|
||||
chunk.blocks.emplace_back(blockID);
|
||||
cBlockID = blockID;
|
||||
}
|
||||
}
|
||||
|
||||
chunk.countRenderableBlocks();
|
||||
chunk.generated = true;
|
||||
}
|
||||
|
||||
void MapGen::setBlock(glm::ivec3 worldPos, unsigned int block, MapGen::chunk_partials_map &chunks) {
|
||||
if (block == DefinitionAtlas::INVALID) return;
|
||||
|
||||
glm::ivec3 chunkPos = Space::Chunk::world::fromBlock(worldPos);
|
||||
Chunk* chunk = nullptr;
|
||||
|
||||
if (chunks.count(chunkPos)) chunk = chunks.at(chunkPos).second;
|
||||
else {
|
||||
chunk = new Chunk();
|
||||
chunk->pos = chunkPos;
|
||||
chunk->partial = true;
|
||||
chunks.insert(std::pair<glm::ivec3, chunk_partial>{chunkPos, {new MapGenJob(), chunk}});
|
||||
}
|
||||
|
||||
unsigned int index = Space::Block::index(worldPos);
|
||||
if (chunk->getBlock(index) <= DefinitionAtlas::AIR) chunk->setBlock(index, block);
|
||||
}
|
||||
|
||||
std::shared_ptr<Chunk> MapGen::combinePartials(std::shared_ptr<Chunk> a, std::shared_ptr<Chunk> b) {
|
||||
std::shared_ptr<Chunk> src;
|
||||
std::shared_ptr<Chunk> res;
|
||||
|
||||
if (a->generated) {
|
||||
res = a;
|
||||
src = b;
|
||||
}
|
||||
else {
|
||||
res = b;
|
||||
src = a;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < 4096; i++) {
|
||||
if (src->getBlock(i) > DefinitionAtlas::INVALID) res->setBlock(i, src->getBlock(i));
|
||||
}
|
||||
|
||||
res->generated = src->generated || res->generated;
|
||||
res->partial = !res->generated;
|
||||
res->recalculateRenderableBlocks();
|
||||
return res;
|
||||
}
|
||||
//void MapGen::generateStructures(chunk_partials_map& chunks, chunk_partial& chunk) {
|
||||
// std::default_random_engine generator(chunk.second->pos.x + chunk.second->pos.y * 30 + chunk.second->pos.z * 3.5);
|
||||
// std::uniform_real_distribution<float> distribution(0, 1);
|
||||
//
|
||||
// glm::ivec3 wp = chunk.second->pos;
|
||||
// glm::ivec3 lp;
|
||||
//
|
||||
// for (unsigned short i = 0; i < 256; i++) {
|
||||
// unsigned short x = i / 16;
|
||||
// unsigned short z = i % 16;
|
||||
//
|
||||
// if (distribution(generator) > 0.97) {
|
||||
// for (unsigned short y = 0; y < 16; y++) {
|
||||
// lp = {x, y, z};
|
||||
// unsigned short ind = Space::Block::index(lp);
|
||||
//
|
||||
// if (chunk.first->depth[ind] > 0 && chunk.first->depth[ind] <= 1.1) {
|
||||
//
|
||||
// glm::ivec3 off = {};
|
||||
// glm::ivec3 p = wp * 16 + lp;
|
||||
//
|
||||
// auto biome = biomes.biomeFromId(chunk.second->getBiome(ind));
|
||||
// auto schematic = biome.schematics.size() > 0 ? biome.schematics[0] : nullptr;
|
||||
//
|
||||
// if (schematic != nullptr) {
|
||||
// if (!schematic->processed) schematic->process(defs);
|
||||
// for (unsigned int j = 0; j < schematic->length(); j++) {
|
||||
// schematic->assignOffset(j, off);
|
||||
// setBlock(p + off - schematic->origin, schematic->blocks[j], chunks);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void MapGen::generateSunlight(MapGen::chunk_partials_map &chunks, glm::ivec3 mbPos) {
|
||||
// std::queue<SunlightNode> sunlightQueue;
|
||||
//
|
||||
// glm::ivec3 c {};
|
||||
// for (c.x = 0; c.x < 4; c.x++) {
|
||||
// for (c.z = 0; c.z < 4; c.z++) {
|
||||
// c.y = 3;
|
||||
// Chunk* chunk = chunks[mbPos * 4 + c].second;
|
||||
//
|
||||
// glm::ivec3 b {};
|
||||
// for (b.x = 0; b.x < 16; b.x++) {
|
||||
// for (b.z = 0; b.z < 16; b.z++) {
|
||||
// b.y = 15;
|
||||
//
|
||||
// while (true) {
|
||||
// unsigned int ind = Space::Block::index(b);
|
||||
// if (defs.blockFromId(chunk->getBlock(ind)).lightPropagates) {
|
||||
// chunk->setLight(ind, 3, 15);
|
||||
// sunlightQueue.emplace(ind, chunk);
|
||||
// }
|
||||
// else {
|
||||
// c.y = 3;
|
||||
// chunk = chunks[mbPos * 4 + c].second;
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// b.y--;
|
||||
// if (b.y < 0) {
|
||||
// b.y = 15;
|
||||
// c.y = c.y ? c.y - 1 : 3;
|
||||
// chunk = chunks[mbPos * 4 + c].second;
|
||||
// if (c.y == 3) break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// propogateSunlightNodes(chunks, sunlightQueue);
|
||||
//}
|
||||
//
|
||||
//bool MapGen::containsWorldPos(Chunk *chunk, glm::ivec3 pos) {
|
||||
// return chunk && Space::Chunk::world::fromBlock(pos) == chunk->pos;
|
||||
//}
|
||||
//
|
||||
//void MapGen::propogateSunlightNodes(MapGen::chunk_partials_map &chunks, std::queue<SunlightNode> &queue) {
|
||||
// while (!queue.empty()) {
|
||||
// SunlightNode& node = queue.front();
|
||||
//
|
||||
// unsigned char lightLevel = node.chunk->getLight(node.index, 3);
|
||||
// glm::ivec3 worldPos = node.chunk->pos * 16 + Space::Block::fromIndex(node.index);
|
||||
//
|
||||
// for (const auto& i : Vec::adj) {
|
||||
// glm::ivec3 check = worldPos + i;
|
||||
//
|
||||
// Chunk* chunk;
|
||||
// if (containsWorldPos(node.chunk, check)) chunk = node.chunk;
|
||||
// else {
|
||||
// glm::ivec3 worldPos = Space::Chunk::world::fromBlock(check);
|
||||
// if (!chunks.count(worldPos)) continue;
|
||||
// chunk = chunks[worldPos].second;
|
||||
// if (!chunk) continue;
|
||||
// }
|
||||
//
|
||||
// auto ind = Space::Block::index(check);
|
||||
// if (defs.blockFromId(chunk->getBlock(ind)).lightPropagates && chunk->getLight(ind, 3) + 2 <= lightLevel) {
|
||||
// chunk->setLight(ind, 3, lightLevel - static_cast<int>(!(lightLevel == 15 && i.y == -1)));
|
||||
// queue.emplace(ind, chunk);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// queue.pop();
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void MapGen::setBlock(glm::ivec3 worldPos, unsigned int block, MapGen::chunk_partials_map &chunks) {
|
||||
// if (block == DefinitionAtlas::INVALID) return;
|
||||
//
|
||||
// glm::ivec3 chunkPos = Space::Chunk::world::fromBlock(worldPos);
|
||||
// Chunk* chunk = nullptr;
|
||||
//
|
||||
// if (chunks.count(chunkPos)) chunk = chunks.at(chunkPos).second;
|
||||
// else {
|
||||
// chunk = new Chunk();
|
||||
// chunk->pos = chunkPos;
|
||||
// chunk->partial = true;
|
||||
// chunks.insert(std::pair<glm::ivec3, chunk_partial>{chunkPos, {new MapGenJob(), chunk}});
|
||||
// }
|
||||
//
|
||||
// unsigned int index = Space::Block::index(worldPos);
|
||||
// if (chunk->getBlock(index) <= DefinitionAtlas::AIR) chunk->setBlock(index, block);
|
||||
//}
|
||||
//
|
||||
//std::shared_ptr<Chunk> MapGen::combinePartials(std::shared_ptr<Chunk> a, std::shared_ptr<Chunk> b) {
|
||||
// std::shared_ptr<Chunk> src;
|
||||
// std::shared_ptr<Chunk> res;
|
||||
//
|
||||
// if (a->generated) {
|
||||
// res = a;
|
||||
// src = b;
|
||||
// }
|
||||
// else {
|
||||
// res = b;
|
||||
// src = a;
|
||||
// }
|
||||
//
|
||||
// for (unsigned int i = 0; i < 4096; i++) {
|
||||
// if (src->getBlock(i) > DefinitionAtlas::INVALID) res->setBlock(i, src->getBlock(i));
|
||||
// }
|
||||
//
|
||||
// res->generated = src->generated || res->generated;
|
||||
// res->partial = !res->generated;
|
||||
// res->recalculateRenderableBlocks();
|
||||
// return res;
|
||||
//}
|
||||
|
|
|
@ -10,57 +10,82 @@
|
|||
#include <glm/vec3.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "MapGenProps.h"
|
||||
#include "NoiseSample.h"
|
||||
#include "../../util/Vec.h"
|
||||
|
||||
class Chunk;
|
||||
class MapGenJob;
|
||||
class BiomeAtlas;
|
||||
class MapGenProps;
|
||||
class DefinitionAtlas;
|
||||
|
||||
class MapGen {
|
||||
public:
|
||||
typedef std::pair<MapGenJob*, Chunk*> chunk_partial;
|
||||
typedef std::unordered_map<glm::ivec3, chunk_partial, Vec::ivec3> chunk_partials_map;
|
||||
constexpr static unsigned int BIOP = 4; // Biome Prop Precision
|
||||
constexpr static unsigned int TERP = 4; // Terrain Map Precision
|
||||
|
||||
MapGen(unsigned int seed, DefinitionAtlas& atlas, BiomeAtlas& biome, std::shared_ptr<MapGenProps> props);
|
||||
chunk_partials_map generateMapBlock(glm::ivec3 mbPos);
|
||||
typedef std::unordered_map<glm::ivec3, std::shared_ptr<Chunk>, Vec::ivec3> ChunkMap;
|
||||
|
||||
// Combine two chunk partials, or a chunk and a chunk partial.
|
||||
// If both are partials `b` takes preference, if one is a fully generated chunk the partial takes preference.
|
||||
static std::shared_ptr<Chunk> combinePartials(std::shared_ptr<Chunk> a, std::shared_ptr<Chunk> b);
|
||||
private:
|
||||
struct SunlightNode {
|
||||
SunlightNode(unsigned short index, Chunk* chunk) : index(index), chunk(chunk) {};
|
||||
unsigned short index;
|
||||
Chunk* chunk;
|
||||
struct Job {
|
||||
Job(glm::ivec3 pos, unsigned int size) :
|
||||
pos(pos), size(size),
|
||||
volume {size * TERP}, heightmap {{size * TERP, 0}},
|
||||
temperature {{size * BIOP, 0}}, roughness {{size * BIOP, 0}}, humidity {{size * BIOP, 0}} {}
|
||||
|
||||
glm::ivec3 pos {};
|
||||
unsigned int size {};
|
||||
|
||||
std::unique_ptr<ChunkMap> chunks = std::make_unique<ChunkMap>();
|
||||
|
||||
NoiseSample volume, heightmap;
|
||||
NoiseSample temperature, humidity, roughness;
|
||||
};
|
||||
|
||||
// Generate a chunk at `worldPos`, and place it and any partials in `chunks`.
|
||||
void generateChunk(chunk_partials_map& chunks, glm::ivec3 worldPos);
|
||||
typedef std::array<float, 4096> ChunkData;
|
||||
|
||||
// Build the density map for a job.
|
||||
void buildDensityMap(MapGenJob* job, glm::ivec3 worldPos);
|
||||
MapGen(DefinitionAtlas& atlas, BiomeAtlas& biome, unsigned int seed);
|
||||
|
||||
// Build the elevation map for a chunk, which uses the `chunks` array for efficiency.
|
||||
void buildElevationMap(chunk_partials_map& chunks, chunk_partial& chunk);
|
||||
std::unique_ptr<ChunkMap> generateChunk(glm::ivec3 pos);
|
||||
std::unique_ptr<ChunkMap> generateMapBlock(glm::ivec3 pos);
|
||||
std::unique_ptr<ChunkMap> generateArea(glm::ivec3 origin, unsigned int size = 1);
|
||||
|
||||
// Generate blocks and structures on a chunk, respectively. generateStructures can create partials.
|
||||
void generateBlocks(chunk_partial& chunk);
|
||||
void generateStructures(chunk_partials_map& chunks, chunk_partial& chunk);
|
||||
// // Combine two chunk partials, or a chunk and a chunk partial.
|
||||
// // If both are partials `b` takes preference, if one is a fully generated chunk the partial takes preference.
|
||||
// static std::shared_ptr<Chunk> combinePartials(std::shared_ptr<Chunk> a, std::shared_ptr<Chunk> b);
|
||||
private:
|
||||
// struct SunlightNode {
|
||||
// SunlightNode(unsigned short index, Chunk* chunk) : index(index), chunk(chunk) {};
|
||||
// unsigned short index;
|
||||
// Chunk* chunk;
|
||||
// };
|
||||
|
||||
// Generate sunlight on the mapgen threads to speed up perf
|
||||
void generateSunlight(chunk_partials_map& chunks, glm::ivec3 mbPos);
|
||||
static bool containsWorldPos(Chunk *chunk, glm::ivec3 pos);
|
||||
void propogateSunlightNodes(chunk_partials_map& chunks, std::queue<SunlightNode>& queue);
|
||||
static std::unique_ptr<ChunkData> populateChunkDensity(Job& job, glm::ivec3 localPos);
|
||||
static std::unique_ptr<ChunkData> populateChunkDepth(Job& job, glm::ivec3 localPos, std::unique_ptr<ChunkData>& chunkDensity, std::unique_ptr<ChunkData> chunkDensityAbove);
|
||||
|
||||
// Place block in the `chunks` array, creates a partial if necessary.
|
||||
static void setBlock(glm::ivec3 worldPos, unsigned int block, chunk_partials_map& chunks);
|
||||
void populateChunk(Job& job, glm::ivec3 localPos, std::vector<unsigned int> biomeMap, ChunkData& depthMap);
|
||||
|
||||
// // Builds the temperature, humidity, roughness, density, and depth maps.
|
||||
// void buildNoisemaps(Job& job);
|
||||
// // Generate a chunk at pos and insert it into the partials map.
|
||||
// void buildChunk(glm::ivec3 pos, Job& job, ChunkMap& chunks);
|
||||
// // Fill a ChunkData struct with data.
|
||||
// static void fillChunkData(glm::ivec3 pos, Job& job, ChunkData& data, Chunk& chunk, ChunkMap& chunks);
|
||||
// // Fill a Chunk with Blocks based on the Data object.
|
||||
// void fillBlocks(glm::ivec3 pos, Job &job, ChunkData& data, Chunk& chunk);
|
||||
// // Fill a Chunk with Structures based on the Data object.
|
||||
// void generateStructures(glm::ivec3 pos, Job& job, ChunkData& data, Chunk& chunk, ChunkMap& chunks);
|
||||
|
||||
// // Generate sunlight on the mapgen threads to speed up perf
|
||||
// void generateSunlight(ChunkMap& chunks, glm::ivec3 mbPos);
|
||||
// static bool containsWorldPos(Chunk *chunk, glm::ivec3 pos);
|
||||
// void propogateSunlightNodes(ChunkMap& chunks, std::queue<SunlightNode>& queue);
|
||||
//
|
||||
// // Place block in the `chunks` array, creates a partial if necessary.
|
||||
// static void setBlock(glm::ivec3 worldPos, unsigned int block, ChunkMap& chunks);
|
||||
|
||||
unsigned int seed = 0;
|
||||
|
||||
DefinitionAtlas& defs;
|
||||
BiomeAtlas& biomes;
|
||||
|
||||
std::shared_ptr<MapGenProps> props;
|
||||
MapGenProps props;
|
||||
};
|
|
@ -1,17 +0,0 @@
|
|||
//
|
||||
// Created by aurailus on 13/02/19.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "NoiseSample.h"
|
||||
|
||||
class MapGenJob {
|
||||
public:
|
||||
std::array<float, 4096> density {};
|
||||
std::array<float, 4096> depth {};
|
||||
|
||||
NoiseSample temperature, humidity, roughness;
|
||||
};
|
|
@ -8,6 +8,7 @@ MapGenProps::MapGenProps(unsigned int seed) : seed(seed) {
|
|||
temperatureBase.SetSeed(seed);
|
||||
temperatureBase.SetFrequency(0.02);
|
||||
temperatureBase.SetOctaveCount(4);
|
||||
temperatureTurbulence.SetSeed(seed);
|
||||
temperatureTurbulence.SetSourceModule(0, temperatureBase);
|
||||
temperatureTurbulence.SetRoughness(4);
|
||||
temperatureTurbulence.SetFrequency(0.2);
|
||||
|
@ -18,6 +19,7 @@ MapGenProps::MapGenProps(unsigned int seed) : seed(seed) {
|
|||
humidityBase.SetSeed(seed + 1);
|
||||
humidityBase.SetFrequency(0.02);
|
||||
humidityBase.SetOctaveCount(4);
|
||||
humidityTurbulence.SetSeed(seed + 1);
|
||||
humidityTurbulence.SetSourceModule(0, humidityBase);
|
||||
humidityTurbulence.SetRoughness(4);
|
||||
humidityTurbulence.SetFrequency(0.2);
|
||||
|
@ -28,6 +30,7 @@ MapGenProps::MapGenProps(unsigned int seed) : seed(seed) {
|
|||
roughnessBase.SetSeed(seed - 1);
|
||||
roughnessBase.SetFrequency(0.02);
|
||||
roughnessBase.SetOctaveCount(4);
|
||||
roughnessTurbulence.SetSeed(seed - 1);
|
||||
roughnessTurbulence.SetSourceModule(0, roughnessBase);
|
||||
roughnessTurbulence.SetRoughness(4);
|
||||
roughnessTurbulence.SetFrequency(0.2);
|
||||
|
|
|
@ -7,66 +7,54 @@
|
|||
#include "NoiseSample.h"
|
||||
|
||||
#include "../../util/Interp.h"
|
||||
#include "../../util/Util.h"
|
||||
|
||||
void NoiseSample::fill(const NoiseSample::fill_function &fun, float precision) {
|
||||
fill(fun, {precision, 1});
|
||||
}
|
||||
NoiseSample::NoiseSample(unsigned int precision, float scaleBy) : NoiseSample({precision, precision}, {scaleBy, scaleBy}) {}
|
||||
|
||||
void NoiseSample::fill(const NoiseSample::fill_function &fun, glm::ivec2 precision) {
|
||||
this->precision = precision;
|
||||
reserve();
|
||||
|
||||
float offsetH = 16.f / precision.x;
|
||||
float offsetV = 16.f / precision.y;
|
||||
|
||||
// Iterate over the array
|
||||
for (int i = 0; i <= precision.x; i++) {
|
||||
for (int j = 0; j <= (precision.y == 1 ? 0 : precision.y); j++) {
|
||||
for (int k = 0; k <= precision.x; k++) {
|
||||
set({i, j, k}, fun({ offsetH * i, offsetV * j, offsetH * k }));
|
||||
NoiseSample::NoiseSample(glm::ivec2 precision, glm::vec2 scaleBy) :
|
||||
precision(precision.x, precision.y, precision.x),
|
||||
scaleBy(scaleBy.x, scaleBy.y, scaleBy.x) {
|
||||
// Reserve space in the vector.
|
||||
for (unsigned int i = 0; i < this->precision.y + 1; i++) {
|
||||
data.emplace_back();
|
||||
for (unsigned int j = 0; j < this->precision.x + 1; j++) {
|
||||
data[i].emplace_back();
|
||||
for (unsigned int k = 0; k < this->precision.z + 1; k++) {
|
||||
data[i][j].emplace_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float NoiseSample::get(glm::ivec3 localPos) {
|
||||
assert(precision.x != 0);
|
||||
assert(precision.y != 0);
|
||||
|
||||
glm::vec3 prec3 {precision.x, precision.y, precision.x};
|
||||
|
||||
if (localPos.x == 16) localPos.x = 15;
|
||||
if (localPos.y == 16) localPos.y = 15;
|
||||
if (localPos.z == 16) localPos.z = 15;
|
||||
glm::ivec3 base = localPos / (glm::ivec3(16) / glm::ivec3(prec3));
|
||||
|
||||
const glm::vec3 factor = glm::floor(glm::mod(glm::vec3(localPos), (glm::vec3(16.f) / prec3))) / 16.f * prec3;
|
||||
|
||||
const auto& x0y0 = data[base.x][base.y];
|
||||
const auto& x1y0 = data[base.x + 1][base.y];
|
||||
|
||||
//No Vertical Interpolation
|
||||
if (precision.y <= 1) return Interp::bilerp(x0y0[base.z], x1y0[base.z], x0y0[base.z + 1], x1y0[base.z + 1], factor.x, factor.z);
|
||||
|
||||
const auto& x0y1 = data[base.x][base.y + 1];
|
||||
const auto& x1y1 = data[base.x + 1][base.y + 1];
|
||||
|
||||
return Interp::trilerp(
|
||||
x0y0[base.z], x1y0[base.z], x0y0[base.z + 1], x1y0[base.z + 1],
|
||||
x0y1[base.z], x1y1[base.z], x0y1[base.z + 1], x1y1[base.z + 1], factor.x, factor.z, factor.y);
|
||||
void NoiseSample::populate(const NoiseSample::fill_function &fn) {
|
||||
glm::vec3 pos;
|
||||
for (pos.x = 0; pos.x <= precision.x; pos.x++)
|
||||
for (pos.y = 0; pos.y <= precision.y; pos.y++)
|
||||
for (pos.z = 0; pos.z <= precision.z; pos.z++) {
|
||||
glm::vec3 queryPos = pos / glm::vec3(precision) * scaleBy;
|
||||
if (queryPos.y == NAN) queryPos.y = 0;
|
||||
data[pos.y][pos.x][pos.z] = fn(queryPos);
|
||||
}
|
||||
}
|
||||
|
||||
void NoiseSample::set(glm::ivec3 localPos, float value) {
|
||||
data[localPos.x][localPos.y][localPos.z] = value;
|
||||
}
|
||||
float NoiseSample::get(glm::vec3 pos) {
|
||||
glm::vec3 scaled = pos * glm::vec3(precision) / scaleBy;
|
||||
|
||||
void NoiseSample::reserve() {
|
||||
data.reserve(precision.x + 1);
|
||||
for (unsigned int i = 0; i <= precision.x; i++) {
|
||||
std::vector<std::vector<float>> subdata;
|
||||
subdata.reserve(precision.y + 1);
|
||||
for (int j = 0; j <= precision.y; j++)
|
||||
subdata.emplace_back(precision.x + 1);
|
||||
data.push_back(subdata);
|
||||
}
|
||||
}
|
||||
glm::vec3 a = glm::floor(scaled);
|
||||
glm::vec3 factor = scaled - glm::floor(scaled);
|
||||
glm::vec3 b = {fmin(a.x + ceil(factor.x), precision.x), fmin(a.y + ceil(factor.y), precision.y), fmin(a.z + ceil(factor.z), precision.z)};
|
||||
|
||||
assert(a.x + factor.x <= precision.x && a.y + factor.y <= precision.y && a.z + factor.z <= precision.z);
|
||||
|
||||
const auto& p00 = data[a.y][a.x];
|
||||
const auto& p10 = data[a.y][b.x];
|
||||
|
||||
// No vertical interpolation
|
||||
if (precision.y == 0) return Interp::bilerp(p00[a.z], p10[a.z], p00[b.z], p10[b.z], factor.x, factor.z);
|
||||
|
||||
const auto& p01 = data[b.y][a.x];
|
||||
const auto& p11 = data[b.y][b.x];
|
||||
|
||||
return Interp::trilerp(p00[a.z], p10[a.z], p00[b.z], p10[b.z],
|
||||
p01[a.z], p11[a.z], p01[b.z], p11[b.z], factor.x, factor.z, factor.y);
|
||||
}
|
||||
|
|
|
@ -11,19 +11,18 @@
|
|||
|
||||
class NoiseSample {
|
||||
public:
|
||||
typedef std::function<float(glm::ivec3 pos)> fill_function;
|
||||
typedef std::function<float(glm::vec3 pos)> fill_function;
|
||||
|
||||
NoiseSample() = default;
|
||||
NoiseSample(unsigned int precision, float scaleBy = 1);
|
||||
NoiseSample(glm::ivec2 precision, glm::vec2 scaleBy = {1, 1});
|
||||
|
||||
void fill(const fill_function& fun, float precision);
|
||||
void fill(const fill_function& fun, glm::ivec2 precision);
|
||||
|
||||
float get(glm::ivec3 localPos);
|
||||
void set(glm::ivec3 localPos, float value);
|
||||
void populate(const fill_function& fn);
|
||||
float get(glm::vec3 pos);
|
||||
private:
|
||||
void reserve();
|
||||
unsigned int length;
|
||||
|
||||
std::vector<std::vector<std::vector<float>>> data {};
|
||||
glm::ivec2 precision {};
|
||||
glm::ivec3 precision {};
|
||||
glm::vec3 scaleBy;
|
||||
};
|
||||
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
|
||||
#include "MeshPart.h"
|
||||
|
||||
#include "../texture/AtlasRef.h";
|
||||
#include "../texture/AtlasRef.h"
|
||||
|
||||
MeshPart::MeshPart(const std::vector<BlockModelVertex>& vertices, const std::vector<unsigned int>& indices,
|
||||
std::shared_ptr<AtlasRef> texture, unsigned int blendInd, std::shared_ptr<AtlasRef> blendMask) :
|
||||
std::shared_ptr<AtlasRef> texture, unsigned int blendInd, std::shared_ptr<AtlasRef> blendMask) :
|
||||
|
||||
vertices(vertices),
|
||||
indices(indices),
|
||||
texture(texture),
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
|
||||
MeshGenStream::MeshGenStream(ClientGame& game, LocalDimension &dimension) :
|
||||
game(game),
|
||||
dimension(dimension) {
|
||||
dimension(dimension),
|
||||
noiseSampler({NoiseSample {16}, NoiseSample {16}, NoiseSample {16}}) {
|
||||
|
||||
queuedTasks.reserve(static_cast<unsigned long>(TOTAL_QUEUE_SIZE));
|
||||
|
||||
|
@ -24,11 +25,10 @@ MeshGenStream::MeshGenStream(ClientGame& game, LocalDimension &dimension) :
|
|||
offsetTurbulence.SetFrequency(4.0);
|
||||
offsetTurbulence.SetPower(0.125);
|
||||
|
||||
noiseSampler = { NoiseSample {}, NoiseSample {}, NoiseSample {} };
|
||||
//8 is just a random value to offset results
|
||||
noiseSampler[0].fill([&](glm::ivec3 pos) -> float { return offsetTurbulence.GetValue(pos.x + 8, pos.y, pos.z); }, {16, 16});
|
||||
noiseSampler[1].fill([&](glm::ivec3 pos) -> float { return offsetTurbulence.GetValue(pos.x, pos.y + 8, pos.z); }, {16, 16});
|
||||
noiseSampler[2].fill([&](glm::ivec3 pos) -> float { return offsetTurbulence.GetValue(pos.x, pos.y, pos.z + 8); }, {16, 16});
|
||||
// 8 is just a random value to offset results
|
||||
noiseSampler[0].populate([&](glm::ivec3 pos) { return offsetTurbulence.GetValue(pos.x + 8, pos.y, pos.z); });
|
||||
noiseSampler[1].populate([&](glm::ivec3 pos) { return offsetTurbulence.GetValue(pos.x, pos.y + 8, pos.z); });
|
||||
noiseSampler[2].populate([&](glm::ivec3 pos) { return offsetTurbulence.GetValue(pos.x, pos.y, pos.z + 8); });
|
||||
|
||||
threads.reserve(THREADS);
|
||||
for (int i = 0; i < THREADS; i++) threads.emplace_back(game, noiseSampler);
|
||||
|
|
|
@ -6,15 +6,11 @@
|
|||
|
||||
#include "../../../net/PacketView.h"
|
||||
#include "../../../def/ClientGame.h"
|
||||
#include "../../../def/gen/MapGen.h"
|
||||
#include "../../../world/chunk/Chunk.h"
|
||||
|
||||
WorldInterpolationStream::WorldInterpolationStream(unsigned int seed, ClientGame& game) :
|
||||
props(std::make_shared<MapGenProps>(seed)),
|
||||
gen(new MapGen(seed, game.defs, game.biomes, props)) {
|
||||
|
||||
WorldInterpolationStream::WorldInterpolationStream(unsigned int seed, ClientGame& game) {
|
||||
threads.reserve(THREADS);
|
||||
for (int i = 0; i < THREADS; i++) threads.emplace_back(gen);
|
||||
for (int i = 0; i < THREADS; i++) threads.emplace_back(game, seed);
|
||||
}
|
||||
|
||||
void WorldInterpolationStream::queuePacket(std::unique_ptr<PacketView> p) {
|
||||
|
@ -34,14 +30,15 @@ std::unique_ptr<std::vector<std::shared_ptr<Chunk>>> WorldInterpolationStream::u
|
|||
auto finishedChunks = std::make_unique<std::vector<std::shared_ptr<Chunk>>>();
|
||||
// auto finishedMapBlocks = std::make_unique<std::vector<std::shared_ptr<MeshFarMap>>>();
|
||||
|
||||
for (auto& t : threads) {
|
||||
for (auto& u : t.tasks) {
|
||||
if (u.locked) continue;
|
||||
for (unsigned int i = 0; i < THREAD_QUEUE_SIZE; i++) {
|
||||
for (auto& t : threads) {
|
||||
auto& j = t.jobs[i];
|
||||
if (j.locked) continue;
|
||||
|
||||
if (u.chunk != nullptr) {
|
||||
finishedChunks->push_back(u.chunk);
|
||||
u.chunk = nullptr;
|
||||
u.job = JobType::EMPTY;
|
||||
if (j.chunk != nullptr) {
|
||||
finishedChunks->push_back(j.chunk);
|
||||
j.chunk = nullptr;
|
||||
j.job = JobType::EMPTY;
|
||||
}
|
||||
// else if (u.mapblock != nullptr) {
|
||||
// finishedMapBlocks->push_back(u.mapblock);
|
||||
|
@ -54,9 +51,9 @@ std::unique_ptr<std::vector<std::shared_ptr<Chunk>>> WorldInterpolationStream::u
|
|||
auto packet = std::move(*it);
|
||||
queuedPacketTasks.erase(it);
|
||||
|
||||
u.job = JobType::PACKET;
|
||||
u.packet = std::move(packet);
|
||||
u.locked = true;
|
||||
j.job = JobType::PACKET;
|
||||
j.packet = std::move(packet);
|
||||
j.locked = true;
|
||||
}
|
||||
else if (!queuedInterpTasks.empty()) {
|
||||
auto it = queuedInterpTasks.begin();
|
||||
|
@ -64,9 +61,9 @@ std::unique_ptr<std::vector<std::shared_ptr<Chunk>>> WorldInterpolationStream::u
|
|||
queuedInterpTasks.erase(it);
|
||||
queuedInterpMap.erase(pos);
|
||||
|
||||
u.job = JobType::FARMAP;
|
||||
u.mapBlockPos = pos;
|
||||
u.locked = true;
|
||||
j.job = JobType::FARMAP;
|
||||
j.mapBlockPos = pos;
|
||||
j.locked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,24 +71,25 @@ std::unique_ptr<std::vector<std::shared_ptr<Chunk>>> WorldInterpolationStream::u
|
|||
return finishedChunks;
|
||||
}
|
||||
|
||||
WorldInterpolationStream::Thread::Thread(MapGen* gen) : gen(gen),
|
||||
WorldInterpolationStream::Thread::Thread(ClientGame& game, unsigned int seed) :
|
||||
gen(game.defs, game.biomes, seed),
|
||||
thread(std::bind(&WorldInterpolationStream::Thread::exec, this)) {}
|
||||
|
||||
void WorldInterpolationStream::Thread::exec() {
|
||||
while (!kill) {
|
||||
bool empty = true;
|
||||
for (Job& u : tasks) {
|
||||
for (Job& u : jobs) {
|
||||
if (u.locked) {
|
||||
if (u.job == JobType::PACKET) {
|
||||
empty = false;
|
||||
u.chunk = std::make_shared<Chunk>();
|
||||
u.chunk->deserialize(u.packet->d);
|
||||
u.locked = false;
|
||||
break;
|
||||
}
|
||||
else if (u.job == JobType::FARMAP) {
|
||||
throw std::runtime_error("Farmap no exist yet.");
|
||||
}
|
||||
// break;
|
||||
}
|
||||
}
|
||||
if (empty) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
|
|
@ -12,17 +12,16 @@
|
|||
#include <unordered_set>
|
||||
|
||||
#include "../../../util/Vec.h"
|
||||
#include "../../../def/gen/MapGen.h"
|
||||
|
||||
class Chunk;
|
||||
class MapGen;
|
||||
class ClientGame;
|
||||
class MapGenProps;
|
||||
class PacketView;
|
||||
|
||||
class WorldInterpolationStream {
|
||||
public:
|
||||
static const int THREADS = 4;
|
||||
static const int THREAD_QUEUE_SIZE = 32;
|
||||
static const int THREAD_QUEUE_SIZE = 64;
|
||||
|
||||
WorldInterpolationStream(unsigned int seed, ClientGame& game);
|
||||
|
||||
|
@ -55,19 +54,17 @@ private:
|
|||
};
|
||||
|
||||
struct Thread {
|
||||
explicit Thread(MapGen* gen);
|
||||
explicit Thread(ClientGame& game, unsigned int seed);
|
||||
void exec();
|
||||
|
||||
MapGen* gen;
|
||||
std::vector<Job> tasks = std::vector<Job>(THREAD_QUEUE_SIZE);
|
||||
|
||||
bool kill = false;
|
||||
|
||||
std::vector<Job> jobs = std::vector<Job>(THREAD_QUEUE_SIZE);
|
||||
|
||||
MapGen gen;
|
||||
std::thread thread;
|
||||
};
|
||||
|
||||
std::shared_ptr<MapGenProps> props;
|
||||
MapGen* gen;
|
||||
|
||||
std::vector<Thread> threads;
|
||||
std::list<std::unique_ptr<PacketView>> queuedPacketTasks;
|
||||
std::unordered_set<glm::vec3, Vec::vec3> queuedInterpMap;
|
||||
|
|
|
@ -68,11 +68,11 @@ ChunkMeshGenerator::ChunkMeshGenerator(ChunkMeshDetails* meshDetails, LocalDefin
|
|||
default: break;
|
||||
|
||||
case MeshMod::OFFSET_X:
|
||||
vis.x += blockOffsets[0].get(off) * mod.second; break;
|
||||
vis.x += blockOffsets[0].get(vis / 16.f) * mod.second; break;
|
||||
case MeshMod::OFFSET_Y:
|
||||
vis.y += blockOffsets[1].get(off) * mod.second; break;
|
||||
vis.y += blockOffsets[1].get(vis / 16.f) * mod.second; break;
|
||||
case MeshMod::OFFSET_Z:
|
||||
vis.z += blockOffsets[2].get(off) * mod.second; break;
|
||||
vis.z += blockOffsets[2].get(vis / 16.f) * mod.second; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,14 +6,10 @@
|
|||
|
||||
#include "../../../def/ServerGame.h"
|
||||
#include "../../../world/chunk/Chunk.h"
|
||||
#include "../../../def/gen/MapGenProps.h"
|
||||
|
||||
ServerGenStream::ServerGenStream(unsigned int seed, ServerGame& game) :
|
||||
props(std::make_shared<MapGenProps>(seed)),
|
||||
gen(seed, game.defs, game.biomes, props) {
|
||||
|
||||
ServerGenStream::ServerGenStream(unsigned int seed, ServerGame& game) {
|
||||
threads.reserve(THREADS);
|
||||
for (int i = 0; i < THREADS; i++) threads.emplace_back(&gen);
|
||||
for (int i = 0; i < THREADS; i++) threads.emplace_back(game, seed);
|
||||
}
|
||||
|
||||
bool ServerGenStream::queue(glm::vec3 pos) {
|
||||
|
@ -28,14 +24,15 @@ bool ServerGenStream::queue(glm::vec3 pos) {
|
|||
std::unique_ptr<std::vector<ServerGenStream::FinishedBlockJob>> ServerGenStream::update() {
|
||||
auto finishedChunks = std::make_unique<std::vector<FinishedBlockJob>>();
|
||||
|
||||
for (auto& t : threads) {
|
||||
for (auto& u : t.tasks) {
|
||||
if (u.locked) continue;
|
||||
for (unsigned int i = 0; i < THREAD_QUEUE_SIZE; i++) {
|
||||
for (auto& t : threads) {
|
||||
auto& j = t.jobs[i];
|
||||
if (j.locked) continue;
|
||||
|
||||
if (!u.chunks.empty()) {
|
||||
finishedChunks->push_back({u.pos, {}});
|
||||
for (auto chunk : u.chunks) finishedChunks->back().chunks.push_back(std::shared_ptr<Chunk>(chunk.second.second));
|
||||
u.chunks.clear();
|
||||
if (j.generated) {
|
||||
finishedChunks->push_back({j.pos, {}});
|
||||
for (auto chunkPair : *j.generated) finishedChunks->back().chunks.push_back(chunkPair.second);
|
||||
j.generated = nullptr;
|
||||
}
|
||||
|
||||
if (!queuedTasks.empty()) {
|
||||
|
@ -44,8 +41,8 @@ std::unique_ptr<std::vector<ServerGenStream::FinishedBlockJob>> ServerGenStream:
|
|||
queuedTasks.erase(it);
|
||||
queuedMap.erase(pos);
|
||||
|
||||
u.pos = pos;
|
||||
u.locked = true;
|
||||
j.pos = pos;
|
||||
j.locked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,18 +50,18 @@ std::unique_ptr<std::vector<ServerGenStream::FinishedBlockJob>> ServerGenStream:
|
|||
return finishedChunks;
|
||||
}
|
||||
|
||||
ServerGenStream::Thread::Thread(MapGen *gen) : gen(gen),
|
||||
ServerGenStream::Thread::Thread(ServerGame& game, unsigned int seed) :
|
||||
gen(game.defs, game.biomes, seed),
|
||||
thread(std::bind(&ServerGenStream::Thread::exec, this)) {}
|
||||
|
||||
void ServerGenStream::Thread::exec() {
|
||||
while (!kill) {
|
||||
bool empty = true;
|
||||
for (Job& u : tasks) {
|
||||
if (u.locked) {
|
||||
for (Job& j : jobs) {
|
||||
if (j.locked) {
|
||||
empty = false;
|
||||
u.chunks = gen->generateMapBlock(u.pos);
|
||||
u.locked = false;
|
||||
break;
|
||||
j.generated = gen.generateMapBlock(j.pos);
|
||||
j.locked = false;
|
||||
}
|
||||
}
|
||||
if (empty) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
|
|
@ -14,7 +14,7 @@ class ServerGame;
|
|||
|
||||
class ServerGenStream {
|
||||
public:
|
||||
static const int THREADS = 4;
|
||||
static const int THREADS = 6;
|
||||
static const int THREAD_QUEUE_SIZE = 6;
|
||||
|
||||
struct FinishedBlockJob {
|
||||
|
@ -35,23 +35,21 @@ private:
|
|||
bool locked = false;
|
||||
|
||||
glm::ivec3 pos {};
|
||||
MapGen::chunk_partials_map chunks {};
|
||||
std::unique_ptr<MapGen::ChunkMap> generated = nullptr;
|
||||
};
|
||||
|
||||
struct Thread {
|
||||
explicit Thread(MapGen* gen);
|
||||
explicit Thread(ServerGame& game, unsigned int seed);
|
||||
void exec();
|
||||
|
||||
MapGen* gen;
|
||||
std::vector<Job> tasks = std::vector<Job>(THREAD_QUEUE_SIZE);
|
||||
|
||||
bool kill = false;
|
||||
|
||||
std::vector<Job> jobs = std::vector<Job>(THREAD_QUEUE_SIZE);
|
||||
|
||||
MapGen gen;
|
||||
std::thread thread;
|
||||
};
|
||||
|
||||
std::shared_ptr<MapGenProps> props;
|
||||
MapGen gen;
|
||||
|
||||
std::vector<Thread> threads;
|
||||
std::list<glm::vec3> queuedTasks;
|
||||
std::unordered_set<glm::vec3, Vec::vec3> queuedMap;
|
||||
|
|
|
@ -73,17 +73,17 @@ void ServerWorld::update(double delta) {
|
|||
|
||||
std::unordered_set<glm::ivec3, Vec::ivec3> changed {};
|
||||
|
||||
for (auto& mb : *finished) {
|
||||
for (const auto& chunk : mb.chunks) {
|
||||
for (auto& data : *finished) {
|
||||
for (const auto& chunk : data.chunks) {
|
||||
changed.insert(chunk->pos);
|
||||
dimension.setChunk(chunk);
|
||||
// fileManip->commitChunk(*chunk);
|
||||
}
|
||||
|
||||
auto resend = dimension.calculateEdgeLight(mb.pos);
|
||||
changed.insert(resend.begin(), resend.end());
|
||||
// auto resend = dimension.calculateEdgeLight(mb.pos);
|
||||
// changed.insert(resend.begin(), resend.end());
|
||||
|
||||
dimension.getMapBlock(mb.pos)->generated = true;
|
||||
auto mb = dimension.getMapBlock(data.pos)->generated = true;
|
||||
}
|
||||
|
||||
for (auto& chunk : changed) {
|
||||
|
|
|
@ -30,29 +30,30 @@ namespace Space {
|
|||
};
|
||||
}
|
||||
|
||||
inline glm::ivec3 sectionFromGlobal(glm::ivec3 pos, int size) {
|
||||
inline glm::ivec3 sectionFromGlobal(glm::ivec3 pos, float size) {
|
||||
return {
|
||||
std::floor(static_cast<float>(pos.x) / size),
|
||||
std::floor(static_cast<float>(pos.y) / size),
|
||||
std::floor(static_cast<float>(pos.z) / size)};
|
||||
std::floor(static_cast<float>(pos.z) / size)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace Region {
|
||||
namespace world {
|
||||
// Get a Region engine position from a MapBlock's world position.
|
||||
static inline glm::ivec3 fromMapBlock(const glm::ivec3& mapBlock) {
|
||||
return sectionFromGlobal(mapBlock, REGION_SIZE);
|
||||
// Get a Region world position from a MapBlock's world position.
|
||||
static inline glm::ivec3 fromMapBlock(const glm::ivec3& pos) {
|
||||
return sectionFromGlobal(pos, REGION_SIZE);
|
||||
}
|
||||
|
||||
// Get a Region engine position from a Chunk's world position.
|
||||
static inline glm::ivec3 fromChunk(const glm::ivec3 &chunk) {
|
||||
return sectionFromGlobal(chunk, REGION_CHUNK_LENGTH);
|
||||
// Get a Region world position from a Chunk's world position.
|
||||
static inline glm::ivec3 fromChunk(const glm::ivec3& pos) {
|
||||
return sectionFromGlobal(pos, REGION_CHUNK_LENGTH);
|
||||
}
|
||||
|
||||
// Get a Region engine position from a Block's world position.
|
||||
static inline glm::ivec3 fromBlock(const glm::ivec3 &chunk) {
|
||||
return sectionFromGlobal(chunk, REGION_BLOCK_LENGTH);
|
||||
// Get a Region world position from a Block's world position.
|
||||
static inline glm::ivec3 fromBlock(const glm::ivec3& pos) {
|
||||
return sectionFromGlobal(pos, REGION_BLOCK_LENGTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,14 +67,19 @@ namespace Space {
|
|||
}
|
||||
|
||||
namespace world {
|
||||
// Get a MapBlock engine position from a Chunk's world position.
|
||||
static inline glm::ivec3 fromChunk(const glm::ivec3 &chunk) {
|
||||
return sectionFromGlobal(chunk, MAPBLOCK_SIZE);
|
||||
// Get a MapBlock world position from a Region's world position.
|
||||
static inline glm::ivec3 fromRegion(const glm::ivec3& pos) {
|
||||
return sectionFromGlobal(pos, 1.f / REGION_SIZE);
|
||||
}
|
||||
|
||||
// Get a MapBlock engine position from a Block's world position.
|
||||
static inline glm::ivec3 fromBlock(const glm::ivec3 &vec) {
|
||||
return sectionFromGlobal(vec, MAPBLOCK_BLOCK_LENGTH);
|
||||
// Get a MapBlock world position from a Chunk's world position.
|
||||
static inline glm::ivec3 fromChunk(const glm::ivec3 &pos) {
|
||||
return sectionFromGlobal(pos, MAPBLOCK_SIZE);
|
||||
}
|
||||
|
||||
// Get a MapBlock world position from a Block's world position.
|
||||
static inline glm::ivec3 fromBlock(const glm::ivec3 &pos) {
|
||||
return sectionFromGlobal(pos, MAPBLOCK_BLOCK_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,6 +105,16 @@ namespace Space {
|
|||
}
|
||||
|
||||
namespace world {
|
||||
// Get a Chunk world position from a Regions's world position.
|
||||
static inline glm::ivec3 fromRegion(const glm::ivec3& pos) {
|
||||
return sectionFromGlobal(pos, 1.f / REGION_CHUNK_LENGTH);
|
||||
}
|
||||
|
||||
// Get a Chunk world position from a MapBlock's world position.
|
||||
static inline glm::ivec3 fromMapBlock(const glm::ivec3& pos) {
|
||||
return sectionFromGlobal(pos, 1.f / MAPBLOCK_CHUNK_LENGTH);
|
||||
}
|
||||
|
||||
// Get a Chunk world position from a Block's world position.
|
||||
static inline glm::ivec3 fromBlock(const glm::ivec3& pos) {
|
||||
return sectionFromGlobal(pos, CHUNK_BLOCK_LENGTH);
|
||||
|
@ -140,6 +156,23 @@ namespace Space {
|
|||
static inline glm::ivec3 toRegion(const glm::ivec3& pos) {
|
||||
return localFromGlobal(pos, REGION_BLOCK_LENGTH);
|
||||
}
|
||||
|
||||
namespace World {
|
||||
// Get a Block world position from a Regions's world position.
|
||||
static inline glm::ivec3 fromRegion(const glm::ivec3& pos) {
|
||||
return sectionFromGlobal(pos, 1.f / REGION_BLOCK_LENGTH);
|
||||
}
|
||||
|
||||
// Get a Block world position from a MapBlock's world position.
|
||||
static inline glm::ivec3 fromMapBlock(const glm::ivec3& pos) {
|
||||
return sectionFromGlobal(pos, 1.f / MAPBLOCK_BLOCK_LENGTH);
|
||||
}
|
||||
|
||||
// Get a Block world position from a Chunk's world position.
|
||||
static inline glm::ivec3 fromChunk(const glm::ivec3& pos) {
|
||||
return sectionFromGlobal(pos, CHUNK_BLOCK_LENGTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the index of a Block within its Chunk from its local or world position.
|
||||
|
|
|
@ -47,7 +47,7 @@ std::shared_ptr<Chunk> DimensionBase::getChunk(glm::ivec3 chunkPosition) {
|
|||
|
||||
void DimensionBase::setChunk(std::shared_ptr<Chunk> chunk) {
|
||||
auto mapBlock = getOrCreateMapBlock(Space::MapBlock::world::fromChunk(chunk->pos));
|
||||
(*mapBlock).set(Space::Chunk::index(chunk->pos), chunk);
|
||||
mapBlock->set(Space::Chunk::index(chunk->pos), chunk);
|
||||
}
|
||||
|
||||
void DimensionBase::removeChunk(glm::ivec3 pos){
|
||||
|
@ -86,6 +86,6 @@ std::shared_ptr<MapBlock> DimensionBase::getOrCreateMapBlock(glm::ivec3 mapBlock
|
|||
unsigned int index = Space::MapBlock::index(mapBlockPosition);
|
||||
|
||||
if ((*region)[index] != nullptr) return (*region)[index];
|
||||
(*region).set(index, std::make_shared<MapBlock>(mapBlockPosition));
|
||||
region->set(index, std::make_shared<MapBlock>(mapBlockPosition));
|
||||
return (*region)[index];
|
||||
}
|
||||
|
|
|
@ -49,8 +49,9 @@ bool ServerDimension::setBlock(glm::ivec3 pos, unsigned int block) {
|
|||
|
||||
void ServerDimension::setChunk(std::shared_ptr<Chunk> chunk) {
|
||||
// Combine partials if there are any
|
||||
std::shared_ptr<Chunk> existing = getChunk(chunk->pos);
|
||||
if (existing != nullptr) chunk = MapGen::combinePartials(chunk, existing);
|
||||
//TODO: Reimplement partial handling
|
||||
// std::shared_ptr<Chunk> existing = getChunk(chunk->pos);
|
||||
// if (existing != nullptr) chunk = MapGen::combinePartials(chunk, existing);
|
||||
|
||||
Dimension::setChunk(chunk);
|
||||
glm::vec3 mb = Space::MapBlock::world::fromChunk(chunk->pos);
|
||||
|
|
|
@ -12,27 +12,26 @@
|
|||
#include "../../net/Serializer.h"
|
||||
#include "../../net/Deserializer.h"
|
||||
|
||||
Chunk::Chunk(const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes) :
|
||||
Chunk(blocks, biomes, {0, 0, 0}) {}
|
||||
|
||||
Chunk::Chunk(const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes, glm::ivec3 pos) :
|
||||
blocks(std::move(blocks)), biomes(std::move(biomes)),
|
||||
generated(true), pos(pos) {
|
||||
recalculateRenderableBlocks();
|
||||
}
|
||||
|
||||
Chunk::Chunk(const Chunk& o) :
|
||||
partial(o.partial),
|
||||
generated(o.generated),
|
||||
dirty(o.dirty),
|
||||
shouldRender(o.shouldRender),
|
||||
pos(o.pos),
|
||||
dirty(o.dirty),
|
||||
blocks(o.blocks),
|
||||
biomes(o.biomes),
|
||||
blockLight(o.blockLight),
|
||||
partial(o.partial),
|
||||
sunLight(o.sunLight),
|
||||
generated(o.generated),
|
||||
blockLight(o.blockLight),
|
||||
shouldRender(o.shouldRender),
|
||||
renderableBlocks(o.renderableBlocks) {}
|
||||
|
||||
Chunk::Chunk(glm::ivec3 pos) : pos(pos) {}
|
||||
|
||||
Chunk::Chunk(glm::ivec3 pos, const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes) :
|
||||
blocks(std::move(blocks)), biomes(std::move(biomes)),
|
||||
generated(true), pos(pos) {
|
||||
countRenderableBlocks();
|
||||
}
|
||||
|
||||
bool Chunk::setBlock(unsigned int ind, unsigned int blk) {
|
||||
if (!RIE::write(ind, blk, blocks, 4096)) return false;
|
||||
if (blk == DefinitionAtlas::AIR && !(renderableBlocks = std::max(renderableBlocks - 1, 0))) shouldRender = false;
|
||||
|
@ -99,10 +98,10 @@ void Chunk::deserialize(Deserializer& d) {
|
|||
this->sunLight[i] = sl.s;
|
||||
}
|
||||
|
||||
recalculateRenderableBlocks();
|
||||
countRenderableBlocks();
|
||||
}
|
||||
|
||||
void Chunk::recalculateRenderableBlocks() {
|
||||
void Chunk::countRenderableBlocks() {
|
||||
shouldRender = false;
|
||||
renderableBlocks = 0;
|
||||
|
||||
|
|
|
@ -35,9 +35,9 @@ public:
|
|||
typedef union { char ch; SunLight s; } sunlight_union;
|
||||
|
||||
Chunk() = default;
|
||||
explicit Chunk(const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes);
|
||||
Chunk(const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes, glm::ivec3 pos);
|
||||
Chunk(const Chunk& o);
|
||||
explicit Chunk(glm::ivec3 pos);
|
||||
Chunk(glm::ivec3 pos, const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes);
|
||||
|
||||
inline std::unique_lock<std::mutex> aquireLock();
|
||||
|
||||
|
@ -65,7 +65,7 @@ public:
|
|||
std::string serialize();
|
||||
void deserialize(Deserializer& d);
|
||||
|
||||
void recalculateRenderableBlocks();
|
||||
void countRenderableBlocks();
|
||||
|
||||
bool partial = false;
|
||||
bool generated = false;
|
||||
|
@ -73,8 +73,7 @@ public:
|
|||
bool dirty = true;
|
||||
bool shouldRender = true;
|
||||
|
||||
glm::ivec3 pos;
|
||||
|
||||
glm::ivec3 pos {};
|
||||
private:
|
||||
std::mutex m;
|
||||
|
||||
|
|
|
@ -12,16 +12,16 @@ zepha.register_block("@aurailus:tnt:tnt", {
|
|||
pick = 2
|
||||
},
|
||||
drop = "@aurailus:tnt:tnt",
|
||||
on_break = function(pos)
|
||||
local amp = 20
|
||||
for i = -amp, amp do
|
||||
for j = -amp, amp do
|
||||
for k = -amp, amp do
|
||||
if V{i, j, k}:distance(V()) < amp then
|
||||
zepha.set_block(pos + offset, "air")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- on_break = function(pos)
|
||||
-- local amp = 20
|
||||
-- for i = -amp, amp do
|
||||
-- for j = -amp, amp do
|
||||
-- for k = -amp, amp do
|
||||
-- if V{i, j, k}:distance(V()) < amp then
|
||||
-- zepha.set_block(pos + offset, "air")
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
})
|
|
@ -1,7 +1,11 @@
|
|||
zepha.register_block("zeus:default:sandstone", {
|
||||
name = "Sandstone",
|
||||
model = "base:block",
|
||||
textures = {"zeus:default:sandstone"},
|
||||
textures = {
|
||||
"zeus:default:sandstone_top",
|
||||
"zeus:default:sandstone_top",
|
||||
"zeus:default:sandstone"
|
||||
},
|
||||
toughness = {
|
||||
hand = 14,
|
||||
pick = 3
|
||||
|
|
|
@ -48,7 +48,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
|
||||
SECTION("Blocks") {
|
||||
SECTION("Exact index = 0, strip one after") {
|
||||
Chunk b {{0, 1, 1, 0}, {}};
|
||||
Chunk b {{}, {0, 1, 1, 0}, {}};
|
||||
|
||||
b.setBlock(0, 2);
|
||||
|
||||
|
@ -60,7 +60,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
}
|
||||
|
||||
SECTION("Exact index, last block same, strip one after") {
|
||||
Chunk b {{0, 1, 1, 0, 2, 5}, {}};
|
||||
Chunk b {{}, {0, 1, 1, 0, 2, 5}, {}};
|
||||
|
||||
b.setBlock(1, 1);
|
||||
|
||||
|
@ -72,7 +72,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
}
|
||||
|
||||
SECTION("Exact index, last block same, strip two after") {
|
||||
Chunk b {{0, 1, 2, 0, 4, 5}, {}};
|
||||
Chunk b {{}, {0, 1, 2, 0, 4, 5}, {}};
|
||||
|
||||
b.setBlock(2, 1);
|
||||
|
||||
|
@ -96,7 +96,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
}
|
||||
|
||||
SECTION("Exact index, last block same, no strip after") {
|
||||
Chunk b {{0, 1, 1, 0}, {}};
|
||||
Chunk b {{}, {0, 1, 1, 0}, {}};
|
||||
|
||||
b.setBlock(1, 1);
|
||||
|
||||
|
@ -108,7 +108,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
}
|
||||
|
||||
SECTION("Exact index, last block different, strip one after") {
|
||||
Chunk b {{0, 1, 1, 0, 2, 5}, {}};
|
||||
Chunk b {{}, {0, 1, 1, 0, 2, 5}, {}};
|
||||
|
||||
b.setBlock(1, 2);
|
||||
|
||||
|
@ -122,7 +122,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
}
|
||||
|
||||
SECTION("Exact index, last block different, strip two after") {
|
||||
Chunk b {{0, 1, 2, 0, 4, 5}, {}};
|
||||
Chunk b {{}, {0, 1, 2, 0, 4, 5}, {}};
|
||||
|
||||
b.setBlock(2, 2);
|
||||
|
||||
|
@ -164,7 +164,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
}
|
||||
|
||||
SECTION("Exact index, last block different, no strip after") {
|
||||
Chunk b {{0, 1, 1, 0}, {}};
|
||||
Chunk b {{}, {0, 1, 1, 0}, {}};
|
||||
|
||||
b.setBlock(1, 2);
|
||||
|
||||
|
@ -178,7 +178,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
}
|
||||
|
||||
SECTION("Greater index, last block same, strip one after") {
|
||||
Chunk b {{0, 1, 1, 0, 3, 5}, {}};
|
||||
Chunk b {{}, {0, 1, 1, 0, 3, 5}, {}};
|
||||
|
||||
b.setBlock(2, 0);
|
||||
|
||||
|
@ -193,7 +193,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
}
|
||||
|
||||
SECTION("Greater index, last block same, strip two after") {
|
||||
Chunk b {{0, 1, 2, 0, 5, 5}, {}};
|
||||
Chunk b {{}, {0, 1, 2, 0, 5, 5}, {}};
|
||||
|
||||
b.setBlock(3, 0);
|
||||
|
||||
|
@ -208,7 +208,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
}
|
||||
|
||||
SECTION("Greater index, last block same, no strip after") {
|
||||
Chunk b {{0, 1, 3, 0}, {}};
|
||||
Chunk b {{}, {0, 1, 3, 0}, {}};
|
||||
|
||||
b.setBlock(1, 1);
|
||||
|
||||
|
@ -222,7 +222,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
|
||||
SECTION("Greater index, last block different, strip one after") {
|
||||
SECTION("Indexed block different") {
|
||||
Chunk b {{0, 1, 1, 0, 3, 5}, {}};
|
||||
Chunk b {{}, {0, 1, 1, 0, 3, 5}, {}};
|
||||
|
||||
b.setBlock(2, 2);
|
||||
|
||||
|
@ -238,7 +238,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
}
|
||||
|
||||
SECTION("Indexed block same") {
|
||||
Chunk b {{0, 1, 1, 0, 3, 5}, {}};
|
||||
Chunk b {{}, {0, 1, 1, 0, 3, 5}, {}};
|
||||
|
||||
b.setBlock(2, 5);
|
||||
|
||||
|
@ -253,7 +253,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
}
|
||||
|
||||
SECTION("Greater index, last block different, strip three after") {
|
||||
Chunk b {{0, 1, 2, 0, 6, 6}, {}};
|
||||
Chunk b {{}, {0, 1, 2, 0, 6, 6}, {}};
|
||||
|
||||
b.setBlock(3, 5);
|
||||
|
||||
|
@ -305,7 +305,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
}
|
||||
|
||||
SECTION("No index found in loop, last block different, not end of chunk") {
|
||||
Chunk b {{0, 1, 2, 0}, {}};
|
||||
Chunk b {{}, {0, 1, 2, 0}, {}};
|
||||
|
||||
b.setBlock(6, 6);
|
||||
|
||||
|
@ -321,7 +321,7 @@ TEST_CASE("Chunk", "[engine]") {
|
|||
}
|
||||
|
||||
SECTION("No index found in loop, last block different, end of chunk") {
|
||||
Chunk b {{0, 1, 2, 0}, {}};
|
||||
Chunk b {{}, {0, 1, 2, 0}, {}};
|
||||
|
||||
b.setBlock(4095, 6);
|
||||
|
||||
|
|
Loading…
Reference in New Issue