From: Daniel Karbach Date: Tue, 3 Mar 2015 17:42:16 +0000 (+0100) Subject: world class for multiple chunks X-Git-Url: http://git.localhorst.tv/?a=commitdiff_plain;h=5700ea3c08ea5e4a5c743f0413b65dc8eebfd220;p=blank.git world class for multiple chunks --- diff --git a/src/app.cpp b/src/app.cpp index 9ec9384..56b12dd 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -19,9 +19,8 @@ Application::Application() , move_velocity(0.003f) , pitch_sensitivity(-0.0025f) , yaw_sensitivity(-0.001f) -, blockType() , cam() -, chunk() +, world() , outline() , outline_visible(false) , outline_transform(1.0f) @@ -58,6 +57,7 @@ Application::Application() "layout(location = 2) in vec3 vtx_normal;\n" "uniform mat4 M;\n" "uniform mat4 V;\n" + "uniform mat4 MV;\n" "uniform mat4 MVP;\n" "uniform vec3 light_position;\n" "out vec3 frag_color;\n" @@ -69,11 +69,11 @@ Application::Application() "vec4 v = vec4(vtx_position, 1);\n" "gl_Position = MVP * v;\n" "vtx_world = (M * v).xyz;\n" - "vec3 vtx_camera = (V * M * v).xyz;\n" + "vec3 vtx_camera = (MV * v).xyz;\n" "eye = vec3(0, 0, 0) - vtx_camera;\n" "vec3 light_camera = (V * v).xyz;\n" "light_direction = light_position + eye;\n" - "normal = (V * M * vec4(vtx_normal, 0)).xyz;\n" + "normal = (MV * vec4(vtx_normal, 0)).xyz;\n" "frag_color = vtx_color;\n" "}\n" ); @@ -117,28 +117,7 @@ Application::Application() cam.Position(glm::vec3(0, 4, 4)); - blockType.Add(BlockType(true, glm::vec3(1, 1, 1))); - blockType.Add(BlockType(true, glm::vec3(1, 0, 0))); - blockType.Add(BlockType(true, glm::vec3(0, 1, 0))); - blockType.Add(BlockType(true, glm::vec3(0, 0, 1))); - - chunk.BlockAt(glm::vec3(0, 0, 0)) = Block(blockType[4]); - chunk.BlockAt(glm::vec3(0, 0, 1)) = Block(blockType[1]); - chunk.BlockAt(glm::vec3(1, 0, 0)) = Block(blockType[2]); - chunk.BlockAt(glm::vec3(1, 0, 1)) = Block(blockType[3]); - chunk.BlockAt(glm::vec3(2, 0, 0)) = Block(blockType[4]); - chunk.BlockAt(glm::vec3(2, 0, 1)) = Block(blockType[1]); - chunk.BlockAt(glm::vec3(3, 0, 0)) = Block(blockType[2]); - chunk.BlockAt(glm::vec3(3, 0, 1)) = Block(blockType[3]); - chunk.BlockAt(glm::vec3(2, 0, 2)) = Block(blockType[4]); - chunk.BlockAt(glm::vec3(2, 0, 3)) = Block(blockType[1]); - chunk.BlockAt(glm::vec3(3, 0, 2)) = Block(blockType[2]); - chunk.BlockAt(glm::vec3(3, 0, 3)) = Block(blockType[3]); - chunk.BlockAt(glm::vec3(1, 1, 0)) = Block(blockType[1]); - chunk.BlockAt(glm::vec3(1, 1, 1)) = Block(blockType[4]); - chunk.BlockAt(glm::vec3(2, 1, 1)) = Block(blockType[3]); - chunk.BlockAt(glm::vec3(2, 2, 1)) = Block(blockType[2]); - chunk.Invalidate(); + world.Generate(); outline.vertices = std::vector({ { 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, @@ -271,35 +250,41 @@ void Application::Update(int dt) { cam.Update(dt); Ray aim = cam.Aim(); + Chunk *chunk; int blkid; float dist; glm::vec3 normal; - if (chunk.Intersection(aim, glm::mat4(1.0f), &blkid, &dist, &normal)) { + if (world.Intersection(aim, glm::mat4(1.0f), &chunk, &blkid, &dist, &normal)) { glm::vec3 pos = Chunk::ToCoords(blkid); outline_visible = true; - outline_transform = glm::translate(glm::mat4(1.0f), pos); + outline_transform = glm::translate(chunk->Transform(), pos); } else { outline_visible = false; } if (pick) { - if (outline_visible) { - place_id = chunk.BlockAt(blkid).type->id; + if (chunk) { + place_id = chunk->BlockAt(blkid).type->id; } pick = false; } if (remove) { - chunk.BlockAt(blkid).type = blockType[remove_id]; - chunk.Invalidate(); + if (chunk) { + chunk->BlockAt(blkid).type = world.BlockTypes()[remove_id]; + chunk->Invalidate(); + } remove = false; } if (place) { - if (outline_visible) { - int next_blkid = Chunk::ToIndex(Chunk::ToCoords(blkid) + normal); - if (next_blkid >= 0 && next_blkid < Chunk::Size()) { - chunk.BlockAt(next_blkid).type = blockType[place_id]; - chunk.Invalidate(); + if (chunk) { + Chunk *mod_chunk = chunk; + glm::vec3 next_pos = Chunk::ToCoords(blkid) + normal; + if (!Chunk::InBounds(next_pos)) { + mod_chunk = &world.Next(*chunk, normal); + next_pos -= normal * Chunk::Extent(); } + mod_chunk->BlockAt(next_pos).type = world.BlockTypes()[place_id]; + mod_chunk->Invalidate(); } place = false; } @@ -310,21 +295,25 @@ void Application::Render() { program.Use(); - glm::mat4 m(1.0f); - glm::mat4 mv(cam.View() * m); - glm::mat4 mvp(cam.MakeMVP(m)); - glUniformMatrix4fv(m_handle, 1, GL_FALSE, &m[0][0]); glUniformMatrix4fv(v_handle, 1, GL_FALSE, &cam.View()[0][0]); - glUniformMatrix4fv(mv_handle, 1, GL_FALSE, &mv[0][0]); - glUniformMatrix4fv(mvp_handle, 1, GL_FALSE, &mvp[0][0]); glUniform3f(light_position_handle, light_position.x, light_position.y, light_position.z); glUniform3f(light_color_handle, light_color.x, light_color.y, light_color.z); glUniform1f(light_power_handle, light_power); - chunk.Draw(); + for (Chunk &chunk : world.LoadedChunks()) { + glm::mat4 m(chunk.Transform()); + glm::mat4 mv(cam.View() * m); + glm::mat4 mvp(cam.MakeMVP(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]); + chunk.Draw(); + } + if (outline_visible) { - mv = cam.View() * outline_transform; - mvp = cam.MakeMVP(outline_transform); + glm::mat4 m(outline_transform); + glm::mat4 mv(cam.View() * outline_transform); + glm::mat4 mvp(cam.MakeMVP(outline_transform)); 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]); diff --git a/src/app.hpp b/src/app.hpp index 28c7536..1c3c69d 100644 --- a/src/app.hpp +++ b/src/app.hpp @@ -42,10 +42,8 @@ private: float pitch_sensitivity; float yaw_sensitivity; - BlockTypeRegistry blockType; - Camera cam; - Chunk chunk; + World world; OutlineModel outline; bool outline_visible; diff --git a/src/model.cpp b/src/model.cpp index b50ccf0..f6a4476 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -18,6 +18,28 @@ Model::~Model() { glDeleteBuffers(ATTRIB_COUNT, handle); } +Model::Model(Model &&other) +: vertices(std::move(other.vertices)) +, colors(std::move(other.colors)) +, normals(std::move(other.normals)) +, dirty(other.dirty) { + for (int i = 0; i < ATTRIB_COUNT; ++i) { + handle[i] = other.handle[i]; + other.handle[i] = 0; + } +} + +Model &Model::operator =(Model &&other) { + vertices = std::move(other.vertices); + colors = std::move(other.colors); + normals = std::move(other.normals); + for (int i = 0; i < ATTRIB_COUNT; ++i) { + std::swap(handle[i], other.handle[i]); + } + dirty = other.dirty; + return *this; +} + void Model::Clear() { vertices.clear(); diff --git a/src/model.hpp b/src/model.hpp index 4fd4515..4423cd7 100644 --- a/src/model.hpp +++ b/src/model.hpp @@ -22,6 +22,9 @@ public: Model(const Model &) = delete; Model &operator =(const Model &) = delete; + Model(Model &&); + Model &operator =(Model &&); + void Invalidate() { dirty = true; } void Clear(); diff --git a/src/world.cpp b/src/world.cpp index e3c10b1..c24450c 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -1,6 +1,7 @@ #include "world.hpp" #include +#include namespace blank { @@ -76,10 +77,27 @@ int BlockTypeRegistry::Add(const BlockType &t) { Chunk::Chunk() : blocks(Size()) , model() +, transform(1.0f) , dirty(false) { } +Chunk::Chunk(Chunk &&other) +: blocks(std::move(other.blocks)) +, model(std::move(other.model)) +, transform(other.transform) +, dirty(other.dirty) { + +} + +Chunk &Chunk::operator =(Chunk &&other) { + blocks = std::move(other.blocks); + model = std::move(other.model); + transform = other.transform; + dirty = other.dirty; + return *this; +} + void Chunk::Draw() { if (dirty) { @@ -147,6 +165,11 @@ bool Chunk::Intersection( return true; } +void Chunk::Position(const glm::vec3 &pos) { + position = pos; + transform = glm::translate(pos * Extent()); +} + int Chunk::VertexCount() const { // TODO: query blocks as soon as type shapes are implemented @@ -167,4 +190,101 @@ void Chunk::Update() { dirty = false; } + +World::World() +: blockType() +, chunks() { + blockType.Add(BlockType(true, glm::vec3(1, 1, 1))); + blockType.Add(BlockType(true, glm::vec3(1, 0, 0))); + blockType.Add(BlockType(true, glm::vec3(0, 1, 0))); + blockType.Add(BlockType(true, glm::vec3(0, 0, 1))); +} + + +void World::Generate() { + for (int z = -1; z < 2; ++z) { + for (int y = -1; y < 2; ++y) { + for (int x = -1; x < 2; ++x) { + Generate(glm::vec3(x, y, z)); + } + } + } +} + +Chunk &World::Generate(const glm::vec3 &pos) { + chunks.emplace_back(); + Chunk &chunk = chunks.back(); + chunk.Position(pos); + chunk.BlockAt(glm::vec3(0, 0, 0)) = Block(blockType[4]); + chunk.BlockAt(glm::vec3(0, 0, 1)) = Block(blockType[1]); + chunk.BlockAt(glm::vec3(1, 0, 0)) = Block(blockType[2]); + chunk.BlockAt(glm::vec3(1, 0, 1)) = Block(blockType[3]); + chunk.BlockAt(glm::vec3(2, 0, 0)) = Block(blockType[4]); + chunk.BlockAt(glm::vec3(2, 0, 1)) = Block(blockType[1]); + chunk.BlockAt(glm::vec3(3, 0, 0)) = Block(blockType[2]); + chunk.BlockAt(glm::vec3(3, 0, 1)) = Block(blockType[3]); + chunk.BlockAt(glm::vec3(2, 0, 2)) = Block(blockType[4]); + chunk.BlockAt(glm::vec3(2, 0, 3)) = Block(blockType[1]); + chunk.BlockAt(glm::vec3(3, 0, 2)) = Block(blockType[2]); + chunk.BlockAt(glm::vec3(3, 0, 3)) = Block(blockType[3]); + chunk.BlockAt(glm::vec3(1, 1, 0)) = Block(blockType[1]); + chunk.BlockAt(glm::vec3(1, 1, 1)) = Block(blockType[4]); + chunk.BlockAt(glm::vec3(2, 1, 1)) = Block(blockType[3]); + chunk.BlockAt(glm::vec3(2, 2, 1)) = Block(blockType[2]); + chunk.Invalidate(); + return chunk; +} + +bool World::Intersection( + const Ray &ray, + const glm::mat4 &M, + Chunk **chunk, + int *blkid, + float *dist, + glm::vec3 *normal) { + Chunk *closest_chunk = nullptr; + int closest_blkid = -1; + float closest_dist = std::numeric_limits::infinity(); + glm::vec3 closest_normal; + + for (Chunk &cur_chunk : chunks) { + int cur_blkid; + float cur_dist; + glm::vec3 cur_normal; + if (cur_chunk.Intersection(ray, M * cur_chunk.Transform(), &cur_blkid, &cur_dist, &cur_normal)) { + if (cur_dist < closest_dist) { + closest_chunk = &cur_chunk; + closest_blkid = cur_blkid; + closest_dist = cur_dist; + closest_normal = cur_normal; + } + } + } + + if (chunk) { + *chunk = closest_chunk; + } + if (blkid) { + *blkid = closest_blkid; + } + if (dist) { + *dist = closest_dist; + } + if (normal) { + *normal = closest_normal; + } + return closest_chunk; +} + + +Chunk &World::Next(const Chunk &to, const glm::vec3 &dir) { + const glm::vec3 tgt_pos = to.Position() + dir; + for (Chunk &chunk : chunks) { + if (chunk.Position() == tgt_pos) { + return chunk; + } + } + return Generate(tgt_pos); +} + } diff --git a/src/world.hpp b/src/world.hpp index 67ee355..9f29ab4 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -4,6 +4,7 @@ #include "model.hpp" #include "geometry.hpp" +#include #include #include #include @@ -75,14 +76,27 @@ class Chunk { public: Chunk(); + Chunk(Chunk &&); + Chunk &operator =(Chunk &&); + static constexpr int Width() { return 16; } static constexpr int Height() { return 16; } static constexpr int Depth() { return 16; } + static glm::vec3 Extent() { return glm::vec3(Width(), Height(), Depth()); } static constexpr int Size() { return Width() * Height() * Depth(); } + static constexpr bool InBounds(const glm::vec3 &pos) { + return + pos.x >= 0 && pos.x < Width() && + pos.y >= 0 && pos.y < Height() && + pos.z >= 0 && pos.z < Depth(); + } static constexpr int ToIndex(const glm::vec3 &pos) { return pos.x + pos.y * Width() + pos.z * Width() * Height(); } + static constexpr bool InBounds(int idx) { + return idx >= 0 && idx < Size(); + } static glm::vec3 ToCoords(int idx) { return glm::vec3( idx % Width(), @@ -105,6 +119,10 @@ public: float *dist = nullptr, glm::vec3 *normal = nullptr) const; + void Position(const glm::vec3 &); + const glm::vec3 &Position() const { return position; } + const glm::mat4 &Transform() const { return transform; } + void Draw(); private: @@ -114,10 +132,42 @@ private: private: std::vector blocks; Model model; + glm::vec3 position; + glm::mat4 transform; bool dirty; }; + +class World { + +public: + World(); + + void Generate(); + + bool Intersection( + const Ray &, + const glm::mat4 &M, + Chunk **chunk = nullptr, + int *blkid = nullptr, + float *dist = nullptr, + glm::vec3 *normal = nullptr); + + BlockTypeRegistry &BlockTypes() { return blockType; } + std::list &LoadedChunks() { return chunks; } + + Chunk &Next(const Chunk &, const glm::vec3 &dir); + +private: + Chunk &Generate(const glm::vec3 &); + +private: + BlockTypeRegistry blockType; + std::list chunks; + +}; + } #endif