]> git.localhorst.tv Git - blank.git/commitdiff
use light levels for shading of blocks
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Mon, 23 Mar 2015 19:49:20 +0000 (20:49 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Mon, 23 Mar 2015 19:49:20 +0000 (20:49 +0100)
13 files changed:
src/app.cpp
src/app.hpp
src/block.cpp
src/block.hpp
src/chunk.cpp
src/chunk.hpp
src/interface.cpp
src/model.cpp
src/model.hpp
src/shader.cpp
src/shader.hpp
src/world.cpp
src/world.hpp

index a6f81f1210ecb677e0043341792ab8a0f9dba8ae..6a87042cffe553f621939e944bd6d81c37b5a39c 100644 (file)
@@ -13,7 +13,8 @@ Application::Application(const Config &config)
 , window()
 , ctx(window.CreateContext())
 , init_glew()
 , window()
 , ctx(window.CreateContext())
 , init_glew()
-, program()
+, chunk_prog()
+, entity_prog()
 , cam()
 , world(config.world)
 , interface(config.interface, world)
 , cam()
 , world(config.world)
 , interface(config.interface, world)
@@ -134,12 +135,12 @@ void Application::Update(int dt) {
 void Application::Render() {
        GLContext::Clear();
 
 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();
 }
 
        window.Flip();
 }
index 23dcd0cef9cf7b3a21bf143f6204d5c836dc5641..e6226dc50454dff487aa8596460b68dcfdf0670a 100644 (file)
@@ -52,7 +52,8 @@ private:
        Window window;
        GLContext ctx;
        InitGLEW init_glew;
        Window window;
        GLContext ctx;
        InitGLEW init_glew;
-       DirectionalLighting program;
+       BlockLighting chunk_prog;
+       DirectionalLighting entity_prog;
 
        Camera cam;
        World world;
 
        Camera cam;
        World world;
index 5fc3cc0ba4369cb651da7a8884649f387d247581..6e6ac18533d7cf10173a121b4f79839b4e8c3d21 100644 (file)
@@ -102,6 +102,15 @@ void BlockType::FillModel(
        buf.colors.insert(buf.colors.end(), shape->VertexCount(), color);
 }
 
        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,
 void BlockType::FillOutlineModel(
        OutlineModel &model,
        const glm::vec3 &pos_offset,
index 0d7d75a5dc8e68460f2413354763e3fbef2e4abf..56f9eace671193c3a9376a0912a9e7b822893b12 100644 (file)
@@ -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;
                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 },
        void FillOutlineModel(
                OutlineModel &m,
                const glm::vec3 &pos_offset = { 0, 0, 0 },
index de30ae91a58d5e5bb092f6ed58b5831b0996bad4..994d68e41bf4e930d4d55df86379381685e4f4c3 100644 (file)
@@ -131,16 +131,12 @@ struct SetNode {
        void Set(int level) { chunk->SetLight(pos, level); }
 
        bool HasNext(Block::Face face) {
        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) {
        }
        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()) { }
 
        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)); }
 
 };
        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) {
 
 
 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];
 }
 
 }
 
 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);
 
 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 {
 
 
 namespace {
 
-Model::Buffer buf;
+BlockModel::Buffer buf;
 
 }
 
 
 }
 
