[Chunk] First attempt to lighting.
This commit is contained in:
parent
72c7948e74
commit
09ba9c84d3
@ -17,10 +17,11 @@
|
||||
#include "OpenGL.hpp"
|
||||
|
||||
struct Vertex {
|
||||
GLfloat coord3d[4] = {0, 0, 0, 1};
|
||||
GLfloat color[4] = {0, 0, 0, 1};
|
||||
GLfloat normal[3] = {0, 0, 0};
|
||||
GLfloat texCoord[2] = {0, 0};
|
||||
GLfloat coord3d[4] = {0, 0, 0, 1};
|
||||
GLfloat color[4] = {0, 0, 0, 1};
|
||||
GLfloat normal[3] = {0, 0, 0};
|
||||
GLfloat texCoord[2] = {0, 0};
|
||||
GLfloat lightValue[2] = {-1, -1};
|
||||
};
|
||||
|
||||
#endif // VERTEX_HPP_
|
||||
|
@ -26,6 +26,23 @@
|
||||
#include "Texture.hpp"
|
||||
#include "VertexBuffer.hpp"
|
||||
|
||||
#include <queue>
|
||||
|
||||
struct LightNode {
|
||||
LightNode(int _x, int _y, int _z) : x(_x), y(_y), z(_z) {}
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
};
|
||||
|
||||
struct LightRemovalNode {
|
||||
LightRemovalNode(int _x, int _y, int _z, int _value) : x(_x), y(_y), z(_z), value(_value) {}
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
int value;
|
||||
};
|
||||
|
||||
class Chunk : public NonCopyable, public IDrawable {
|
||||
public:
|
||||
Chunk(s32 x, s32 y, s32 z, Texture &texture);
|
||||
@ -35,6 +52,11 @@ class Chunk : public NonCopyable, public IDrawable {
|
||||
u32 getBlock(int x, int y, int z) const;
|
||||
void setBlock(int x, int y, int z, u32 id);
|
||||
|
||||
void addLight(Chunk &chunk, int x, int y, int z, int val);
|
||||
void removeLight(Chunk &chunk, int x, int y, int z);
|
||||
|
||||
void updateLights(Chunk &chunk);
|
||||
|
||||
s32 x() const { return m_x; }
|
||||
s32 y() const { return m_y; }
|
||||
s32 z() const { return m_z; }
|
||||
@ -65,6 +87,12 @@ class Chunk : public NonCopyable, public IDrawable {
|
||||
void setGenerated(bool isGenerated) { m_isGenerated = isGenerated; }
|
||||
void setInitialized(bool isInitialized) { m_isInitialized = isInitialized; }
|
||||
|
||||
int getSunlight(int x, int y, int z) const;
|
||||
void setSunlight(int x, int y, int z, int val);
|
||||
|
||||
int getTorchlight(int x, int y, int z) const;
|
||||
void setTorchlight(int x, int y, int z, int val);
|
||||
|
||||
private:
|
||||
void draw(RenderTarget &target, RenderStates states) const override;
|
||||
void drawOutlines(RenderTarget &target, RenderStates states) const;
|
||||
@ -79,6 +107,12 @@ class Chunk : public NonCopyable, public IDrawable {
|
||||
using DataArray = u32[Chunk::width][Chunk::height][Chunk::depth];
|
||||
DataArray m_data;
|
||||
|
||||
using LightMapArray = u8[Chunk::width][Chunk::height][Chunk::depth];
|
||||
LightMapArray m_lightMap;
|
||||
std::queue<LightNode> m_lightBfsQueue;
|
||||
std::queue<LightRemovalNode> m_lightRemovalBfsQueue;
|
||||
std::queue<LightNode> m_sunlightBfsQueue;
|
||||
|
||||
ChunkBuilder m_builder;
|
||||
|
||||
VertexBuffer m_vbo;
|
||||
|
@ -28,7 +28,7 @@ class ChunkBuilder {
|
||||
std::size_t buildChunk(const Chunk &chunk, const VertexBuffer &vbo);
|
||||
|
||||
private:
|
||||
void addFace(u8 x, u8 y, u8 z, u8 i, const Block *block, const Block *surroundingBlock);
|
||||
void addFace(u8 x, u8 y, u8 z, u8 i, const Chunk &chunk, const Block *block, const Block *surroundingBlock);
|
||||
|
||||
std::vector<Vertex> m_vertices;
|
||||
};
|
||||
|
@ -4,11 +4,13 @@ attribute vec4 color;
|
||||
attribute vec4 coord3d;
|
||||
attribute vec3 normal;
|
||||
attribute vec2 texCoord;
|
||||
attribute vec2 lightValue;
|
||||
|
||||
varying vec4 v_color;
|
||||
varying vec4 v_coord3d;
|
||||
varying vec4 v_normal;
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_lightValue;
|
||||
|
||||
uniform mat4 u_modelMatrix;
|
||||
uniform mat4 u_projectionMatrix;
|
||||
@ -19,9 +21,10 @@ void main() {
|
||||
v_normal = vec4(normal, 1.0);
|
||||
v_color = color;
|
||||
v_texCoord = texCoord;
|
||||
v_lightValue = lightValue;
|
||||
|
||||
// Get rid of unused 'normal' attribute warning
|
||||
v_coord3d = v_coord3d + v_normal * 0.00000000000000000001;
|
||||
// Get rid of unused 'normal'/'lightValue' attribute warning
|
||||
v_coord3d = v_coord3d + v_normal * vec4(v_lightValue, 1.0, 1.0) * 0.00000000000000000001;
|
||||
|
||||
gl_Position = u_projectionMatrix * u_viewMatrix * v_coord3d;
|
||||
}
|
||||
|
@ -3,6 +3,9 @@
|
||||
varying float v_blockID;
|
||||
varying float v_dist;
|
||||
|
||||
varying vec4 v_coord3d;
|
||||
varying vec2 v_lightValue;
|
||||
|
||||
uniform int u_renderDistance;
|
||||
|
||||
// Get current pixel color
|
||||
@ -36,8 +39,11 @@ void main() {
|
||||
// vec3 lightPosition = vec3(0.0, sin(time) * 40, cos(time) * 40);
|
||||
// color *= light(vec3(1.0, 1.0, 1.0), vec4(lightPosition, 1.0), 0.5, 0.5);
|
||||
|
||||
if (v_blockID != -1)
|
||||
color = light(color, vec3(1.0, 1.0, 1.0), vec4(0.0, 48.0, 0.0, 1.0), 0.5, 0.5);
|
||||
if (v_lightValue.x != -1)
|
||||
color = light(color, vec3(1.0, 1.0, 1.0), v_coord3d, v_lightValue.y / 14.0, 1.0);
|
||||
|
||||
/* if (v_blockID != -1) */
|
||||
/* color = light(color, vec3(1.0, 1.0, 1.0), vec4(0.0, 48.0, 0.0, 1.0), 0.5, 0.5); */
|
||||
|
||||
color = fog(color, v_dist, u_renderDistance - 32, u_renderDistance);
|
||||
|
||||
|
@ -4,11 +4,13 @@ attribute vec4 color;
|
||||
attribute vec4 coord3d;
|
||||
attribute vec3 normal;
|
||||
attribute vec2 texCoord;
|
||||
attribute vec2 lightValue;
|
||||
|
||||
varying vec4 v_color;
|
||||
varying vec4 v_coord3d;
|
||||
varying vec4 v_normal;
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_lightValue;
|
||||
|
||||
varying float v_blockID;
|
||||
varying float v_dist;
|
||||
@ -42,6 +44,7 @@ void main() {
|
||||
|
||||
v_color = color;
|
||||
v_texCoord = texCoord;
|
||||
v_lightValue = lightValue;
|
||||
|
||||
// Distance from eye
|
||||
v_dist = length(u_viewMatrix * v_coord3d);
|
||||
|
@ -38,6 +38,7 @@ void RenderTarget::draw(const VertexBuffer &vertexBuffer, GLenum mode, std::size
|
||||
states.shader->enableVertexAttribArray("coord3d");
|
||||
states.shader->enableVertexAttribArray("normal");
|
||||
states.shader->enableVertexAttribArray((states.texture) ? "texCoord" : "color");
|
||||
states.shader->enableVertexAttribArray("lightValue");
|
||||
|
||||
// glVertexAttribPointer(states.shader->attrib("coord3d"), 4, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
glVertexAttribPointer(states.shader->attrib("coord3d"), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<GLvoid *>(offsetof(Vertex, coord3d)));
|
||||
@ -46,6 +47,7 @@ void RenderTarget::draw(const VertexBuffer &vertexBuffer, GLenum mode, std::size
|
||||
glVertexAttribPointer(states.shader->attrib("texCoord"), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<GLvoid *>(offsetof(Vertex, texCoord)));
|
||||
else
|
||||
glVertexAttribPointer(states.shader->attrib("color"), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<GLvoid *>(offsetof(Vertex, color)));
|
||||
glVertexAttribPointer(states.shader->attrib("lightValue"), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<GLvoid *>(offsetof(Vertex, lightValue)));
|
||||
|
||||
|
||||
if (states.texture)
|
||||
@ -55,6 +57,7 @@ void RenderTarget::draw(const VertexBuffer &vertexBuffer, GLenum mode, std::size
|
||||
|
||||
Texture::bind(nullptr);
|
||||
|
||||
states.shader->disableVertexAttribArray("lightValue");
|
||||
states.shader->disableVertexAttribArray((states.texture) ? "texCoord" : "color");
|
||||
states.shader->disableVertexAttribArray("normal");
|
||||
states.shader->disableVertexAttribArray("coord3d");
|
||||
|
@ -18,6 +18,9 @@ Chunk::Chunk(s32 x, s32 y, s32 z, Texture &texture) : m_texture(texture) {
|
||||
m_x = x;
|
||||
m_y = y;
|
||||
m_z = z;
|
||||
|
||||
std::memset(m_data, 0, sizeof(m_data));
|
||||
std::memset(m_lightMap, 0, sizeof(m_lightMap));
|
||||
}
|
||||
|
||||
void Chunk::update(World &world) {
|
||||
@ -67,6 +70,11 @@ void Chunk::setBlock(int x, int y, int z, u32 type) {
|
||||
m_tickingBlocks.erase(it);
|
||||
}
|
||||
|
||||
if (type == 2)
|
||||
addLight(*this, x, y, z, 14);
|
||||
else if (m_data[x][y][z] == 2)
|
||||
removeLight(*this, x, y, z);
|
||||
|
||||
m_data[x][y][z] = type;
|
||||
|
||||
m_isChanged = true;
|
||||
@ -79,6 +87,137 @@ void Chunk::setBlock(int x, int y, int z, u32 type) {
|
||||
if(z == depth - 1 && back()) { back()->m_isChanged = true; }
|
||||
}
|
||||
|
||||
void Chunk::addLight(Chunk &chunk, int x, int y, int z, int val) {
|
||||
chunk.setTorchlight(x, y, z, val);
|
||||
m_lightBfsQueue.emplace(x, y, z);
|
||||
updateLights(chunk);
|
||||
}
|
||||
|
||||
void Chunk::removeLight(Chunk &chunk, int x, int y, int z) {
|
||||
m_lightRemovalBfsQueue.emplace(x, y, z, chunk.getTorchlight(x, y, z));
|
||||
chunk.setTorchlight(x, y, z, 0);
|
||||
updateLights(chunk);
|
||||
}
|
||||
|
||||
void Chunk::updateLights(Chunk &chunk) {
|
||||
while (!m_lightRemovalBfsQueue.empty()) {
|
||||
LightRemovalNode node = m_lightRemovalBfsQueue.front();
|
||||
m_lightRemovalBfsQueue.pop();
|
||||
|
||||
LightNode surroundingNodes[6] = {
|
||||
{node.x - 1, node.y, node.z},
|
||||
{node.x + 1, node.y, node.z},
|
||||
{node.x, node.y - 1, node.z},
|
||||
{node.x, node.y + 1, node.z},
|
||||
{node.x, node.y, node.z - 1},
|
||||
{node.x, node.y, node.z + 1},
|
||||
};
|
||||
|
||||
for (const LightNode &surroundingNode : surroundingNodes) {
|
||||
int level = chunk.getTorchlight(surroundingNode.x, surroundingNode.y, surroundingNode.z);
|
||||
if (level != 0 && level < node.value) {
|
||||
chunk.setTorchlight(surroundingNode.x, surroundingNode.y, surroundingNode.z, 0);
|
||||
|
||||
m_lightRemovalBfsQueue.emplace(surroundingNode.x, surroundingNode.y, surroundingNode.z, level);
|
||||
}
|
||||
else if (level >= node.value) {
|
||||
m_lightBfsQueue.emplace(surroundingNode.x, surroundingNode.y, surroundingNode.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!m_lightBfsQueue.empty()) {
|
||||
LightNode node = m_lightBfsQueue.front();
|
||||
m_lightBfsQueue.pop();
|
||||
|
||||
LightNode surroundingNodes[6] = {
|
||||
{node.x - 1, node.y, node.z},
|
||||
{node.x + 1, node.y, node.z},
|
||||
{node.x, node.y - 1, node.z},
|
||||
{node.x, node.y + 1, node.z},
|
||||
{node.x, node.y, node.z - 1},
|
||||
{node.x, node.y, node.z + 1},
|
||||
};
|
||||
|
||||
int lightLevel = chunk.getTorchlight(node.x, node.y, node.z);
|
||||
for (const LightNode &surroundingNode : surroundingNodes) {
|
||||
if (/*!Registry::getInstance().getBlock(getBlock(surroundingNode.x, surroundingNode.y, surroundingNode.z)).isOpaque()
|
||||
&& */ chunk.getTorchlight(surroundingNode.x, surroundingNode.y, surroundingNode.z) + 2 <= lightLevel) {
|
||||
chunk.setTorchlight(surroundingNode.x, surroundingNode.y, surroundingNode.z, lightLevel - 1);
|
||||
|
||||
m_lightBfsQueue.emplace(surroundingNode.x, surroundingNode.y, surroundingNode.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!m_sunlightBfsQueue.empty()) {
|
||||
LightNode node = m_sunlightBfsQueue.front();
|
||||
m_sunlightBfsQueue.pop();
|
||||
|
||||
LightNode surroundingNodes[6] = {
|
||||
{node.x - 1, node.y, node.z},
|
||||
{node.x + 1, node.y, node.z},
|
||||
{node.x, node.y - 1, node.z},
|
||||
{node.x, node.y + 1, node.z},
|
||||
{node.x, node.y, node.z - 1},
|
||||
{node.x, node.y, node.z + 1},
|
||||
};
|
||||
|
||||
int sunlightLevel = chunk.getSunlight(node.x, node.y, node.z);
|
||||
for (const LightNode &surroundingNode : surroundingNodes) {
|
||||
if (/*!Registry::getInstance().getBlock(getBlock(surroundingNode.x, surroundingNode.y, surroundingNode.z)).isOpaque()
|
||||
&& */ chunk.getSunlight(surroundingNode.x, surroundingNode.y, surroundingNode.z) + 2 <= sunlightLevel) {
|
||||
chunk.setSunlight(surroundingNode.x, surroundingNode.y, surroundingNode.z, sunlightLevel - 1);
|
||||
|
||||
m_sunlightBfsQueue.emplace(surroundingNode.x, surroundingNode.y, surroundingNode.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Chunk::getSunlight(int x, int y, int z) const {
|
||||
if(x < 0) return m_surroundingChunks[0] ? m_surroundingChunks[0]->getSunlight(x + Chunk::width, y, z) : 0;
|
||||
if(x >= Chunk::width) return m_surroundingChunks[1] ? m_surroundingChunks[1]->getSunlight(x - Chunk::width, y, z) : 0;
|
||||
if(y < 0) return m_surroundingChunks[4] ? m_surroundingChunks[4]->getSunlight(x, y + Chunk::height, z) : 0;
|
||||
if(y >= Chunk::height) return m_surroundingChunks[5] ? m_surroundingChunks[5]->getSunlight(x, y - Chunk::height, z) : 0;
|
||||
if(z < 0) return m_surroundingChunks[2] ? m_surroundingChunks[2]->getSunlight(x, y, z + Chunk::depth) : 0;
|
||||
if(z >= Chunk::depth) return m_surroundingChunks[3] ? m_surroundingChunks[3]->getSunlight(x, y, z - Chunk::depth) : 0;
|
||||
return (m_lightMap[x][y][z] >> 4) & 0xf;
|
||||
}
|
||||
|
||||
void Chunk::setSunlight(int x, int y, int z, int val) {
|
||||
if(x < 0) { if(m_surroundingChunks[0]) m_surroundingChunks[0]->setSunlight(x + Chunk::width, y, z, val); return; }
|
||||
if(x >= Chunk::width) { if(m_surroundingChunks[1]) m_surroundingChunks[1]->setSunlight(x - Chunk::width, y, z, val); return; }
|
||||
if(y < 0) { if(m_surroundingChunks[4]) m_surroundingChunks[4]->setSunlight(x, y + Chunk::height, z, val); return; }
|
||||
if(y >= Chunk::height) { if(m_surroundingChunks[5]) m_surroundingChunks[5]->setSunlight(x, y - Chunk::height, z, val); return; }
|
||||
if(z < 0) { if(m_surroundingChunks[2]) m_surroundingChunks[2]->setSunlight(x, y, z + Chunk::depth, val); return; }
|
||||
if(z >= Chunk::depth) { if(m_surroundingChunks[3]) m_surroundingChunks[3]->setSunlight(x, y, z - Chunk::depth, val); return; }
|
||||
m_lightMap[x][y][z] = (m_lightMap[x][y][z] & 0xf) | (val << 4);
|
||||
|
||||
m_isChanged = true;
|
||||
}
|
||||
|
||||
int Chunk::getTorchlight(int x, int y, int z) const {
|
||||
if(x < 0) return m_surroundingChunks[0] ? m_surroundingChunks[0]->getTorchlight(x + Chunk::width, y, z) : 0;
|
||||
if(x >= Chunk::width) return m_surroundingChunks[1] ? m_surroundingChunks[1]->getTorchlight(x - Chunk::width, y, z) : 0;
|
||||
if(y < 0) return m_surroundingChunks[4] ? m_surroundingChunks[4]->getTorchlight(x, y + Chunk::height, z) : 0;
|
||||
if(y >= Chunk::height) return m_surroundingChunks[5] ? m_surroundingChunks[5]->getTorchlight(x, y - Chunk::height, z) : 0;
|
||||
if(z < 0) return m_surroundingChunks[2] ? m_surroundingChunks[2]->getTorchlight(x, y, z + Chunk::depth) : 0;
|
||||
if(z >= Chunk::depth) return m_surroundingChunks[3] ? m_surroundingChunks[3]->getTorchlight(x, y, z - Chunk::depth) : 0;
|
||||
return m_lightMap[x][y][z] & 0xf;
|
||||
}
|
||||
|
||||
void Chunk::setTorchlight(int x, int y, int z, int val) {
|
||||
if(x < 0) { if(m_surroundingChunks[0]) m_surroundingChunks[0]->setTorchlight(x + Chunk::width, y, z, val); return; }
|
||||
if(x >= Chunk::width) { if(m_surroundingChunks[1]) m_surroundingChunks[1]->setTorchlight(x - Chunk::width, y, z, val); return; }
|
||||
if(y < 0) { if(m_surroundingChunks[4]) m_surroundingChunks[4]->setTorchlight(x, y + Chunk::height, z, val); return; }
|
||||
if(y >= Chunk::height) { if(m_surroundingChunks[5]) m_surroundingChunks[5]->setTorchlight(x, y - Chunk::height, z, val); return; }
|
||||
if(z < 0) { if(m_surroundingChunks[2]) m_surroundingChunks[2]->setTorchlight(x, y, z + Chunk::depth, val); return; }
|
||||
if(z >= Chunk::depth) { if(m_surroundingChunks[3]) m_surroundingChunks[3]->setTorchlight(x, y, z - Chunk::depth, val); return; }
|
||||
m_lightMap[x][y][z] = (m_lightMap[x][y][z] & 0xf0) | val;
|
||||
|
||||
m_isChanged = true;
|
||||
}
|
||||
|
||||
|
||||
void Chunk::draw(RenderTarget &target, RenderStates states) const {
|
||||
if(m_verticesCount == 0) return;
|
||||
|
||||
|
@ -72,7 +72,7 @@ std::size_t ChunkBuilder::buildChunk(const Chunk &chunk, const VertexBuffer &vbo
|
||||
};
|
||||
|
||||
for(u8 i = 0 ; i < 6 ; i++) {
|
||||
addFace(x, y, z, i, &block, surroundingBlocks[i]);
|
||||
addFace(x, y, z, i, chunk, &block, surroundingBlocks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -89,7 +89,7 @@ std::size_t ChunkBuilder::buildChunk(const Chunk &chunk, const VertexBuffer &vbo
|
||||
return verticesCount;
|
||||
}
|
||||
|
||||
void ChunkBuilder::addFace(u8 x, u8 y, u8 z, u8 i, const Block *block, const Block *surroundingBlock) {
|
||||
void ChunkBuilder::addFace(u8 x, u8 y, u8 z, u8 i, const Chunk &chunk, const Block *block, const Block *surroundingBlock) {
|
||||
// Skip hidden faces
|
||||
if(surroundingBlock && surroundingBlock->id()
|
||||
&& (surroundingBlock->isOpaque() || (block->id() == surroundingBlock->id() && block->id() != 4)))
|
||||
@ -141,6 +141,9 @@ void ChunkBuilder::addFace(u8 x, u8 y, u8 z, u8 i, const Block *block, const Blo
|
||||
vertex.texCoord[0] = faceTexCoords[j * 2];
|
||||
vertex.texCoord[1] = faceTexCoords[j * 2 + 1];
|
||||
|
||||
vertex.lightValue[0] = chunk.getSunlight(x, y, z);
|
||||
vertex.lightValue[1] = chunk.getTorchlight(x, y, z);
|
||||
|
||||
m_vertices.emplace_back(vertex);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user