diff --git a/assets/shader/world/deferredGeometryWorld.vs b/assets/shader/world/deferredGeometryWorld.vs index 309b8e02..bda88250 100644 --- a/assets/shader/world/deferredGeometryWorld.vs +++ b/assets/shader/world/deferredGeometryWorld.vs @@ -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; diff --git a/src/def/gen/MapGen.cpp b/src/def/gen/MapGen.cpp index 89c57409..c2fcbcc7 100644 --- a/src/def/gen/MapGen.cpp +++ b/src/def/gen/MapGen.cpp @@ -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 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(!(lightLevel == 15 && i.y == -1))); queue.emplace(ind, chunk); } } diff --git a/src/world/Dimension.cpp b/src/world/Dimension.cpp index ddb1b69d..38ff4d27 100644 --- a/src/world/Dimension.cpp +++ b/src/world/Dimension.cpp @@ -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 { 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 Dimension::propogateAddNodes() { + std::unordered_set 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 Dimension::propogateRemoveNodes() { + std::unordered_set 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 Dimension::propogateAddNodes() { - std::unordered_set 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 Dimension::propogateRemoveNodes() { - std::unordered_set 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(); +} \ No newline at end of file