From: Daniel Karbach Date: Mon, 23 Mar 2015 19:49:20 +0000 (+0100) Subject: use light levels for shading of blocks X-Git-Url: http://git.localhorst.tv/?a=commitdiff_plain;ds=sidebyside;h=e74f1ad236429f05db90c0ace825277e2a3fbc05;p=blank.git use light levels for shading of blocks --- diff --git a/src/app.cpp b/src/app.cpp index a6f81f1..6a87042 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -13,7 +13,8 @@ Application::Application(const Config &config) , window() , ctx(window.CreateContext()) , init_glew() -, program() +, chunk_prog() +, entity_prog() , cam() , world(config.world) , interface(config.interface, world) @@ -134,12 +135,12 @@ void Application::Update(int dt) { void Application::Render() { GLContext::Clear(); - program.Activate(); + chunk_prog.SetProjection(cam.Projection()); + entity_prog.SetProjection(cam.Projection()); - program.SetProjection(cam.Projection()); - world.Render(program); + world.Render(chunk_prog, entity_prog); - interface.Render(program); + interface.Render(entity_prog); window.Flip(); } diff --git a/src/app.hpp b/src/app.hpp index 23dcd0c..e6226dc 100644 --- a/src/app.hpp +++ b/src/app.hpp @@ -52,7 +52,8 @@ private: Window window; GLContext ctx; InitGLEW init_glew; - DirectionalLighting program; + BlockLighting chunk_prog; + DirectionalLighting entity_prog; Camera cam; World world; diff --git a/src/block.cpp b/src/block.cpp index 5fc3cc0..6e6ac18 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -102,6 +102,15 @@ void BlockType::FillModel( buf.colors.insert(buf.colors.end(), shape->VertexCount(), color); } +void BlockType::FillBlockModel( + BlockModel::Buffer &buf, + const glm::mat4 &transform, + BlockModel::Index idx_offset +) const { + shape->Vertices(buf.vertices, buf.normals, buf.indices, transform, idx_offset); + buf.colors.insert(buf.colors.end(), shape->VertexCount(), color); +} + void BlockType::FillOutlineModel( OutlineModel &model, const glm::vec3 &pos_offset, diff --git a/src/block.hpp b/src/block.hpp index 0d7d75a..56f9eac 100644 --- a/src/block.hpp +++ b/src/block.hpp @@ -66,6 +66,23 @@ struct Block { } } + static Face NormalFace(const glm::vec3 &norm) { + const glm::vec3 anorm(abs(norm)); + if (anorm.x > anorm.y) { + if (anorm.x > anorm.z) { + return norm.x > 0.0f ? FACE_RIGHT : FACE_LEFT; + } else { + return norm.z > 0.0f ? FACE_FRONT : FACE_BACK; + } + } else { + if (anorm.y > anorm.z) { + return norm.y > 0.0f ? FACE_UP : FACE_DOWN; + } else { + return norm.z > 0.0f ? FACE_FRONT : FACE_BACK; + } + } + } + }; @@ -111,6 +128,11 @@ struct BlockType { const glm::mat4 &transform = glm::mat4(1.0f), Model::Index idx_offset = 0 ) const; + void FillBlockModel( + BlockModel::Buffer &m, + const glm::mat4 &transform = glm::mat4(1.0f), + BlockModel::Index idx_offset = 0 + ) const; void FillOutlineModel( OutlineModel &m, const glm::vec3 &pos_offset = { 0, 0, 0 }, diff --git a/src/chunk.cpp b/src/chunk.cpp index de30ae9..994d68e 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -131,16 +131,12 @@ struct SetNode { void Set(int level) { chunk->SetLight(pos, level); } bool HasNext(Block::Face face) { - const Block *next = chunk->FindNext(pos, face); - return next && !chunk->Type(*next).block_light; + const BlockLookup next(chunk, pos, face); + return next.result && !next.chunk->Type(*next.result).block_light; } SetNode GetNext(Block::Face face) { - Chunk::Pos next_pos(pos + Block::FaceNormal(face)); - if (Chunk::InBounds(next_pos)) { - return SetNode(chunk, next_pos); - } else { - return SetNode(&chunk->GetNeighbor(face), next_pos - (Block::FaceNormal(face) * Chunk::Extent())); - } + const BlockLookup next(chunk, pos, face); + return SetNode(next.chunk, next.pos); } }; @@ -156,6 +152,11 @@ struct UnsetNode UnsetNode(const SetNode &set) : SetNode(set), level(Get()) { } + + bool HasNext(Block::Face face) { + const BlockLookup next(chunk, pos, face); + return next.result; + } UnsetNode GetNext(Block::Face face) { return UnsetNode(SetNode::GetNext(face)); } }; @@ -269,13 +270,51 @@ const Block *Chunk::FindNext(const Pos &pos, Block::Face face) const { void Chunk::SetLight(int index, int level) { - light[index] = level; + if (light[index] != level) { + light[index] = level; + Invalidate(); + } } int Chunk::GetLight(int index) const { return light[index]; } +float Chunk::GetVertexLight(int index, const BlockModel::Position &vtx, const BlockModel::Normal &norm) const { + float light = GetLight(index); + Chunk::Pos pos(ToPos(index)); + + Block::Face direct_face(Block::NormalFace(norm)); + const Chunk *direct_chunk = this; + Chunk::Pos direct_pos(pos + Block::FaceNormal(direct_face)); + if (!InBounds(direct_pos)) { + if (HasNeighbor(direct_face)) { + direct_chunk = &GetNeighbor(direct_face); + direct_pos -= (Block::FaceNormal(direct_face) * Extent()); + float direct_light = direct_chunk->GetLight(direct_pos); + if (direct_light > light) { + light = direct_light; + } + } + } else { + float direct_light = direct_chunk->GetLight(direct_pos); + if (direct_light > light) { + light = direct_light; + } + } + + // cheap alternative until AO etc are implemented + // to tell the faces apart + + if (direct_face == Block::FACE_LEFT || direct_face == Block::FACE_RIGHT) { + light -= 0.2; + } else if (direct_face == Block::FACE_FRONT || direct_face == Block::FACE_BACK) { + light -= 0.4; + } + + return light; +} + bool Chunk::IsSurface(const Pos &pos) const { const Block &block = BlockAt(pos); @@ -355,7 +394,7 @@ glm::mat4 Chunk::Transform(const Pos &offset) const { namespace { -Model::Buffer buf; +BlockModel::Buffer buf; } @@ -375,14 +414,19 @@ void Chunk::Update() { buf.Clear(); buf.Reserve(vtx_count, idx_count); - Model::Index vtx_counter = 0; + BlockModel::Index vtx_counter = 0; for (size_t i = 0; i < Size(); ++i) { const BlockType &type = Type(blocks[i]); if (!type.visible || Obstructed(i)) continue; - type.FillModel(buf, ToTransform(i), vtx_counter); + type.FillBlockModel(buf, ToTransform(i), vtx_counter); + size_t vtx_begin = vtx_counter; vtx_counter += type.shape->VertexCount(); + + for (size_t vtx = vtx_begin; vtx < vtx_counter; ++vtx) { + buf.lights.emplace_back(GetVertexLight(i, buf.vertices[vtx], buf.normals[vtx])); + } } model.Update(buf); @@ -484,6 +528,74 @@ glm::mat4 Chunk::ToTransform(int idx) const { } +BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p) +: chunk(c), pos(p), result(nullptr) { + while (pos.x >= Chunk::Width()) { + if (chunk->HasNeighbor(Block::FACE_RIGHT)) { + chunk = &chunk->GetNeighbor(Block::FACE_RIGHT); + pos.x -= Chunk::Width(); + } else { + return; + } + } + while (pos.x < 0) { + if (chunk->HasNeighbor(Block::FACE_LEFT)) { + chunk = &chunk->GetNeighbor(Block::FACE_LEFT); + pos.x += Chunk::Width(); + } else { + return; + } + } + while (pos.y >= Chunk::Height()) { + if (chunk->HasNeighbor(Block::FACE_UP)) { + chunk = &chunk->GetNeighbor(Block::FACE_UP); + pos.y -= Chunk::Height(); + } else { + return; + } + } + while (pos.y < 0) { + if (chunk->HasNeighbor(Block::FACE_DOWN)) { + chunk = &chunk->GetNeighbor(Block::FACE_DOWN); + pos.y += Chunk::Height(); + } else { + return; + } + } + while (pos.z >= Chunk::Depth()) { + if (chunk->HasNeighbor(Block::FACE_FRONT)) { + chunk = &chunk->GetNeighbor(Block::FACE_FRONT); + pos.z -= Chunk::Depth(); + } else { + return; + } + } + while (pos.z < 0) { + if (chunk->HasNeighbor(Block::FACE_BACK)) { + chunk = &chunk->GetNeighbor(Block::FACE_BACK); + pos.z += Chunk::Depth(); + } else { + return; + } + } + result = &chunk->BlockAt(pos); +} + +BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p, Block::Face face) +: chunk(c), pos(p), result(nullptr) { + pos += Block::FaceNormal(face); + if (Chunk::InBounds(pos)) { + result = &chunk->BlockAt(pos); + } else { + pos -= Block::FaceNormal(face) * Chunk::Extent(); + if (chunk->HasNeighbor(face)) { + chunk = &chunk->GetNeighbor(face); + result = &chunk->BlockAt(pos); + } + } +} + + ChunkLoader::ChunkLoader(const Config &config, const BlockTypeRegistry ®, const Generator &gen) : base(0, 0, 0) , reg(reg) @@ -527,6 +639,42 @@ void ChunkLoader::Generate(const Chunk::Pos &from, const Chunk::Pos &to) { } else if (pos == base) { Generate(pos); + // light testing + // for (int i = 0; i < 16; ++i) { + // for (int j = 0; j < 16; ++j) { + // loaded.back().SetBlock(Chunk::Pos{ i, j, 0 }, Block(1)); + // loaded.back().SetBlock(Chunk::Pos{ i, j, 15 }, Block(1)); + // loaded.back().SetBlock(Chunk::Pos{ 0, j, i }, Block(1)); + // loaded.back().SetBlock(Chunk::Pos{ 15, j, i }, Block(1)); + // } + // } + // loaded.back().SetBlock(Chunk::Pos{ 1, 0, 1 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 14, 0, 1 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 1, 0, 14 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 14, 0, 14 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 1, 15, 1 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 14, 15, 1 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 1, 15, 14 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 14, 15, 14 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 7, 7, 0 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 8, 7, 0 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 7, 8, 0 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 8, 8, 0 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 7, 7, 15 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 8, 7, 15 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 7, 8, 15 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 8, 8, 15 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 0, 7, 7 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 0, 7, 8 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 0, 8, 7 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 0, 8, 8 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 15, 7, 7 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 15, 7, 8 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 15, 8, 7 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 15, 8, 8 }, Block(13)); + // loaded.back().Invalidate(); + // loaded.back().CheckUpdate(); + // orientation testing // for (int i = 0; i < Block::FACE_COUNT; ++i) { // for (int j = 0; j < Block::TURN_COUNT; ++j) { diff --git a/src/chunk.hpp b/src/chunk.hpp index 840bac0..0b1e5bd 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -116,6 +116,8 @@ public: int GetLight(const Pos &pos) const { return GetLight(ToIndex(pos)); } int GetLight(const Block::Pos &pos) const { return GetLight(ToIndex(pos)); } + float GetVertexLight(int index, const BlockModel::Position &, const BlockModel::Normal &) const; + bool Intersection( const Ray &ray, const glm::mat4 &M, @@ -146,13 +148,30 @@ private: Chunk *neighbor[Block::FACE_COUNT]; std::vector blocks; std::vector light; - Model model; + BlockModel model; Pos position; bool dirty; }; +struct BlockLookup { + + Chunk *chunk; + Chunk::Pos pos; + const Block *result; + + // resolve chunk/position/block from oob coordinates + // result will be nullptr if unsuccessful + BlockLookup(Chunk *c, const Chunk::Pos &p); + + // resolve chunk/position/block from ib coordinates and direction + // result will be nullptr if unsuccessful + BlockLookup(Chunk *c, const Chunk::Pos &p, Block::Face dir); + +}; + + class Generator; class ChunkLoader { diff --git a/src/interface.cpp b/src/interface.cpp index dddb732..45439da 100644 --- a/src/interface.cpp +++ b/src/interface.cpp @@ -124,24 +124,24 @@ void Interface::PrintChunkInfo() { << aim_chunk->Position() << std::endl; - std::cout << " neighbors:"; + std::cout << " neighbors:" << std::endl; if (aim_chunk->HasNeighbor(Block::FACE_LEFT)) { - std::cout << " left"; + std::cout << " left " << aim_chunk->GetNeighbor(Block::FACE_LEFT).Position() << std::endl; } if (aim_chunk->HasNeighbor(Block::FACE_RIGHT)) { - std::cout << " right"; + std::cout << " right " << aim_chunk->GetNeighbor(Block::FACE_RIGHT).Position() << std::endl; } if (aim_chunk->HasNeighbor(Block::FACE_UP)) { - std::cout << " up"; + std::cout << " up " << aim_chunk->GetNeighbor(Block::FACE_UP).Position() << std::endl; } if (aim_chunk->HasNeighbor(Block::FACE_DOWN)) { - std::cout << " down"; + std::cout << " down " << aim_chunk->GetNeighbor(Block::FACE_DOWN).Position() << std::endl; } if (aim_chunk->HasNeighbor(Block::FACE_FRONT)) { - std::cout << " front"; + std::cout << " front " << aim_chunk->GetNeighbor(Block::FACE_FRONT).Position() << std::endl; } if (aim_chunk->HasNeighbor(Block::FACE_BACK)) { - std::cout << " back"; + std::cout << " back " << aim_chunk->GetNeighbor(Block::FACE_BACK).Position() << std::endl; } std::cout << std::endl; } diff --git a/src/model.cpp b/src/model.cpp index d26968a..125d57a 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -103,6 +103,120 @@ void Model::Draw() const { } +BlockModel::BlockModel() +: va(0) +, handle{} +, count(0) { + glGenVertexArrays(1, &va); + glGenBuffers(ATTRIB_COUNT, handle); +} + +BlockModel::~BlockModel() { + glDeleteBuffers(ATTRIB_COUNT, handle); + glDeleteVertexArrays(1, &va); +} + +BlockModel::BlockModel(BlockModel &&other) +: va(other.va) +, count(other.count) { + other.va = 0; + for (int i = 0; i < ATTRIB_COUNT; ++i) { + handle[i] = other.handle[i]; + other.handle[i] = 0; + } +} + +BlockModel &BlockModel::operator =(BlockModel &&other) { + std::swap(va, other.va); + for (int i = 0; i < ATTRIB_COUNT; ++i) { + std::swap(handle[i], other.handle[i]); + } + count = other.count; + return *this; +} + +void BlockModel::Update(const Buffer &buf) { + glBindVertexArray(va); + glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_VERTEX]); + glBufferData(GL_ARRAY_BUFFER, buf.vertices.size() * sizeof(glm::vec3), buf.vertices.data(), GL_STATIC_DRAW); + glEnableVertexAttribArray(ATTRIB_VERTEX); + glVertexAttribPointer( + ATTRIB_VERTEX, // location (for shader) + 3, // size + GL_FLOAT, // type + GL_FALSE, // normalized + 0, // stride + nullptr // offset + ); + +#ifndef NDEBUG + if (buf.colors.size() < buf.vertices.size()) { + std::cerr << "BlockModel: not enough colors!" << std::endl; + } +#endif + glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_COLOR]); + glBufferData(GL_ARRAY_BUFFER, buf.colors.size() * sizeof(glm::vec3), buf.colors.data(), GL_STATIC_DRAW); + glEnableVertexAttribArray(ATTRIB_COLOR); + glVertexAttribPointer( + ATTRIB_COLOR, // location (for shader) + 3, // size + GL_FLOAT, // type + GL_FALSE, // normalized + 0, // stride + nullptr // offset + ); + +#ifndef NDEBUG + if (buf.normals.size() < buf.vertices.size()) { + std::cerr << "BlockModel: not enough normals!" << std::endl; + } +#endif + glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_NORMAL]); + glBufferData(GL_ARRAY_BUFFER, buf.normals.size() * sizeof(glm::vec3), buf.normals.data(), GL_STATIC_DRAW); + glEnableVertexAttribArray(ATTRIB_NORMAL); + glVertexAttribPointer( + ATTRIB_NORMAL, // location (for shader) + 3, // size + GL_FLOAT, // type + GL_FALSE, // normalized + 0, // stride + nullptr // offset + ); + +#ifndef NDEBUG + if (buf.lights.size() < buf.vertices.size()) { + std::cerr << "BlockModel: not enough lights!" << std::endl; + } +#endif + glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_LIGHT]); + glBufferData(GL_ARRAY_BUFFER, buf.lights.size() * sizeof(float), buf.lights.data(), GL_STATIC_DRAW); + glEnableVertexAttribArray(ATTRIB_LIGHT); + glVertexAttribPointer( + ATTRIB_LIGHT, // location (for shader) + 1, // size + GL_FLOAT, // type + GL_FALSE, // normalized + 0, // stride + nullptr // offset + ); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle[ATTRIB_INDEX]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, buf.indices.size() * sizeof(Index), buf.indices.data(), GL_STATIC_DRAW); + count = buf.indices.size(); +} + + +void BlockModel::Draw() const { + glBindVertexArray(va); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle[ATTRIB_INDEX]); + glDrawElements( + GL_TRIANGLES, // how + count, // count + GL_UNSIGNED_INT, // type + nullptr // offset + ); +} + OutlineModel::OutlineModel() : vertices() , colors() diff --git a/src/model.hpp b/src/model.hpp index d5c77d1..7b9fc3d 100644 --- a/src/model.hpp +++ b/src/model.hpp @@ -75,6 +75,79 @@ private: }; +class BlockModel { + +public: + using Position = glm::vec3; + using Color = glm::vec3; + using Normal = glm::vec3; + using Light = float; + using Index = unsigned int; + + using Positions = std::vector; + using Colors = std::vector; + using Normals = std::vector; + using Lights = std::vector; + using Indices = std::vector; + +public: + struct Buffer { + + Positions vertices; + Colors colors; + Normals normals; + Lights lights; + Indices indices; + + void Clear() { + vertices.clear(); + colors.clear(); + normals.clear(); + lights.clear(); + indices.clear(); + } + + void Reserve(size_t p, size_t i) { + vertices.reserve(p); + colors.reserve(p); + normals.reserve(p); + lights.reserve(p); + indices.reserve(i); + } + + }; + +public: + BlockModel(); + ~BlockModel(); + + BlockModel(const BlockModel &) = delete; + BlockModel &operator =(const Model &) = delete; + + BlockModel(BlockModel &&); + BlockModel &operator =(BlockModel &&); + + void Update(const Buffer &); + + void Draw() const; + +private: + enum Attribute { + ATTRIB_VERTEX, + ATTRIB_COLOR, + ATTRIB_NORMAL, + ATTRIB_LIGHT, + ATTRIB_INDEX, + ATTRIB_COUNT, + }; + + GLuint va; + GLuint handle[ATTRIB_COUNT]; + size_t count; + +}; + + class OutlineModel { public: diff --git a/src/shader.cpp b/src/shader.cpp index eb09b10..134f710 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -253,4 +253,108 @@ void DirectionalLighting::SetMVP(const glm::mat4 &m, const glm::mat4 &v, const g SetM(m); } + +BlockLighting::BlockLighting() +: program() +, vp(1.0f) +, m_handle(0) +, mv_handle(0) +, mvp_handle(0) +, fog_density_handle(0) { + program.LoadShader( + GL_VERTEX_SHADER, + "#version 330 core\n" + "layout(location = 0) in vec3 vtx_position;\n" + "layout(location = 1) in vec3 vtx_color;\n" + "layout(location = 2) in vec3 vtx_normal;\n" + "layout(location = 3) in float vtx_light;\n" + "uniform mat4 M;\n" + "uniform mat4 MV;\n" + "uniform mat4 MVP;\n" + "out vec3 frag_color;\n" + "out vec3 vtx_viewspace;\n" + "out vec3 normal;\n" + "out float frag_light;\n" + "void main() {\n" + "gl_Position = MVP * vec4(vtx_position, 1);\n" + "frag_color = vtx_color;\n" + "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n" + "normal = (M * vec4(vtx_normal, 0)).xyz;\n" + "frag_light = vtx_light;\n" + "}\n" + ); + program.LoadShader( + GL_FRAGMENT_SHADER, + "#version 330 core\n" + "in vec3 frag_color;\n" + "in vec3 vtx_viewspace;\n" + "in float frag_light;\n" + "uniform float fog_density;\n" + "out vec3 color;\n" + "void main() {\n" + "vec3 ambient = vec3(0.1, 0.1, 0.1) * frag_color;\n" + "float light_power = clamp(pow(0.8, 15 - frag_light), 0, 1);\n" + //"float light_power = clamp(frag_light / 15, 0, 1);\n" + // this should be the same as the clear color, otherwise looks really weird + "vec3 fog_color = vec3(0, 0, 0);\n" + "float e = 2.718281828;\n" + //"vec3 reflect_color = ambient + frag_color * light_power;\n" + "vec3 reflect_color = frag_color * light_power;\n" + "float value = pow(e, -pow(fog_density * length(vtx_viewspace), 5));" + "color = mix(fog_color, reflect_color, value);\n" + "}\n" + ); + program.Link(); + if (!program.Linked()) { + program.Log(std::cerr); + throw std::runtime_error("link program"); + } + + m_handle = program.UniformLocation("M"); + mv_handle = program.UniformLocation("MV"); + mvp_handle = program.UniformLocation("MVP"); + fog_density_handle = program.UniformLocation("fog_density"); +} + + +void BlockLighting::Activate() { + GLContext::EnableDepthTest(); + GLContext::EnableBackfaceCulling(); + program.Use(); +} + +void BlockLighting::SetM(const glm::mat4 &m) { + glm::mat4 mv(view * m); + glm::mat4 mvp(vp * m); + glUniformMatrix4fv(m_handle, 1, GL_FALSE, &m[0][0]); + glUniformMatrix4fv(mv_handle, 1, GL_FALSE, &mv[0][0]); + glUniformMatrix4fv(mvp_handle, 1, GL_FALSE, &mvp[0][0]); +} + +void BlockLighting::SetFogDensity(float f) { + fog_density = f; + glUniform1f(fog_density_handle, fog_density); +} + +void BlockLighting::SetProjection(const glm::mat4 &p) { + projection = p; + vp = p * view; +} + +void BlockLighting::SetView(const glm::mat4 &v) { + view = v; + vp = projection * v; +} + +void BlockLighting::SetVP(const glm::mat4 &v, const glm::mat4 &p) { + projection = p; + view = v; + vp = p * v; +} + +void BlockLighting::SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) { + SetVP(v, p); + SetM(m); +} + } diff --git a/src/shader.hpp b/src/shader.hpp index f42d19b..873460b 100644 --- a/src/shader.hpp +++ b/src/shader.hpp @@ -102,6 +102,43 @@ private: }; +class BlockLighting { + +public: + BlockLighting(); + + void Activate(); + + void SetFogDensity(float); + + void SetM(const glm::mat4 &m); + void SetProjection(const glm::mat4 &p); + void SetView(const glm::mat4 &v); + void SetVP(const glm::mat4 &v, const glm::mat4 &p); + void SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p); + + const glm::mat4 &Projection() const { return projection; } + const glm::mat4 &View() const { return view; } + const glm::mat4 &GetVP() const { return vp; } + +private: + Program program; + + float fog_density; + + glm::mat4 projection; + glm::mat4 view; + glm::mat4 vp; + + GLuint m_handle; + GLuint mv_handle; + GLuint mvp_handle; + GLuint light_direction_handle; + GLuint light_color_handle; + GLuint fog_density_handle; + +}; + } #endif diff --git a/src/world.cpp b/src/world.cpp index 756c66f..137fd2a 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -99,7 +99,7 @@ World::World(const Config &config) { // glowing yellow block BlockType type(true, { 1.0f, 1.0f, 0.0f }, &blockShape); - type.luminosity = 10; + type.luminosity = 15; type.block_light = true; type.fill = block_fill; blockType.Add(type); @@ -200,23 +200,28 @@ void World::Update(int dt) { } -void World::Render(DirectionalLighting &program) { - program.SetLightDirection(light_direction); - program.SetFogDensity(fog_density); - program.SetView(glm::inverse(player->Transform(player->ChunkCoords()))); +void World::Render(BlockLighting &chunk_prog, DirectionalLighting &entity_prog) { + chunk_prog.Activate(); + chunk_prog.SetFogDensity(fog_density); + chunk_prog.SetView(glm::inverse(player->Transform(player->ChunkCoords()))); for (Chunk &chunk : chunks.Loaded()) { glm::mat4 m(chunk.Transform(player->ChunkCoords())); - program.SetM(m); - glm::mat4 mvp(program.GetVP() * m); + chunk_prog.SetM(m); + glm::mat4 mvp(chunk_prog.GetVP() * m); if (!CullTest(Chunk::Bounds(), mvp)) { chunk.Draw(); } } + entity_prog.Activate(); + entity_prog.SetLightDirection(light_direction); + entity_prog.SetFogDensity(fog_density); + entity_prog.SetView(glm::inverse(player->Transform(player->ChunkCoords()))); + for (Entity &entity : entities) { if (entity.HasShape()) { - program.SetM(entity.Transform(player->ChunkCoords())); + entity_prog.SetM(entity.Transform(player->ChunkCoords())); entity.Draw(); } } diff --git a/src/world.hpp b/src/world.hpp index 3dd04fb..1d43fbe 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -52,7 +52,7 @@ public: void Update(int dt); - void Render(DirectionalLighting &); + void Render(BlockLighting &, DirectionalLighting &); private: BlockTypeRegistry blockType;