Attempting to propogate light downwards

master
Nicole Collings 2020-05-28 16:53:23 -07:00
parent 0bfe269308
commit aa624464e0
3 changed files with 152 additions and 117 deletions

View File

@ -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) * (aLight.w / 16.0), 0, 1);
vec3 sunlightColor = clamp(sunlightIntensity * 1.25 * vec3(1, 1, 1) * (aLight.w / 15.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;

View File

@ -245,8 +245,8 @@ void MapGen::generateSunlight(MapGen::chunk_partials_map &chunks, glm::ivec3 mbP
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;
if (c.y == 3) break;
}
}
}
@ -268,8 +268,7 @@ void MapGen::propogateSunlightNodes(MapGen::chunk_partials_map &chunks, std::que
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) {
for (const auto& i : Vec::adj) {
glm::ivec3 check = worldPos + i;
BlockChunk* chunk;
@ -283,9 +282,7 @@ void MapGen::propogateSunlightNodes(MapGen::chunk_partials_map &chunks, std::que
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);
chunk->setSunlight(ind, lightLevel - static_cast<int>(!(lightLevel == 15 && i.y == -1)));
queue.emplace(ind, chunk);
}
}

View File

@ -4,31 +4,161 @@
#include "Dimension.h"
bool Dimension::setBlock(glm::ivec3 pos, unsigned int block) {
if (!DimensionBase::setBlock(pos, block)) return false;
auto chunk = getChunk(Space::Chunk::world::fromBlock(pos));
auto &def = defs.blockFromId(block);
// Remove light when placing solid blocks.
glm::ivec4 oldLight = chunk->getLight(Space::Block::index(pos));
if (!def.lightPropagates && oldLight.x + oldLight.y + oldLight.z != 0) removeBlockLight(pos);
// Add light when placing light emitting blocks.
glm::ivec3 newLight = def.lightSource;
if (newLight.x > oldLight.x || newLight.y > oldLight.y || newLight.z > oldLight.z) addBlockLight(pos, newLight);
// Reflow light when a transparent block is placed.
if (def.lightPropagates) reflowLightAroundTransparent(pos);
// Block sunlight when a solid block is placed.
if (!def.lightPropagates && getLight(pos, chunk.get()).w != 0) reflowSunlightAroundSolid(pos);
return true;
}
void Dimension::calculateEdgeLight(glm::ivec3 mbPos) {
for (auto i = 0; i < 64; i++) {
glm::ivec3 l = Space::Chunk::fromIndex(i);
glm::ivec3 chunkPos = mbPos * 4 + l;
auto edges = std::array<bool, 6> { l.x == 0, l.y == 0, l.z == 0,
l.x == Space::MAPBLOCK_SIZE, l.y == Space::MAPBLOCK_SIZE, l.z == Space::MAPBLOCK_SIZE};
l.x == Space::MAPBLOCK_SIZE - 1, l.y == Space::MAPBLOCK_SIZE - 1, l.z == Space::MAPBLOCK_SIZE - 1};
// Pull light from above
if (edges[4]) {
if (!getChunk(chunkPos + glm::ivec3 {0, 1, 0})) continue;
auto chunk = getChunk(chunkPos).get();
for (unsigned int j = 0; j < 16; j++) {
for (unsigned int k = 0; k < 16; k++) {
glm::ivec3 belowPos = chunkPos * 16 + glm::ivec3 {j, 15, k};
glm::ivec3 abovePos = belowPos + glm::ivec3 {0, 1, 0};
unsigned int lightAbove = getLight(abovePos).w;
unsigned int lightBelow = getLight(belowPos).w;
if (lightBelow > lightAbove) {
unsigned int ind = Space::Block::index(belowPos);
lightRemoveQueue[SUNLIGHT_CHANNEL].emplace(ind, lightBelow, chunk);
chunk->setSunlight(ind, 0);
}
}
}
}
// Push light below
if (edges[1]) {
for (unsigned int j = 0; j < 64; j++) {
for (unsigned int k = 0; k < 64; k++) {
auto belowChunk = getChunk(chunkPos + glm::ivec3 {0, -1, 0}).get();
if (!belowChunk) continue;
for (unsigned int j = 0; j < 16; j++) {
for (unsigned int k = 0; k < 16; k++) {
glm::ivec3 abovePos = chunkPos * 16 + glm::ivec3 {j, 0, k};
glm::ivec3 belowPos = abovePos + glm::ivec3 {0, -1, 0};
unsigned int lightAbove = getLight(abovePos).w;
unsigned int lightBelow = getLight(belowPos).w;
if (lightBelow > lightAbove) {
unsigned int ind = Space::Block::index(belowPos);
lightRemoveQueue[SUNLIGHT_CHANNEL].emplace(ind, lightBelow, belowChunk);
belowChunk->setSunlight(ind, 0);
}
}
}
}
}
propogateRemoveNodes();
}
void Dimension::reflowSunlightAroundSolid(glm::ivec3 pos) {
auto startChunk = getChunk(Space::Chunk::world::fromBlock(pos));
auto ind = Space::Block::index(pos);
unsigned int light = startChunk->getSunlight(ind);
startChunk->setSunlight(ind, 0);
lightRemoveQueue[SUNLIGHT_CHANNEL].emplace(ind, light, startChunk.get());
propogateRemoveNodes();
std::unordered_set<glm::ivec3, Vec::ivec3> Dimension::propogateAddNodes() {
std::unordered_set<glm::ivec3, Vec::ivec3> chunksUpdated {};
for (unsigned int channel = 0; channel < lightAddQueue.size(); channel++) {
while (!lightAddQueue[channel].empty()) {
LightAddNode& node = lightAddQueue[channel].front();
unsigned char lightLevel = node.chunk->getLight(node.index, channel);
glm::ivec3 worldPos = node.chunk->pos * 16 + Space::Block::fromIndex(node.index);
for (const auto& i : Vec::adj) {
glm::ivec3 check = worldPos + i;
unsigned int ind = Space::Block::index(check);
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;
}
bool sunDown = channel == SUNLIGHT_CHANNEL && lightLevel == 15 && i.y == -1;
if (defs.blockFromId(chunk->getBlock(ind)).lightPropagates && (sunDown || chunk->getLight(ind, channel) + 2 <= lightLevel)) {
int subtract = sunDown ? 0 : 1;
chunk->setLight(ind, channel, lightLevel - subtract);
lightAddQueue[channel].emplace(ind, chunk);
}
}
lightAddQueue[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 < lightRemoveQueue.size(); channel++) {
while (!lightRemoveQueue[channel].empty()) {
LightRemoveNode& node = lightRemoveQueue[channel].front();
glm::ivec3 worldPos = node.chunk->pos * 16 + Space::Block::fromIndex(node.index);
for (const auto& i : Vec::adj) {
glm::ivec3 check = worldPos + i;
unsigned int ind = Space::Block::index(check);
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;
}
unsigned char checkLight = chunk->getLight(ind, channel);
if (checkLight != 0 && (checkLight < node.value || (i.y == -1 && node.value == 15))) {
unsigned int replaceLight = channel == SUNLIGHT_CHANNEL ? 0 :
defs.blockFromId(chunk->getBlock(Space::Block::index(check))).lightSource[channel];
chunk->setLight(ind, channel, replaceLight);
if (replaceLight) lightAddQueue[channel].emplace(ind, chunk);
lightRemoveQueue[channel].emplace(ind, checkLight, chunk);
}
else if (checkLight >= node.value) {
auto chunk = containsWorldPos(node.chunk, check) ? node.chunk : getChunk(Space::Chunk::world::fromBlock(check)).get();
if (!chunk) continue;
lightAddQueue[channel].emplace(ind, chunk);
}
}
lightRemoveQueue[channel].pop();
}
}
propogateAddNodes(); //TODO: Merge returned chunks with our list
return chunksUpdated;
}
bool Dimension::containsWorldPos(BlockChunk *chunk, glm::ivec3 pos) {
@ -93,103 +223,11 @@ void Dimension::reflowLightAroundTransparent(glm::ivec3 pos) {
propogateAddNodes();
}
std::unordered_set<glm::ivec3, Vec::ivec3> Dimension::propogateAddNodes() {
std::unordered_set<glm::ivec3, Vec::ivec3> chunksUpdated {};
for (unsigned int channel = 0; channel < lightAddQueue.size(); channel++) {
while (!lightAddQueue[channel].empty()) {
LightAddNode& node = lightAddQueue[channel].front();
unsigned char lightLevel = node.chunk->getLight(node.index, channel);
glm::ivec3 worldPos = node.chunk->pos * 16 + Space::Block::fromIndex(node.index);
for (const auto& i : Vec::adj) {
glm::ivec3 check = worldPos + i;
unsigned int ind = Space::Block::index(check);
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;
}
bool sunDown = channel == SUNLIGHT_CHANNEL && lightLevel == 15 && i.y == -1;
if (defs.blockFromId(chunk->getBlock(ind)).lightPropagates && (sunDown || chunk->getLight(ind, channel) + 2 <= lightLevel)) {
int subtract = sunDown ? 0 : 1;
chunk->setLight(ind, channel, lightLevel - subtract);
lightAddQueue[channel].emplace(ind, chunk);
}
}
lightAddQueue[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 < lightRemoveQueue.size(); channel++) {
while (!lightRemoveQueue[channel].empty()) {
LightRemoveNode& node = lightRemoveQueue[channel].front();
glm::ivec3 worldPos = node.chunk->pos * 16 + Space::Block::fromIndex(node.index);
for (const auto& i : Vec::adj) {
glm::ivec3 check = worldPos + i;
unsigned int ind = Space::Block::index(check);
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;
}
unsigned char checkLight = chunk->getLight(ind, channel);
if (checkLight != 0 && (checkLight < node.value || (i.y == -1 && node.value == 15))) {
auto blockLight = defs.blockFromId(chunk->getBlock(Space::Block::index(check))).lightSource[channel];
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);
}
else if (checkLight >= node.value) {
auto chunk = containsWorldPos(node.chunk, check) ? node.chunk : getChunk(Space::Chunk::world::fromBlock(check)).get();
if (!chunk) continue;
lightAddQueue[channel].emplace(Space::Block::index(check), chunk);
}
}
lightRemoveQueue[channel].pop();
}
}
propogateAddNodes(); //TODO: Merge returned chunks with our list
return chunksUpdated;
}
bool Dimension::setBlock(glm::ivec3 pos, unsigned int block) {
if (!DimensionBase::setBlock(pos, block)) return false;
auto chunk = getChunk(Space::Chunk::world::fromBlock(pos));
auto &def = defs.blockFromId(block);
// Remove light when placing solid blocks.
glm::ivec4 oldLight = chunk->getLight(Space::Block::index(pos));
if (!def.lightPropagates && oldLight.x + oldLight.y + oldLight.z != 0) removeBlockLight(pos);
// Add light when placing light emitting blocks.
glm::ivec3 newLight = def.lightSource;
if (newLight.x > oldLight.x || newLight.y > oldLight.y || newLight.z > oldLight.z) addBlockLight(pos, newLight);
// Reflow light when a transparent block is placed.
if (def.lightPropagates) reflowLightAroundTransparent(pos);
// Block sunlight when a solid block is placed.
if (!def.lightPropagates && getLight(pos, chunk.get()).w != 0) reflowSunlightAroundSolid(pos);
return true;
}
void Dimension::reflowSunlightAroundSolid(glm::ivec3 pos) {
auto startChunk = getChunk(Space::Chunk::world::fromBlock(pos));
auto ind = Space::Block::index(pos);
unsigned int light = startChunk->getSunlight(ind);
startChunk->setSunlight(ind, 0);
lightRemoveQueue[SUNLIGHT_CHANNEL].emplace(ind, light, startChunk.get());
propogateRemoveNodes();
}