Add sunlight generation - wip implementation, does not pass MapBlocks.
* Added light_propagates block definition parameter. * Improved BlockLight propagation and rendering. * Change index order to improve caching.master
parent
b50732ec5e
commit
571453843e
|
@ -95,7 +95,7 @@ void main() {
|
|||
float sunlightIntensity = 1;
|
||||
// float sunlightIntensity = aLight.w * clamp(sin(time / 2.5) + 0.25, 0, 1) / MAX_SUNLIGHT;
|
||||
vec3 blockLightColor = (aLight.xyz / MAX_BLOCKLIGHT) * vec3(1 + sunlightIntensity / 4);
|
||||
vec3 sunlightColor = clamp(sunlightIntensity * 1.25 * vec3(1, 0.9, 0.75), 0, 1);
|
||||
vec3 sunlightColor = clamp(sunlightIntensity * 1.25 * vec3(1, 0.9, 0.75) * (aLight.w / 16.0), 0, 1);
|
||||
vec3 resultantLight = vec3(max(sunlightColor.x, blockLightColor.x), max(sunlightColor.y, blockLightColor.y), max(sunlightColor.z, blockLightColor.z));
|
||||
|
||||
vec4 worldPos = model * pos;
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
LocalDefinitionAtlas::LocalDefinitionAtlas(TextureAtlas& atlas) {
|
||||
//Invalid Node
|
||||
BlockModel invalidModel = BlockModel::createCube({atlas["_missing"]}, {}, {});
|
||||
BlockDef* invalid = new BlockDef("invalid", "Invalid (you broke the game!)", 64, invalidModel, invalidModel, true, {}, {{}}, {{}});
|
||||
BlockDef* invalid = new BlockDef("invalid", "Invalid (you broke the game!)", 64, invalidModel, invalidModel, true, {}, false, {{}}, {{}});
|
||||
defs.push_back(invalid);
|
||||
defTable.insert({"invalid", 0});
|
||||
|
||||
//Air Node
|
||||
BlockModel nullModel {};
|
||||
BlockDef* air = new BlockDef("air", "Air", 64, nullModel, nullModel, false, {}, {}, {}, 1);
|
||||
BlockDef* air = new BlockDef("air", "Air", 64, nullModel, nullModel, false, {}, true, {}, {}, 1);
|
||||
defs.push_back(air);
|
||||
defTable.insert({"air", 1});
|
||||
}
|
||||
|
|
|
@ -8,12 +8,12 @@ ServerDefinitionAtlas::ServerDefinitionAtlas() {
|
|||
|
||||
//Invalid Node
|
||||
BlockModel invalidModel = BlockModel::createCube({}, {}, {});
|
||||
BlockDef* invalid = new BlockDef("invalid", "Invalid (you broke the game!)", 1, invalidModel, invalidModel, true, {}, {{}}, {{}}, INVALID);
|
||||
BlockDef* invalid = new BlockDef("invalid", "Invalid (you broke the game!)", 1, invalidModel, invalidModel, true, {}, false, {{}}, {{}}, INVALID);
|
||||
registerDef(invalid);
|
||||
|
||||
//Air Node
|
||||
BlockModel nullModel {};
|
||||
BlockDef* air = new BlockDef("air", "Air (you broke the game!)", 1, nullModel, nullModel, false, {}, {}, {}, AIR);
|
||||
BlockDef* air = new BlockDef("air", "Air (you broke the game!)", 1, nullModel, nullModel, false, {}, true, {}, {}, AIR);
|
||||
registerDef(air);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
// Created by aurailus on 28/01/19.
|
||||
//
|
||||
|
||||
#include "MapGen.h"
|
||||
#include "NoiseSample.h"
|
||||
#include "../../game/scene/world/Schematic.h"
|
||||
#include <random>
|
||||
#include <cmath>
|
||||
|
||||
#include "MapGen.h"
|
||||
|
||||
#include "NoiseSample.h"
|
||||
|
||||
MapGen::MapGen(unsigned int seed, DefinitionAtlas& defs, BiomeAtlas& biomes, std::shared_ptr<MapGenProps> props) :
|
||||
seed(seed),
|
||||
defs(defs),
|
||||
|
@ -26,6 +27,8 @@ MapGen::chunk_partials_map MapGen::generateMapBlock(glm::ivec3 mbPos) {
|
|||
}
|
||||
}
|
||||
|
||||
generateSunlight(chunks, mbPos);
|
||||
|
||||
for (auto& chunk : chunks) {
|
||||
// Delete MapGenJobs
|
||||
delete chunk.second.first;
|
||||
|
@ -122,9 +125,8 @@ void MapGen::buildElevationMap(chunk_partials_map& chunks, chunk_partial& chunk)
|
|||
}
|
||||
|
||||
void MapGen::generateBlocks(chunk_partial& chunk) {
|
||||
glm::ivec3 lp {};
|
||||
|
||||
auto dupe = std::make_unique<BlockChunk>(*chunk.second);
|
||||
std::unique_ptr<BlockChunk> dupe = nullptr;
|
||||
if (chunk.second->partial) dupe = std::make_unique<BlockChunk>(*chunk.second);
|
||||
|
||||
chunk.second->blocks = {};
|
||||
chunk.second->biomes = {};
|
||||
|
@ -133,7 +135,7 @@ void MapGen::generateBlocks(chunk_partial& chunk) {
|
|||
for (unsigned short x = 0; x < 16; x++) {
|
||||
biomeArray[x] = {};
|
||||
for (unsigned short z = 0; z < 16; z++) {
|
||||
lp = {x, 0, z};
|
||||
glm::ivec3 lp = {x, 0, z};
|
||||
biomeArray[x][z] = biomes.getBiomeAt(
|
||||
chunk.first->temperature.get(lp),
|
||||
chunk.first->humidity.get(lp),
|
||||
|
@ -142,7 +144,7 @@ void MapGen::generateBlocks(chunk_partial& chunk) {
|
|||
}
|
||||
|
||||
for (unsigned short m = 0; m < 4096; m++) {
|
||||
Vec::indAssignVec(m, lp);
|
||||
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]);
|
||||
|
@ -166,7 +168,7 @@ void MapGen::generateBlocks(chunk_partial& chunk) {
|
|||
}
|
||||
}
|
||||
|
||||
if (dupe->partial) for (unsigned short i = 0; i < 4096; i++) {
|
||||
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);
|
||||
}
|
||||
|
@ -176,17 +178,6 @@ 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);
|
||||
|
||||
// unsigned int cWood = defs.blockFromStr("zeus:default:wood").index;
|
||||
// unsigned int cLeaves = defs.blockFromStr("zeus:default:leaves").index;
|
||||
// unsigned int cAir = DefinitionAtlas::INVALID;
|
||||
|
||||
// Schematic c {};
|
||||
// c.dimensions = {3, 3, 3};
|
||||
// c.origin = {1, 0, 1};
|
||||
// c.blocks = { cAir, cAir, cAir, cAir, cLeaves, cAir, cAir, cAir, cAir,
|
||||
// cAir, cWood, cAir, cLeaves, cWood, cLeaves, cAir, cLeaves, cAir,
|
||||
// cAir, cAir, cAir, cAir, cLeaves, cAir, cAir, cAir, cAir };
|
||||
|
||||
glm::ivec3 wp = chunk.second->pos;
|
||||
glm::ivec3 lp;
|
||||
|
||||
|
@ -220,6 +211,89 @@ void MapGen::generateStructures(chunk_partials_map& chunks, chunk_partial& chunk
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
BlockChunk* 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->setSunlight(ind, 15);
|
||||
|
||||
// const static std::array<glm::ivec3, 4> checks {
|
||||
// glm::ivec3 {-1, 0, 0}, glm::ivec3 {1, 0, 0}, glm::ivec3 {0, 0, -1}, glm::ivec3 {0, 0, 1}};
|
||||
|
||||
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;
|
||||
if (c.y == 3) break;
|
||||
chunk = chunks[mbPos * 4 + c].second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
propogateSunlightNodes(chunks, sunlightQueue);
|
||||
}
|
||||
|
||||
bool MapGen::containsWorldPos(BlockChunk *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->getSunlight(node.index);
|
||||
glm::ivec3 worldPos = node.chunk->pos * 16 + Space::Block::fromIndex(node.index);
|
||||
|
||||
const static std::array<glm::ivec3, 6> checks = { glm::ivec3 {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1} };
|
||||
for (const auto& i : checks) {
|
||||
glm::ivec3 check = worldPos + i;
|
||||
|
||||
BlockChunk* 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->getSunlight(ind) + 2 <= lightLevel) {
|
||||
int subtract = 1;
|
||||
if (lightLevel == 15 && i == checks[2]) subtract = 0;
|
||||
chunk->setSunlight(ind, lightLevel - subtract);
|
||||
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;
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "MapGenJob.h"
|
||||
#include "MapGenProps.h"
|
||||
#include "../../util/Vec.h"
|
||||
|
@ -21,6 +23,12 @@ public:
|
|||
// If both are partials `b` takes preference, if one is a fully generated chunk the partial takes preference.
|
||||
static std::shared_ptr<BlockChunk> combinePartials(std::shared_ptr<BlockChunk> a, std::shared_ptr<BlockChunk> b);
|
||||
private:
|
||||
struct SunlightNode {
|
||||
SunlightNode(unsigned short index, BlockChunk* chunk) : index(index), chunk(chunk) {};
|
||||
unsigned short index;
|
||||
BlockChunk* chunk;
|
||||
};
|
||||
|
||||
// Generate a chunk at `worldPos`, and place it and any partials in `chunks`.
|
||||
void generateChunk(chunk_partials_map& chunks, glm::ivec3 worldPos);
|
||||
|
||||
|
@ -34,6 +42,11 @@ private:
|
|||
void generateBlocks(chunk_partial& chunk);
|
||||
void generateStructures(chunk_partials_map& chunks, chunk_partial& chunk);
|
||||
|
||||
// Generate sunlight on the mapgen threads to speed up perf
|
||||
void generateSunlight(chunk_partials_map& chunks, glm::ivec3 mbPos);
|
||||
bool containsWorldPos(BlockChunk *chunk, glm::ivec3 pos);
|
||||
void propogateSunlightNodes(chunk_partials_map& 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, chunk_partials_map& chunks);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ BlockDef::BlockDef(
|
|||
const BlockModel& farModel,
|
||||
bool solid,
|
||||
glm::ivec3 lightSource,
|
||||
bool lightPropagates,
|
||||
const std::vector<SelectionBox>& sBoxes,
|
||||
const std::vector<SelectionBox>& cBoxes,
|
||||
unsigned int index) :
|
||||
|
@ -23,6 +24,7 @@ BlockDef::BlockDef(
|
|||
culls(model.culls),
|
||||
solid(solid),
|
||||
lightSource(lightSource),
|
||||
lightPropagates(lightPropagates),
|
||||
sBoxes(sBoxes),
|
||||
cBoxes(cBoxes) {}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ public:
|
|||
const BlockModel& farModel,
|
||||
bool solid,
|
||||
glm::ivec3 lightSource,
|
||||
bool lightPropagates,
|
||||
const std::vector<SelectionBox>& sBoxes,
|
||||
const std::vector<SelectionBox>& cBoxes,
|
||||
unsigned int index = 0
|
||||
|
@ -35,6 +36,7 @@ public:
|
|||
|
||||
bool culls = false;
|
||||
bool solid = false;
|
||||
bool lightPropagates = false;
|
||||
|
||||
glm::ivec3 lightSource;
|
||||
|
||||
|
|
|
@ -99,16 +99,16 @@ BlockDef& ChunkMeshGenerator::getBlockAt(const glm::ivec3& pos) {
|
|||
}
|
||||
|
||||
glm::vec4 ChunkMeshGenerator::getLightAt(const glm::ivec3& pos) {
|
||||
if (pos.x == 16) return adjacent[0]->getLightVec(Space::Block::index(pos - glm::ivec3 {16, 0, 0}));
|
||||
if (pos.x == -1) return adjacent[1]->getLightVec(Space::Block::index(pos + glm::ivec3 {16, 0, 0}));
|
||||
if (pos.x == 16) return adjacent[0]->getLight(Space::Block::index(pos - glm::ivec3 {16, 0, 0}));
|
||||
if (pos.x == -1) return adjacent[1]->getLight(Space::Block::index(pos + glm::ivec3 {16, 0, 0}));
|
||||
|
||||
if (pos.y == 16) return adjacent[2]->getLightVec(Space::Block::index(pos - glm::ivec3 {0, 16, 0}));
|
||||
if (pos.y == -1) return adjacent[3]->getLightVec(Space::Block::index(pos + glm::ivec3 {0, 16, 0}));
|
||||
if (pos.y == 16) return adjacent[2]->getLight(Space::Block::index(pos - glm::ivec3 {0, 16, 0}));
|
||||
if (pos.y == -1) return adjacent[3]->getLight(Space::Block::index(pos + glm::ivec3 {0, 16, 0}));
|
||||
|
||||
if (pos.z == 16) return adjacent[4]->getLightVec(Space::Block::index(pos - glm::ivec3 {0, 0, 16}));
|
||||
if (pos.z == -1) return adjacent[5]->getLightVec(Space::Block::index(pos + glm::ivec3 {0, 0, 16}));
|
||||
if (pos.z == 16) return adjacent[4]->getLight(Space::Block::index(pos - glm::ivec3 {0, 0, 16}));
|
||||
if (pos.z == -1) return adjacent[5]->getLight(Space::Block::index(pos + glm::ivec3 {0, 0, 16}));
|
||||
|
||||
return chunk->getLightVec(Space::Block::index(pos));
|
||||
return chunk->getLight(Space::Block::index(pos));
|
||||
}
|
||||
|
||||
void ChunkMeshGenerator::addFaces(const glm::vec3 &offset, const std::vector<MeshPart> &meshParts, const glm::vec3& tint, glm::vec4 light) {
|
||||
|
@ -134,7 +134,7 @@ void ChunkMeshGenerator::addFaces(const glm::vec3 &offset, const std::vector<Mes
|
|||
mp.blendInd ? tint : glm::vec3 {1, 1, 1},
|
||||
mp.blendInd ? vertex.blendMask : glm::vec2 {-1, -1},
|
||||
Util::packFloat(vertex.nml),
|
||||
light,
|
||||
glm::vec4(light),
|
||||
static_cast<float>(mp.shaderMod),
|
||||
modData
|
||||
});
|
||||
|
|
|
@ -263,6 +263,7 @@ namespace RegisterBlocks {
|
|||
if (!nameOpt) throw identifier + " is missing name property!";
|
||||
|
||||
bool solid = blockTable.get_or("solid", true);
|
||||
bool lightPropagates = blockTable.get_or("light_propagates", false);
|
||||
auto maxStack = blockTable.get_or("stack", 64);
|
||||
|
||||
glm::vec3 lightSource {};
|
||||
|
@ -299,6 +300,7 @@ namespace RegisterBlocks {
|
|||
models.first, models.second,
|
||||
solid,
|
||||
lightSource,
|
||||
lightPropagates,
|
||||
std::move(selectionBoxes),
|
||||
std::move(collisionBoxes),
|
||||
defs.size() // Index
|
||||
|
|
|
@ -23,16 +23,16 @@ bool ServerGenStream::queue(glm::vec3 pos) {
|
|||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<std::shared_ptr<BlockChunk>>> ServerGenStream::update() {
|
||||
auto finishedChunks = std::make_unique<std::vector<std::shared_ptr<BlockChunk>>>();
|
||||
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;
|
||||
|
||||
if (!u.chunks.empty()) {
|
||||
for (auto chunk : u.chunks)
|
||||
finishedChunks->push_back(std::shared_ptr<BlockChunk>(chunk.second.second));
|
||||
finishedChunks->push_back({u.pos, {}});
|
||||
for (auto chunk : u.chunks) finishedChunks->back().chunks.push_back(std::shared_ptr<BlockChunk>(chunk.second.second));
|
||||
u.chunks.clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,11 @@ public:
|
|||
static const int THREADS = 4;
|
||||
static const int THREAD_QUEUE_SIZE = 6;
|
||||
|
||||
struct FinishedBlockJob {
|
||||
glm::ivec3 pos;
|
||||
std::vector<std::shared_ptr<BlockChunk>> chunks;
|
||||
};
|
||||
|
||||
explicit ServerGenStream(unsigned int seed, ServerGame& game);
|
||||
~ServerGenStream();
|
||||
|
||||
|
@ -25,8 +30,7 @@ public:
|
|||
bool queue(glm::vec3 pos);
|
||||
// Returns a vector of BlockChunks that have finished generating,
|
||||
// and gives the threads new data to work with.
|
||||
std::unique_ptr<std::vector<std::shared_ptr<BlockChunk>>> update();
|
||||
|
||||
std::unique_ptr<std::vector<FinishedBlockJob>> update();
|
||||
private:
|
||||
struct Job {
|
||||
bool locked = false;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "../conn/ClientList.h"
|
||||
#include "../conn/ServerClient.h"
|
||||
#include "../../util/Timer.h"
|
||||
|
||||
ServerWorld::ServerWorld(unsigned int seed, ServerGame& game, ClientList& clients) :
|
||||
clientList(clients),
|
||||
|
@ -58,13 +59,19 @@ void ServerWorld::update(double delta) {
|
|||
auto finished = genStream->update();
|
||||
generatedChunks = static_cast<int>(finished->size());
|
||||
|
||||
for (const auto& chunk : *finished) {
|
||||
dimension.setChunk(chunk);
|
||||
for (auto& mb : *finished) {
|
||||
Timer t("finishing mapblock");
|
||||
|
||||
glm::ivec3 mapBlockPos = Space::MapBlock::world::fromChunk(chunk->pos);
|
||||
if (chunk->generated) dimension.getMapBlock(mapBlockPos)->generated = true;
|
||||
unsigned long long mapBlockIntegrity = dimension.getMapBlockIntegrity(mapBlockPos);
|
||||
for (const auto& chunk : mb.chunks) {
|
||||
dimension.setChunk(chunk);
|
||||
// dimension.createSunlight(chunk->pos);
|
||||
}
|
||||
|
||||
// dimension.propogateLight();
|
||||
dimension.getMapBlock(mb.pos)->generated = true;
|
||||
t.printElapsedMs();
|
||||
|
||||
unsigned long long mapBlockIntegrity = dimension.getMapBlockIntegrity(mb.pos);
|
||||
for (auto& client : clientList.clients) {
|
||||
if (client->hasPlayer) {
|
||||
auto playerMapBlock = Space::MapBlock::world::fromBlock(client->getPos());
|
||||
|
@ -73,14 +80,19 @@ void ServerWorld::update(double delta) {
|
|||
{playerMapBlock.x - MB_GEN_H, playerMapBlock.y - MB_GEN_V, playerMapBlock.z - MB_GEN_H},
|
||||
{playerMapBlock.x + MB_GEN_H, playerMapBlock.y + MB_GEN_V, playerMapBlock.z + MB_GEN_H}};
|
||||
|
||||
if (isInBounds(mapBlockPos, bounds) && client->getMapBlockIntegrity(mapBlockPos) < mapBlockIntegrity) {
|
||||
client->setMapBlockIntegrity(mapBlockPos, mapBlockIntegrity);
|
||||
sendChunk(chunk->pos, *client);
|
||||
if (isInBounds(mb.pos, bounds) && client->getMapBlockIntegrity(mb.pos) < mapBlockIntegrity) {
|
||||
client->setMapBlockIntegrity(mb.pos, mapBlockIntegrity);
|
||||
|
||||
//TODO: Replace with sendMapBlock
|
||||
for (int i = 0; i < 64; i++) {
|
||||
sendChunk(dimension.getMapBlock(mb.pos)->operator[](i)->pos, *client);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Send the # of generated chunks to the client (debug),
|
||||
// and trigger new chunks to be generated if a player has changed MapBlocks.
|
||||
Packet r(PacketType::SERVER_INFO);
|
||||
|
|
|
@ -111,6 +111,18 @@ namespace Space {
|
|||
glm::ivec3 local = Chunk::relative::toMapBlock(vec);
|
||||
return static_cast<unsigned int>(local.x + MAPBLOCK_SIZE * (local.y + MAPBLOCK_SIZE * local.z));
|
||||
}
|
||||
|
||||
// Return a local vector of an chunk within its mapblock.
|
||||
static inline glm::ivec3 fromIndex(unsigned int ind) {
|
||||
glm::ivec3 vec {};
|
||||
|
||||
vec.y = ind / (MAPBLOCK_SIZE * MAPBLOCK_SIZE);
|
||||
ind -= (static_cast<int>(vec.y) * MAPBLOCK_SIZE * MAPBLOCK_SIZE);
|
||||
vec.z = ind / MAPBLOCK_SIZE;
|
||||
vec.x = ind % MAPBLOCK_SIZE;
|
||||
|
||||
return vec;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Block {
|
||||
|
@ -134,16 +146,16 @@ namespace Space {
|
|||
// Get the index of a Block within its Chunk from its local or world position.
|
||||
static inline unsigned int index(const glm::ivec3& vec) {
|
||||
glm::ivec3 local = Block::relative::toChunk(vec);
|
||||
return static_cast<unsigned int>(local.x + CHUNK_SIZE * (local.y + CHUNK_SIZE * local.z));
|
||||
return static_cast<unsigned int>(local.x + CHUNK_SIZE * (local.z + CHUNK_SIZE * local.y));
|
||||
}
|
||||
|
||||
// Return a local vector of an index within it's chunk.
|
||||
// Return a local vector of an block within its chunk.
|
||||
static inline glm::ivec3 fromIndex(unsigned int ind) {
|
||||
glm::ivec3 vec {};
|
||||
|
||||
vec.z = ind / (CHUNK_SIZE * CHUNK_SIZE);
|
||||
ind -= (static_cast<int>(vec.z) * CHUNK_SIZE * CHUNK_SIZE);
|
||||
vec.y = ind / CHUNK_SIZE;
|
||||
vec.y = ind / (CHUNK_SIZE * CHUNK_SIZE);
|
||||
ind -= (static_cast<int>(vec.y) * CHUNK_SIZE * CHUNK_SIZE);
|
||||
vec.z = ind / CHUNK_SIZE;
|
||||
vec.x = ind % CHUNK_SIZE;
|
||||
|
||||
return vec;
|
||||
|
|
|
@ -30,9 +30,9 @@ namespace Vec {
|
|||
};
|
||||
|
||||
static inline void indAssignVec(int ind, glm::ivec3& vec, unsigned int wid = 16) {
|
||||
vec.z = ind / (wid * wid);
|
||||
ind -= ((int)vec.z * wid * wid);
|
||||
vec.y = ind / wid;
|
||||
vec.y = ind / (wid * wid);
|
||||
ind -= ((int)vec.y * wid * wid);
|
||||
vec.z = ind / wid;
|
||||
vec.x = ind % wid;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -60,9 +60,9 @@ bool Dimension::setBlock(glm::ivec3 pos, unsigned int block) {
|
|||
|
||||
chunk->setBlock(Space::Block::relative::toChunk(pos), block);
|
||||
|
||||
glm::ivec3 oldLight = chunk->getBlockLight(Space::Block::index(pos));
|
||||
glm::ivec4 oldLight = chunk->getLight(Space::Block::index(pos));
|
||||
glm::ivec3 newLight = defs.blockFromId(block).lightSource;
|
||||
if (oldLight != newLight) {
|
||||
if (oldLight.x != newLight.x || oldLight.y != newLight.y || oldLight.z != newLight.z) {
|
||||
if (abs(oldLight.x) + abs(oldLight.y) + abs(oldLight.z) != 0) removeLight(pos);
|
||||
if (abs(newLight.x) + abs(newLight.y) + abs(newLight.z) != 0) addLight(pos, newLight);
|
||||
}
|
||||
|
@ -84,6 +84,42 @@ std::shared_ptr<MapBlock> Dimension::getOrCreateMapBlock(glm::ivec3 mapBlockPosi
|
|||
return (*region)[index];
|
||||
}
|
||||
|
||||
//
|
||||
// Light related functions.
|
||||
//
|
||||
|
||||
void Dimension::createSunlight(glm::ivec3 pos) {
|
||||
// auto chunk = getChunk(pos);
|
||||
// auto top = getChunk(pos + glm::ivec3 {0, 1, 0});
|
||||
// if (top) {
|
||||
// for (unsigned int i = 0; i < 256; i++) {
|
||||
// unsigned int ind = Space::Block::index(glm::ivec3 {i / 16, 0, i % 16});
|
||||
// auto light = top->getSunlight(ind);
|
||||
// if (light != 0) {
|
||||
// lightAddQueue[SUNLIGHT_CHANNEL].emplace(ind, top.get());
|
||||
// if (light == 15) for (int j = 15; j >= 0; j--) {
|
||||
// unsigned int ind = Space::Block::index({i / 16, j, i % 16});
|
||||
// if (!defs.blockFromId(chunk->getBlock(ind)).solid) {
|
||||
// chunk->setSunlight(ind, 15);
|
||||
// lightAddQueue[SUNLIGHT_CHANNEL].emplace(ind, chunk.get());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// for (unsigned int i = 0; i < 256; i++) {
|
||||
// for (unsigned int j = 15; j >= 0; j--) {
|
||||
// auto index = Space::Block::index(glm::ivec3{i / 16, j, i % 16});
|
||||
// if (defs.blockFromId(chunk->getBlock(index)).solid) continue;
|
||||
// chunk->setSunlight(index, 15);
|
||||
// lightAddQueue[SUNLIGHT_CHANNEL].emplace(index, chunk.get());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
// Returns true if the provided pos references a block within chunk, otherwise returns false.
|
||||
bool Dimension::containsWorldPos(BlockChunk *chunk, glm::ivec3 pos) {
|
||||
return chunk && Space::Chunk::world::fromBlock(pos) == chunk->pos;
|
||||
|
@ -91,10 +127,10 @@ bool Dimension::containsWorldPos(BlockChunk *chunk, glm::ivec3 pos) {
|
|||
|
||||
// Get the BlockLight of a block. This function can be accelerated
|
||||
// by providing a chunk that might contain the world position.
|
||||
glm::ivec3 Dimension::getBlockLight(glm::ivec3 worldPos, BlockChunk *chunk) {
|
||||
if (containsWorldPos(chunk, worldPos)) return chunk->getBlockLight(Space::Block::index(worldPos));
|
||||
glm::ivec4 Dimension::getLight(glm::ivec3 worldPos, BlockChunk *chunk) {
|
||||
if (containsWorldPos(chunk, worldPos)) return chunk->getLight(Space::Block::index(worldPos));
|
||||
auto oChunk = getChunk(Space::Chunk::world::fromBlock(worldPos)).get();
|
||||
return (oChunk ? oChunk->getBlockLight(Space::Block::index(worldPos)) : glm::ivec3 {});
|
||||
return (oChunk ? oChunk->getLight(Space::Block::index(worldPos)) : glm::ivec4 {});
|
||||
}
|
||||
|
||||
void Dimension::addLight(glm::ivec3 pos, glm::ivec3 light) {
|
||||
|
@ -110,7 +146,7 @@ void Dimension::addLight(glm::ivec3 pos, glm::ivec3 light) {
|
|||
|
||||
void Dimension::removeLight(glm::ivec3 pos) {
|
||||
auto startChunk = getChunk(Space::Chunk::world::fromBlock(pos));
|
||||
glm::ivec3 val = startChunk->getBlockLight(Space::Block::index(pos));
|
||||
glm::ivec4 val = startChunk->getLight(Space::Block::index(pos));
|
||||
|
||||
startChunk->setBlockLight(Space::Block::index(pos), {});
|
||||
lightRemoveQueue[0].emplace(Space::Block::index(pos), val.x, startChunk.get());
|
||||
|
@ -122,17 +158,17 @@ void Dimension::removeLight(glm::ivec3 pos) {
|
|||
std::unordered_set<glm::ivec3, Vec::ivec3> Dimension::propogateAddNodes() {
|
||||
std::unordered_set<glm::ivec3, Vec::ivec3> chunksUpdated {};
|
||||
|
||||
for (unsigned int channel = 0; channel < 3; channel++) {
|
||||
for (unsigned int channel = 0; channel < SUNLIGHT_CHANNEL; channel++) {
|
||||
while (!lightAddQueue[channel].empty()) {
|
||||
LightAddNode& node = lightAddQueue[channel].front();
|
||||
|
||||
unsigned char lightLevel = node.chunk->getBlockLight(node.index, channel);
|
||||
unsigned char lightLevel = node.chunk->getLight(node.index, channel);
|
||||
glm::ivec3 worldPos = node.chunk->pos * 16 + Space::Block::fromIndex(node.index);
|
||||
|
||||
const static std::array<glm::ivec3, 6> checks = { glm::ivec3 {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1} };
|
||||
for (const auto& i : checks) {
|
||||
glm::ivec3 check = worldPos + i;
|
||||
if (!defs.blockFromId(getBlock(check)).solid && getBlockLight(check, node.chunk)[channel] + 2 <= lightLevel) {
|
||||
if (defs.blockFromId(getBlock(check)).lightPropagates && getLight(check, node.chunk)[channel] + 2 <= lightLevel) {
|
||||
BlockChunk* chunk;
|
||||
if (containsWorldPos(node.chunk, check)) chunk = node.chunk;
|
||||
else {
|
||||
|
@ -141,7 +177,8 @@ std::unordered_set<glm::ivec3, Vec::ivec3> Dimension::propogateAddNodes() {
|
|||
chunksUpdated.insert(chunk->pos);
|
||||
chunk->dirty = true;
|
||||
}
|
||||
chunk->setBlockLight(Space::Block::index(check), channel, lightLevel - 1);
|
||||
|
||||
chunk->setLight(Space::Block::index(check), channel, lightLevel - 1);
|
||||
lightAddQueue[channel].emplace(Space::Block::index(check), chunk);
|
||||
}
|
||||
}
|
||||
|
@ -149,13 +186,41 @@ std::unordered_set<glm::ivec3, Vec::ivec3> Dimension::propogateAddNodes() {
|
|||
}
|
||||
}
|
||||
|
||||
while (!lightAddQueue[SUNLIGHT_CHANNEL].empty()) {
|
||||
LightAddNode& node = lightAddQueue[SUNLIGHT_CHANNEL].front();
|
||||
|
||||
unsigned char lightLevel = node.chunk->getSunlight(node.index);
|
||||
glm::ivec3 worldPos = node.chunk->pos * 16 + Space::Block::fromIndex(node.index);
|
||||
|
||||
const static std::array<glm::ivec3, 6> checks = { glm::ivec3 {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1} };
|
||||
for (const auto& i : checks) {
|
||||
glm::ivec3 check = worldPos + i;
|
||||
if (defs.blockFromId(getBlock(check)).lightPropagates && getLight(check, node.chunk)[SUNLIGHT_CHANNEL] + 2 <= lightLevel) {
|
||||
BlockChunk* chunk;
|
||||
if (containsWorldPos(node.chunk, check)) chunk = node.chunk;
|
||||
else {
|
||||
chunk = getChunk(Space::Chunk::world::fromBlock(check)).get();
|
||||
if (!chunk) continue;
|
||||
chunksUpdated.insert(chunk->pos);
|
||||
chunk->dirty = true;
|
||||
}
|
||||
|
||||
int subtract = 1;
|
||||
if (lightLevel == 15 && i == checks[2]) subtract = 0;
|
||||
chunk->setLight(Space::Block::index(check), SUNLIGHT_CHANNEL, lightLevel - subtract);
|
||||
lightAddQueue[SUNLIGHT_CHANNEL].emplace(Space::Block::index(check), chunk);
|
||||
}
|
||||
}
|
||||
lightAddQueue[SUNLIGHT_CHANNEL].pop();
|
||||
}
|
||||
|
||||
return chunksUpdated;
|
||||
}
|
||||
|
||||
std::unordered_set<glm::ivec3, Vec::ivec3> Dimension::propogateRemoveNodes() {
|
||||
std::unordered_set<glm::ivec3, Vec::ivec3> chunksUpdated {};
|
||||
|
||||
for (unsigned int channel = 0; channel < 3; channel++) {
|
||||
for (unsigned int channel = 0; channel < SUNLIGHT_CHANNEL; channel++) {
|
||||
while (!lightRemoveQueue[channel].empty()) {
|
||||
LightRemoveNode& node = lightRemoveQueue[channel].front();
|
||||
|
||||
|
@ -164,7 +229,7 @@ std::unordered_set<glm::ivec3, Vec::ivec3> Dimension::propogateRemoveNodes() {
|
|||
const static std::array<glm::ivec3, 6> checks = { glm::ivec3 {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1} };
|
||||
for (const auto& i : checks) {
|
||||
glm::ivec3 check = worldPos + i;
|
||||
unsigned char checkLight = getBlockLight(check, node.chunk)[channel];
|
||||
unsigned char checkLight = getLight(check, node.chunk)[channel];
|
||||
|
||||
if (checkLight != 0 && checkLight < node.value) {
|
||||
BlockChunk* chunk;
|
||||
|
@ -177,7 +242,7 @@ std::unordered_set<glm::ivec3, Vec::ivec3> Dimension::propogateRemoveNodes() {
|
|||
}
|
||||
|
||||
auto blockLight = defs.blockFromId(chunk->getBlock(Space::Block::index(check))).lightSource[channel];
|
||||
chunk->setBlockLight(Space::Block::index(check), channel, blockLight);
|
||||
chunk->setLight(Space::Block::index(check), channel, blockLight);
|
||||
if (blockLight) lightAddQueue[channel].emplace(Space::Block::index(check), chunk);
|
||||
lightRemoveQueue[channel].emplace(Space::Block::index(check), checkLight, chunk);
|
||||
}
|
||||
|
@ -194,3 +259,8 @@ std::unordered_set<glm::ivec3, Vec::ivec3> Dimension::propogateRemoveNodes() {
|
|||
propogateAddNodes();
|
||||
return chunksUpdated;
|
||||
}
|
||||
|
||||
void Dimension::propogateLight() {
|
||||
propogateRemoveNodes();
|
||||
propogateAddNodes();
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@ public:
|
|||
unsigned int getBlock(glm::ivec3 pos);
|
||||
virtual bool setBlock(glm::ivec3 pos, unsigned int block);
|
||||
|
||||
void createSunlight(glm::ivec3 pos);
|
||||
void propogateLight();
|
||||
protected:
|
||||
typedef std::unordered_map<glm::ivec3, std::shared_ptr<Region>, Vec::ivec3> block_region_map;
|
||||
block_region_map regions;
|
||||
|
@ -41,8 +43,8 @@ private:
|
|||
inline std::shared_ptr<MapBlock> getOrCreateMapBlock(glm::ivec3 mapBlockPosition);
|
||||
|
||||
static inline bool containsWorldPos(BlockChunk* chunk, glm::ivec3 pos);
|
||||
inline glm::ivec4 getLight(glm::ivec3 worldPos, BlockChunk* chunk = nullptr);
|
||||
|
||||
inline glm::ivec3 getBlockLight(glm::ivec3 worldPos, BlockChunk* chunk = nullptr);
|
||||
inline void addLight(glm::ivec3 pos, glm::ivec3 light);
|
||||
inline void removeLight(glm::ivec3 pos);
|
||||
|
||||
|
@ -59,6 +61,7 @@ private:
|
|||
BlockChunk* chunk;
|
||||
};
|
||||
|
||||
std::array<std::queue<LightAddNode>, 3> lightAddQueue;
|
||||
std::array<std::queue<LightRemoveNode>, 3> lightRemoveQueue;
|
||||
static constexpr unsigned char SUNLIGHT_CHANNEL = 3;
|
||||
std::array<std::queue<LightAddNode>, 4> lightAddQueue;
|
||||
std::array<std::queue<LightRemoveNode>, 4> lightRemoveQueue;
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@ BlockChunk::BlockChunk(const std::vector<unsigned int>& blocks, const std::vecto
|
|||
biomes(std::move(biomes)),
|
||||
pos(pos),
|
||||
generated(true) {
|
||||
memset(light.data(), 0, sizeof(light));
|
||||
memset(blocklight.data(), 0, sizeof(blocklight));
|
||||
calcNonAirBlocks();
|
||||
}
|
||||
|
||||
|
@ -61,11 +61,12 @@ Packet BlockChunk::serialize() {
|
|||
s.append<std::string>(gzip::compress(temp.data(), temp.size()));
|
||||
|
||||
std::vector<unsigned char> lights {};
|
||||
lights.resize(4096 * 3);
|
||||
lights.resize(4096 * 4);
|
||||
for (unsigned short i = 0; i < 4096; i++) {
|
||||
lights[i * 3] = this->light[i].r;
|
||||
lights[i * 3 + 1] = this->light[i].g;
|
||||
lights[i * 3 + 2] = this->light[i].b;
|
||||
lights[i * 4] = blocklight[i].r;
|
||||
lights[i * 4 + 1] = blocklight[i].g;
|
||||
lights[i * 4 + 2] = blocklight[i].b;
|
||||
lights[i * 4 + 3] = getSunlight(i);
|
||||
}
|
||||
temp = Serializer().append(lights).data;
|
||||
s.append<std::string>(gzip::compress(temp.data(), temp.size()));
|
||||
|
@ -96,9 +97,10 @@ void BlockChunk::deserialize(PacketView& packet) {
|
|||
|
||||
auto lightsVec = Deserializer(gzip).read<std::vector<unsigned char>>();
|
||||
for (unsigned int i = 0; i < 4096; i++) {
|
||||
light[i].r = lightsVec[i * 3];
|
||||
light[i].g = lightsVec[i * 3 + 1];
|
||||
light[i].b = lightsVec[i * 3 + 2];
|
||||
blocklight[i].r = lightsVec[i * 4];
|
||||
blocklight[i].g = lightsVec[i * 4 + 1];
|
||||
blocklight[i].b = lightsVec[i * 4 + 2];
|
||||
setSunlight(i, lightsVec[i * 4 + 3]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,51 +22,62 @@ public:
|
|||
|
||||
void initializeEmpty();
|
||||
|
||||
bool setBlock(unsigned int ind, unsigned int blk);
|
||||
inline bool setBlock(const glm::ivec3& pos, unsigned int blk);
|
||||
// Blocks
|
||||
|
||||
inline unsigned int getBlock(unsigned int ind) const;
|
||||
inline unsigned int getBlock(const glm::ivec3& pos) const;
|
||||
|
||||
inline bool setBiome(unsigned int ind, unsigned short bio);
|
||||
inline bool setBiome(const glm::ivec3& pos, unsigned short bio);
|
||||
bool setBlock(unsigned int ind, unsigned int blk);
|
||||
inline bool setBlock(const glm::ivec3& pos, unsigned int blk);
|
||||
|
||||
const std::vector<unsigned int>& cGetBlocks() const;
|
||||
|
||||
// Biomes
|
||||
|
||||
inline unsigned short getBiome(unsigned int ind) const;
|
||||
inline unsigned short getBiome(const glm::ivec3& pos) const;
|
||||
|
||||
inline void setSunlight(unsigned int ind, unsigned char val);
|
||||
inline bool setBiome(unsigned int ind, unsigned short bio);
|
||||
inline bool setBiome(const glm::ivec3& pos, unsigned short bio);
|
||||
const std::vector<unsigned short>& cGetBiomes() const;
|
||||
|
||||
// Light
|
||||
|
||||
inline glm::ivec4 getLight(unsigned int ind);
|
||||
inline unsigned char getLight(unsigned int ind, unsigned char channel);
|
||||
inline void setLight(unsigned int ind, unsigned char channel, unsigned char light);
|
||||
inline void setBlockLight(unsigned int ind, glm::ivec3 light);
|
||||
inline void setBlockLight(unsigned int ind, unsigned char channel, unsigned char light);
|
||||
|
||||
inline unsigned char getSunlight(unsigned int ind);
|
||||
inline glm::ivec3 getBlockLight(unsigned int ind);
|
||||
inline unsigned char getBlockLight(unsigned int ind, unsigned char channel);
|
||||
inline void setSunlight(unsigned int ind, unsigned char val);
|
||||
|
||||
inline glm::vec4 getLightVec(unsigned int ind);
|
||||
|
||||
const std::vector<unsigned int>& cGetBlocks() const;
|
||||
const std::vector<unsigned short>& cGetBiomes() const;
|
||||
// Serialization
|
||||
|
||||
Packet serialize();
|
||||
void deserialize(PacketView& packet);
|
||||
|
||||
bool generated = false;
|
||||
bool shouldHaveMesh = true;
|
||||
bool dirty = true;
|
||||
|
||||
bool generated = false;
|
||||
|
||||
glm::ivec3 pos;
|
||||
private:
|
||||
struct light_bits {
|
||||
struct blocklight_bits {
|
||||
// 16 bits - 1 short
|
||||
unsigned char r: 5;
|
||||
unsigned char g: 5;
|
||||
unsigned char b: 5, :1;
|
||||
};
|
||||
struct sunlight_bits {
|
||||
// 8 bits for two values - 1 char
|
||||
unsigned char a: 4;
|
||||
unsigned char b: 4;
|
||||
};
|
||||
|
||||
std::vector<unsigned int> blocks {};
|
||||
std::vector<unsigned short> biomes {};
|
||||
std::array <light_bits, 4096> light {};
|
||||
std::array <blocklight_bits, 4096> blocklight {};
|
||||
std::array <sunlight_bits, 2048> sunlight {};
|
||||
|
||||
bool empty = true;
|
||||
bool partial = false;
|
||||
|
@ -110,35 +121,36 @@ inline unsigned short BlockChunk::getBiome(const glm::ivec3& pos) const {
|
|||
return getBiome(Space::Block::index(pos));
|
||||
}
|
||||
|
||||
inline void BlockChunk::setSunlight(unsigned int ind, unsigned char val) {
|
||||
inline glm::ivec4 BlockChunk::getLight(unsigned int ind) {
|
||||
return { blocklight[ind].r, blocklight[ind].g, blocklight[ind].b, getSunlight(ind) };
|
||||
}
|
||||
|
||||
inline unsigned char BlockChunk::getLight(unsigned int ind, unsigned char channel) {
|
||||
return channel == 0 ? blocklight[ind].r :
|
||||
channel == 1 ? blocklight[ind].g :
|
||||
channel == 2 ? blocklight[ind].b :
|
||||
getSunlight(ind);
|
||||
}
|
||||
|
||||
inline void BlockChunk::setLight(unsigned int ind, unsigned char channel, unsigned char l) {
|
||||
channel == 0 ? blocklight[ind].r = l:
|
||||
channel == 1 ? blocklight[ind].g = l:
|
||||
channel == 2 ? blocklight[ind].b = l:
|
||||
(setSunlight(ind, l), 0);
|
||||
}
|
||||
|
||||
inline void BlockChunk::setBlockLight(unsigned int ind, glm::ivec3 l) {
|
||||
light[ind].r = l.x;
|
||||
light[ind].g = l.y;
|
||||
light[ind].b = l.z;
|
||||
}
|
||||
|
||||
inline void BlockChunk::setBlockLight(unsigned int ind, unsigned char channel, unsigned char l){
|
||||
channel == 0 ? light[ind].r = l:
|
||||
channel == 1 ? light[ind].g = l:
|
||||
light[ind].b = l;
|
||||
blocklight[ind].r = l.x;
|
||||
blocklight[ind].g = l.y;
|
||||
blocklight[ind].b = l.z;
|
||||
}
|
||||
|
||||
inline unsigned char BlockChunk::getSunlight(unsigned int ind) {
|
||||
return 15;
|
||||
if (ind % 2 == 0) return sunlight[ind / 2].a;
|
||||
else return sunlight[ind / 2].b;
|
||||
}
|
||||
|
||||
inline glm::ivec3 BlockChunk::getBlockLight(unsigned int ind) {
|
||||
return { light[ind].r, light[ind].g, light[ind].b };
|
||||
}
|
||||
|
||||
inline unsigned char BlockChunk::getBlockLight(unsigned int ind, unsigned char channel) {
|
||||
return channel == 0 ? light[ind].r:
|
||||
channel == 1 ? light[ind].g:
|
||||
light[ind].b;
|
||||
}
|
||||
|
||||
inline glm::vec4 BlockChunk::getLightVec(unsigned int ind) {
|
||||
return glm::vec4 { light[ind].r, light[ind].g, light[ind].b, getSunlight(ind) };
|
||||
inline void BlockChunk::setSunlight(unsigned int ind, unsigned char val) {
|
||||
if (ind % 2 == 0) sunlight[ind / 2].a = val;
|
||||
else sunlight[ind / 2].b = val;
|
||||
}
|
|
@ -7,6 +7,6 @@ zepha.register_block("zeus:default:dirt", {
|
|||
shovel = 1,
|
||||
pick = 2
|
||||
},
|
||||
light_source = { 0, 0, 31 },
|
||||
light_source = { 0, 16, 31 },
|
||||
yields = "zeus:default:dirt"
|
||||
})
|
|
@ -1,6 +1,7 @@
|
|||
zepha.register_block("zeus:default:leaves", {
|
||||
visible = true,
|
||||
culls = false,
|
||||
light_propagates = true,
|
||||
name = "Leaves",
|
||||
model = "base:leaf_like",
|
||||
textures = {
|
||||
|
|
|
@ -1,127 +1,127 @@
|
|||
local noise = {
|
||||
heightmap = {
|
||||
module = "add",
|
||||
sources = {{
|
||||
## Elevation
|
||||
module = "scale_bias",
|
||||
source = {
|
||||
module = "perlin",
|
||||
frequency = 0.002,
|
||||
octaves = 8
|
||||
},
|
||||
scale = 250,
|
||||
bias = -32
|
||||
}, {
|
||||
## Features
|
||||
module = "scale_bias",
|
||||
source = {
|
||||
module = "perlin",
|
||||
frequency = 0.2,
|
||||
octaves = 3,
|
||||
},
|
||||
scale = 6,
|
||||
bias = 6
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
local woo = "zeus:default:wood"
|
||||
local lea = "zeus:default:leaves"
|
||||
local inv = "invalid"
|
||||
|
||||
local trunk_layer_0 = {
|
||||
{ inv, inv, inv, inv, inv },
|
||||
{ inv, woo, woo, woo, inv },
|
||||
{ inv, woo, woo, woo, inv },
|
||||
{ inv, woo, woo, woo, inv },
|
||||
{ inv, inv, inv, inv, inv }
|
||||
}
|
||||
|
||||
local trunk_layer_1 = {
|
||||
{ inv, inv, inv, inv, inv },
|
||||
{ inv, inv, woo, inv, inv },
|
||||
{ inv, woo, woo, woo, inv },
|
||||
{ inv, inv, woo, inv, inv },
|
||||
{ inv, inv, inv, inv, inv }
|
||||
}
|
||||
|
||||
local trunk_layer_2 = {
|
||||
{ inv, inv, inv, inv, inv },
|
||||
{ inv, inv, inv, inv, inv },
|
||||
{ inv, inv, woo, inv, inv },
|
||||
{ inv, inv, inv, inv, inv },
|
||||
{ inv, inv, inv, inv, inv }
|
||||
}
|
||||
|
||||
local leaf_layer_1 = {
|
||||
{ inv, lea, lea, lea, inv },
|
||||
{ lea, lea, lea, lea, lea },
|
||||
{ lea, lea, woo, lea, lea },
|
||||
{ lea, lea, lea, lea, lea },
|
||||
{ inv, lea, lea, lea, inv }
|
||||
}
|
||||
|
||||
local leaf_layer_2 = {
|
||||
{ inv, inv, inv, inv, inv },
|
||||
{ inv, lea, lea, lea, inv },
|
||||
{ inv, lea, woo, lea, inv },
|
||||
{ inv, lea, lea, lea, inv },
|
||||
{ inv, inv, inv, inv, inv }
|
||||
}
|
||||
|
||||
local leaf_layer_3 = {
|
||||
{ inv, inv, inv, inv, inv },
|
||||
{ inv, lea, lea, inv, inv },
|
||||
{ inv, lea, lea, lea, inv },
|
||||
{ inv, inv, lea, lea, inv },
|
||||
{ inv, inv, inv, inv, inv }
|
||||
}
|
||||
|
||||
local tree = zepha.create_structure({
|
||||
origin = V(2, 2, 2),
|
||||
schematic = {
|
||||
trunk_layer_0,
|
||||
trunk_layer_0,
|
||||
trunk_layer_0,
|
||||
trunk_layer_0,
|
||||
trunk_layer_1,
|
||||
trunk_layer_1,
|
||||
trunk_layer_1,
|
||||
trunk_layer_2,
|
||||
trunk_layer_2,
|
||||
trunk_layer_2,
|
||||
trunk_layer_2,
|
||||
trunk_layer_2,
|
||||
trunk_layer_2,
|
||||
trunk_layer_2,
|
||||
trunk_layer_2,
|
||||
trunk_layer_2,
|
||||
trunk_layer_2,
|
||||
trunk_layer_2,
|
||||
leaf_layer_2,
|
||||
leaf_layer_1,
|
||||
leaf_layer_1,
|
||||
leaf_layer_1,
|
||||
leaf_layer_1,
|
||||
leaf_layer_2,
|
||||
leaf_layer_3
|
||||
}
|
||||
})
|
||||
|
||||
zepha.register_biome("zeus:mapgen:forest", {
|
||||
environment = {
|
||||
temperature = 15/100,
|
||||
humidity = 80/100,
|
||||
roughness = 20/100,
|
||||
},
|
||||
blocks = {
|
||||
top = "zeus:default:grass",
|
||||
soil = "zeus:default:dirt",
|
||||
rock = "zeus:default:stone"
|
||||
},
|
||||
biome_tint = "#7beb26",
|
||||
noise = noise,
|
||||
structures = {
|
||||
tree
|
||||
}
|
||||
})
|
||||
##local noise = {
|
||||
## heightmap = {
|
||||
## module = "add",
|
||||
## sources = {{
|
||||
## ## Elevation
|
||||
## module = "scale_bias",
|
||||
## source = {
|
||||
## module = "perlin",
|
||||
## frequency = 0.002,
|
||||
## octaves = 8
|
||||
## },
|
||||
## scale = 250,
|
||||
## bias = -32
|
||||
## }, {
|
||||
## ## Features
|
||||
## module = "scale_bias",
|
||||
## source = {
|
||||
## module = "perlin",
|
||||
## frequency = 0.2,
|
||||
## octaves = 3,
|
||||
## },
|
||||
## scale = 6,
|
||||
## bias = 6
|
||||
## }}
|
||||
## }
|
||||
##}
|
||||
##
|
||||
##local woo = "zeus:default:wood"
|
||||
##local lea = "zeus:default:leaves"
|
||||
##local inv = "invalid"
|
||||
##
|
||||
##local trunk_layer_0 = {
|
||||
## { inv, inv, inv, inv, inv },
|
||||
## { inv, woo, woo, woo, inv },
|
||||
## { inv, woo, woo, woo, inv },
|
||||
## { inv, woo, woo, woo, inv },
|
||||
## { inv, inv, inv, inv, inv }
|
||||
##}
|
||||
##
|
||||
##local trunk_layer_1 = {
|
||||
## { inv, inv, inv, inv, inv },
|
||||
## { inv, inv, woo, inv, inv },
|
||||
## { inv, woo, woo, woo, inv },
|
||||
## { inv, inv, woo, inv, inv },
|
||||
## { inv, inv, inv, inv, inv }
|
||||
##}
|
||||
##
|
||||
##local trunk_layer_2 = {
|
||||
## { inv, inv, inv, inv, inv },
|
||||
## { inv, inv, inv, inv, inv },
|
||||
## { inv, inv, woo, inv, inv },
|
||||
## { inv, inv, inv, inv, inv },
|
||||
## { inv, inv, inv, inv, inv }
|
||||
##}
|
||||
##
|
||||
##local leaf_layer_1 = {
|
||||
## { inv, lea, lea, lea, inv },
|
||||
## { lea, lea, lea, lea, lea },
|
||||
## { lea, lea, woo, lea, lea },
|
||||
## { lea, lea, lea, lea, lea },
|
||||
## { inv, lea, lea, lea, inv }
|
||||
##}
|
||||
##
|
||||
##local leaf_layer_2 = {
|
||||
## { inv, inv, inv, inv, inv },
|
||||
## { inv, lea, lea, lea, inv },
|
||||
## { inv, lea, woo, lea, inv },
|
||||
## { inv, lea, lea, lea, inv },
|
||||
## { inv, inv, inv, inv, inv }
|
||||
##}
|
||||
##
|
||||
##local leaf_layer_3 = {
|
||||
## { inv, inv, inv, inv, inv },
|
||||
## { inv, lea, lea, inv, inv },
|
||||
## { inv, lea, lea, lea, inv },
|
||||
## { inv, inv, lea, lea, inv },
|
||||
## { inv, inv, inv, inv, inv }
|
||||
##}
|
||||
##
|
||||
##local tree = zepha.create_structure({
|
||||
## origin = V(2, 2, 2),
|
||||
## schematic = {
|
||||
## trunk_layer_0,
|
||||
## trunk_layer_0,
|
||||
## trunk_layer_0,
|
||||
## trunk_layer_0,
|
||||
## trunk_layer_1,
|
||||
## trunk_layer_1,
|
||||
## trunk_layer_1,
|
||||
## trunk_layer_2,
|
||||
## trunk_layer_2,
|
||||
## trunk_layer_2,
|
||||
## trunk_layer_2,
|
||||
## trunk_layer_2,
|
||||
## trunk_layer_2,
|
||||
## trunk_layer_2,
|
||||
## trunk_layer_2,
|
||||
## trunk_layer_2,
|
||||
## trunk_layer_2,
|
||||
## trunk_layer_2,
|
||||
## leaf_layer_2,
|
||||
## leaf_layer_1,
|
||||
## leaf_layer_1,
|
||||
## leaf_layer_1,
|
||||
## leaf_layer_1,
|
||||
## leaf_layer_2,
|
||||
## leaf_layer_3
|
||||
## }
|
||||
##})
|
||||
##
|
||||
##zepha.register_biome("zeus:mapgen:forest", {
|
||||
## environment = {
|
||||
## temperature = 15/100,
|
||||
## humidity = 80/100,
|
||||
## roughness = 20/100,
|
||||
## },
|
||||
## blocks = {
|
||||
## top = "zeus:default:grass",
|
||||
## soil = "zeus:default:dirt",
|
||||
## rock = "zeus:default:stone"
|
||||
## },
|
||||
## biome_tint = "#7beb26",
|
||||
## noise = noise,
|
||||
## structures = {
|
||||
## tree
|
||||
## }
|
||||
##})
|
|
@ -19,7 +19,7 @@ local noise = {
|
|||
frequency = 0.2,
|
||||
octaves = 3,
|
||||
},
|
||||
scale = 6,
|
||||
scale = 12,
|
||||
bias = 6
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -1,44 +1,46 @@
|
|||
local noise = {
|
||||
heightmap = {
|
||||
module = "add",
|
||||
sources = {{
|
||||
## Elevation
|
||||
module = "scale_bias",
|
||||
source = {
|
||||
module = "perlin",
|
||||
frequency = 0.002,
|
||||
octaves = 8
|
||||
},
|
||||
scale = 250,
|
||||
bias = -32
|
||||
}, {
|
||||
## Features
|
||||
module = "scale_bias",
|
||||
source = {
|
||||
module = "perlin",
|
||||
frequency = 0.2,
|
||||
octaves = 3,
|
||||
},
|
||||
scale = 6,
|
||||
bias = 6
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
zepha.register_biome("zeus:mapgen:plains", {
|
||||
environment = {
|
||||
temperature = 15/100,
|
||||
humidity = 60/100,
|
||||
roughness = 20/100,
|
||||
},
|
||||
blocks = {
|
||||
top = "zeus:default:grass",
|
||||
soil = "zeus:default:dirt",
|
||||
rock = "zeus:default:stone"
|
||||
},
|
||||
biome_tint = "#aaed45",
|
||||
noise = noise,
|
||||
structures = {
|
||||
tree
|
||||
}
|
||||
})
|
||||
##local noise = {
|
||||
## heightmap = {
|
||||
## module = "const",
|
||||
## value = -12
|
||||
#### module = "add",
|
||||
#### sources = {{
|
||||
#### ## Elevation
|
||||
#### module = "scale_bias",
|
||||
#### source = {
|
||||
#### module = "perlin",
|
||||
#### frequency = 0.002,
|
||||
#### octaves = 8
|
||||
#### },
|
||||
#### scale = 250,
|
||||
#### bias = -32
|
||||
#### }, {
|
||||
#### ## Features
|
||||
#### module = "scale_bias",
|
||||
#### source = {
|
||||
#### module = "perlin",
|
||||
#### frequency = 0.2,
|
||||
#### octaves = 3,
|
||||
#### },
|
||||
#### scale = 6,
|
||||
#### bias = 6
|
||||
#### }}
|
||||
## }
|
||||
##}
|
||||
##
|
||||
##zepha.register_biome("zeus:mapgen:plains", {
|
||||
## environment = {
|
||||
## temperature = 15/100,
|
||||
## humidity = 60/100,
|
||||
## roughness = 20/100,
|
||||
## },
|
||||
## blocks = {
|
||||
## top = "zeus:default:grass",
|
||||
## soil = "zeus:default:dirt",
|
||||
## rock = "zeus:default:stone"
|
||||
## },
|
||||
## biome_tint = "#aaed45",
|
||||
## noise = noise,
|
||||
## structures = {
|
||||
## tree
|
||||
## }
|
||||
##})
|
|
@ -10,41 +10,41 @@
|
|||
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
|
||||
|
||||
TEST_CASE("BlockChunk", "[engine]") {
|
||||
SECTION("Lighting") {
|
||||
BlockChunk b;
|
||||
|
||||
b.setSunlight(1, 4);
|
||||
b.setSunlight(2, 1);
|
||||
b.setSunlight(3, 11);
|
||||
b.setSunlight(4, 5);
|
||||
b.setSunlight(100, 15);
|
||||
b.setSunlight(3000, 0);
|
||||
|
||||
b.setBlocklight(1, 4);
|
||||
b.setBlocklight(2, 1);
|
||||
b.setBlocklight(3, 11);
|
||||
b.setBlocklight(4, 5);
|
||||
b.setBlocklight(100, 15);
|
||||
b.setBlocklight(3000, 0);
|
||||
|
||||
SECTION("Sunlight") {
|
||||
REQUIRE(b.getSunlight(1) == 4);
|
||||
REQUIRE(b.getSunlight(2) == 1);
|
||||
REQUIRE(b.getSunlight(3) == 11);
|
||||
REQUIRE(b.getSunlight(4) == 5);
|
||||
REQUIRE(b.getSunlight(100) == 15);
|
||||
REQUIRE(b.getSunlight(3000) == 0);
|
||||
}
|
||||
|
||||
SECTION("Blocklight") {
|
||||
REQUIRE(b.getBlocklight(1) == 4);
|
||||
REQUIRE(b.getBlocklight(2) == 1);
|
||||
REQUIRE(b.getBlocklight(3) == 11);
|
||||
REQUIRE(b.getBlocklight(4) == 5);
|
||||
REQUIRE(b.getBlocklight(100) == 15);
|
||||
REQUIRE(b.getBlocklight(3000) == 0);
|
||||
}
|
||||
}
|
||||
// SECTION("Lighting") {
|
||||
// BlockChunk b;
|
||||
//
|
||||
// b.setSunlight(1, 4);
|
||||
// b.setSunlight(2, 1);
|
||||
// b.setSunlight(3, 11);
|
||||
// b.setSunlight(4, 5);
|
||||
// b.setSunlight(100, 15);
|
||||
// b.setSunlight(3000, 0);
|
||||
//
|
||||
// b.setBlocklight(1, 4);
|
||||
// b.setBlocklight(2, 1);
|
||||
// b.setBlocklight(3, 11);
|
||||
// b.setBlocklight(4, 5);
|
||||
// b.setBlocklight(100, 15);
|
||||
// b.setBlocklight(3000, 0);
|
||||
//
|
||||
// SECTION("Sunlight") {
|
||||
// REQUIRE(b.getSunlight(1) == 4);
|
||||
// REQUIRE(b.getSunlight(2) == 1);
|
||||
// REQUIRE(b.getSunlight(3) == 11);
|
||||
// REQUIRE(b.getSunlight(4) == 5);
|
||||
// REQUIRE(b.getSunlight(100) == 15);
|
||||
// REQUIRE(b.getSunlight(3000) == 0);
|
||||
// }
|
||||
//
|
||||
// SECTION("Blocklight") {
|
||||
// REQUIRE(b.getBlocklight(1) == 4);
|
||||
// REQUIRE(b.getBlocklight(2) == 1);
|
||||
// REQUIRE(b.getBlocklight(3) == 11);
|
||||
// REQUIRE(b.getBlocklight(4) == 5);
|
||||
// REQUIRE(b.getBlocklight(100) == 15);
|
||||
// REQUIRE(b.getBlocklight(3000) == 0);
|
||||
// }
|
||||
// }
|
||||
|
||||
SECTION("Blocks") {
|
||||
|
||||
|
|
Loading…
Reference in New Issue