@@ -375,14 +414,19 @@ void Chunk::Update() {
        buf.Clear();
        buf.Reserve(vtx_count, idx_count);
 
        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;
 
        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();
                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);
        }
 
        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 &reg, const Generator &gen)
 : base(0, 0, 0)
 , reg(reg)
 ChunkLoader::ChunkLoader(const Config &config, const BlockTypeRegistry &reg, 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);
 
                                } 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) {
                                //      orientation testing
                                //      for (int i = 0; i < Block::FACE_COUNT; ++i) {
                                //              for (int j = 0; j < Block::TURN_COUNT; ++j) {
index 840bac0f3caf312574ebb888998f5aeae29ea4ea..0b1e5bdec20f79f65971e23234a5d77e04cd2dfd 100644 (file)
@@ -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)); }
 
        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,
        bool Intersection(
                const Ray &ray,
                const glm::mat4 &M,
@@ -146,13 +148,30 @@ private:
        Chunk *neighbor[Block::FACE_COUNT];
        std::vector<Block> blocks;
        std::vector<unsigned char> light;
        Chunk *neighbor[Block::FACE_COUNT];
        std::vector<Block> blocks;
        std::vector<unsigned char> light;
-       Model model;
+       BlockModel model;
        Pos position;
        bool dirty;
 
 };
 
 
        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 {
 class Generator;
 
 class ChunkLoader {
index dddb7324f965fc7fe2a4f90810837b7e3e6598c2..45439da0e9a1de63c497063f192a6109c60434b9 100644 (file)
@@ -124,24 +124,24 @@ void Interface::PrintChunkInfo() {
                << aim_chunk->Position()
                << std::endl;
 
                << aim_chunk->Position()
                << std::endl;
 
-       std::cout << "  neighbors:";
+       std::cout << "  neighbors:" << std::endl;
        if (aim_chunk->HasNeighbor(Block::FACE_LEFT)) {
        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)) {
        }
        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)) {
        }
        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)) {
        }
        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)) {
        }
        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)) {
        }
        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;
 }
        }
        std::cout << std::endl;
 }
index d26968a0e6282e51cdcb9dda431eb90a751d4c33..125d57aefcd16d7f7e7291229bf999879610d5d4 100644 (file)
@@ -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()
 OutlineModel::OutlineModel()
 : vertices()
 , colors()
index d5c77d174929756f2ace1445e887946b017dfe20..7b9fc3d1b09cf702109111ae51568e694f45736a 100644 (file)
@@ -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<Position>;
+       using Colors = std::vector<Color>;
+       using Normals = std::vector<Normal>;
+       using Lights = std::vector<Light>;
+       using Indices = std::vector<Index>;
+
+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:
 class OutlineModel {
 
 public:
index eb09b10bcf2e0e1933e980e41610829452e9bc3a..134f710c9684b2c690a3b71b58219872a02d419f 100644 (file)
@@ -253,4 +253,108 @@ void DirectionalLighting::SetMVP(const glm::mat4 &m, const glm::mat4 &v, const g
        SetM(m);
 }
 
        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);
+}
+
 }
 }
index f42d19b396b1d8187302eea77c6fe9b4a1401dc2..873460bf17644947ee61f3e87e8f5be82ccad2d8 100644 (file)
@@ -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
 }
 
 #endif
index 756c66fdff87718ff724ee0263006eac7b4b9f4a..137fd2a6cf29abcc9cfd2fca2fc950c75f94aa81 100644 (file)
@@ -99,7 +99,7 @@ World::World(const Config &config)
 
        { // glowing yellow block
                BlockType type(true, { 1.0f, 1.0f, 0.0f }, &blockShape);
 
        { // 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);
                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()));
 
        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();
                }
        }
 
                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()) {
        for (Entity &entity : entities) {
                if (entity.HasShape()) {
-                       program.SetM(entity.Transform(player->ChunkCoords()));
+                       entity_prog.SetM(entity.Transform(player->ChunkCoords()));
                        entity.Draw();
                }
        }
                        entity.Draw();
                }
        }
index 3dd04fb31add2b0a8738328c824f54884875b21a..1d43fbe7ffce45e2929ea659ea48293be33daa33 100644 (file)
@@ -52,7 +52,7 @@ public:
 
        void Update(int dt);
 
 
        void Update(int dt);
 
-       void Render(DirectionalLighting &);
+       void Render(BlockLighting &, DirectionalLighting &);
 
 private:
        BlockTypeRegistry blockType;
 
 private:
        BlockTypeRegistry blockType;