]> git.localhorst.tv Git - blank.git/commitdiff
split chunk redering from world model
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 27 Aug 2015 09:45:20 +0000 (11:45 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 27 Aug 2015 09:48:06 +0000 (11:48 +0200)
first step towards headless

18 files changed:
src/ai/Spawner.cpp
src/ai/Spawner.hpp
src/app/PreloadState.cpp
src/app/PreloadState.hpp
src/app/WorldState.cpp
src/app/WorldState.hpp
src/io/WorldSave.cpp
src/ui/HUD.hpp
src/ui/ui.cpp
src/world/Block.hpp
src/world/BlockTypeRegistry.hpp
src/world/Chunk.hpp
src/world/ChunkRenderer.hpp [new file with mode: 0644]
src/world/World.cpp
src/world/World.hpp
src/world/chunk.cpp
src/world/render.cpp [new file with mode: 0644]
tst/test.cpp

index b0ded15ab771121763f93c72bf1604164c12aa70..6d5549faf6eaffb7afdaa0d0b88ae385ef0f8e53 100644 (file)
@@ -2,9 +2,9 @@
 
 #include "Chaser.hpp"
 #include "RandomWalk.hpp"
+#include "../model/shapes.hpp"
 #include "../world/BlockLookup.hpp"
 #include "../world/BlockType.hpp"
-#include "../world/BlockTypeRegistry.hpp"
 #include "../world/Entity.hpp"
 #include "../world/World.hpp"
 
@@ -20,10 +20,25 @@ Spawner::Spawner(World &world)
 , max_entities(16)
 , chunk_range(4) {
        EntityModel::Buffer buf;
-       for (size_t i = 0; i < 14; ++i) {
-               world.BlockTypes()[i + 1].FillEntityModel(buf);
-               models[i].Update(buf);
+       {
+               CuboidShape shape({{ -0.25f, -0.5f, -0.25f }, { 0.25f, 0.5f, 0.25f }});
+               shape.Vertices(buf, 1.0f);
+               buf.colors.resize(shape.VertexCount(), { 1.0f, 1.0f, 0.0f });
+               models[0].Update(buf);
+       }
+       {
+               CuboidShape shape({{ -0.5f, -0.25f, -0.5f }, { 0.5f, 0.25f, 0.5f }});
+               buf.Clear();
+               shape.Vertices(buf, 2.0f);
+               buf.colors.resize(shape.VertexCount(), { 0.0f, 1.0f, 1.0f });
+               models[1].Update(buf);
+       }
+       {
+               StairShape shape({{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }}, { 0.4f, 0.4f });
                buf.Clear();
+               shape.Vertices(buf, 3.0f);
+               buf.colors.resize(shape.VertexCount(), { 1.0f, 0.0f, 1.0f });
+               models[2].Update(buf);
        }
 
        timer.Start();
@@ -112,7 +127,7 @@ void Spawner::Spawn(const glm::ivec3 &chunk, const glm::vec3 &pos) {
        e.Position(chunk, pos);
        e.Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } });
        e.WorldCollidable(true);
-       e.GetModel().SetNodeModel(&models[rand() % 14]);
+       e.GetModel().SetNodeModel(&models[rand() % 3]);
        e.AngularVelocity(rot);
        Controller *ctrl;
        if (rand() % 2) {
index b36e520f7d38cb7273e33109052bbc6435ea205b..c55d73c0f7f90b835b5791f69e8c9096e17cc81d 100644 (file)
@@ -30,7 +30,7 @@ private:
        World &world;
        std::vector<Controller *> controllers;
 
-       EntityModel models[14];
+       EntityModel models[3];
 
        IntervalTimer timer;
        float despawn_range;
index aca2502eaeacc92e2417204fec3f618739c95eb7..3b686107a278febd6fcc7f01f0fe06a44fa1b5cf 100644 (file)
@@ -2,13 +2,15 @@
 
 #include "Environment.hpp"
 #include "../world/ChunkLoader.hpp"
+#include "../world/ChunkRenderer.hpp"
 
 
 namespace blank {
 
-PreloadState::PreloadState(Environment &env, ChunkLoader &loader)
+PreloadState::PreloadState(Environment &env, ChunkLoader &loader, ChunkRenderer &render)
 : env(env)
 , loader(loader)
+, render(render)
 , progress(env.assets.large_ui_font)
 , total(loader.ToLoad())
 , per_update(64) {
@@ -26,10 +28,8 @@ void PreloadState::Handle(const SDL_Event &e) {
 void PreloadState::Update(int dt) {
        loader.LoadN(per_update);
        if (loader.ToLoad() == 0) {
-               for (auto &chunk : loader.Loaded()) {
-                       chunk.CheckUpdate();
-               }
                env.state.Pop();
+               render.Update(render.MissingChunks());
        } else {
                progress.Update(total - loader.ToLoad(), total);
        }
index 010dde7648b5e8149b390e2991defdbe34b6431b..64936dc2b7cd5ebdae270bec0bb00d4b77362fbe 100644 (file)
 namespace blank {
 
 class ChunkLoader;
+class ChunkRenderer;
 class Environment;
 
 class PreloadState
 : public State {
 
 public:
-       PreloadState(Environment &, ChunkLoader &);
+       PreloadState(Environment &, ChunkLoader &, ChunkRenderer &);
 
        void Handle(const SDL_Event &) override;
        void Update(int dt) override;
@@ -26,6 +27,7 @@ public:
 private:
        Environment &env;
        ChunkLoader &loader;
+       ChunkRenderer &render;
        Progress progress;
        std::size_t total;
        std::size_t per_update;
index 372b659f8975b4c564bc73a8d91485abb6eafd69..ed711bfc8c15e6fde8999f9846b5184b77fed3d5 100644 (file)
@@ -1,6 +1,7 @@
 #include "WorldState.hpp"
 
 #include "Environment.hpp"
+#include "TextureIndex.hpp"
 
 #include <SDL.h>
 
@@ -14,12 +15,19 @@ WorldState::WorldState(
        const WorldSave &save
 )
 : env(env)
-, world(env.assets, wc, save)
+, block_types()
+, world(block_types, wc, save)
+, chunk_renderer(world, wc.load.load_dist)
 , spawner(world)
 , interface(ic, env, world)
-, preload(env, world.Loader())
+, preload(env, world.Loader(), chunk_renderer)
 , unload(env, world.Loader()) {
-
+       TextureIndex tex_index;
+       env.assets.LoadBlockTypes("default", block_types, tex_index);
+       chunk_renderer.LoadTextures(env.assets, tex_index);
+       chunk_renderer.FogDensity(wc.fog_density);
+       // TODO: better solution for initializing HUD
+       interface.SelectNext();
 }
 
 
@@ -60,8 +68,10 @@ void WorldState::Update(int dt) {
        interface.Update(dt);
        spawner.Update(dt);
        world.Update(dt);
+       chunk_renderer.Rebase(world.Player().ChunkCoords());
+       chunk_renderer.Update(dt);
 
-       glm::mat4 trans = world.Player().Transform(Chunk::Pos(0, 0, 0));
+       glm::mat4 trans = world.Player().Transform(world.Player().ChunkCoords());
        glm::vec3 dir(trans * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f));
        glm::vec3 up(trans * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f));
        env.audio.Position(world.Player().Position());
@@ -71,6 +81,8 @@ void WorldState::Update(int dt) {
 }
 
 void WorldState::Render(Viewport &viewport) {
+       viewport.WorldPosition(world.Player().Transform(world.Player().ChunkCoords()));
+       chunk_renderer.Render(viewport);
        world.Render(viewport);
        interface.Render(viewport);
 }
index 04bf6a84a8100a744018e0f0ba7036a87dff874f..d47024ff6633ed1fb65cb07dd29d1c8ba6ce2080 100644 (file)
@@ -6,6 +6,8 @@
 #include "UnloadState.hpp"
 #include "../ai/Spawner.hpp"
 #include "../ui/Interface.hpp"
+#include "../world/BlockTypeRegistry.hpp"
+#include "../world/ChunkRenderer.hpp"
 #include "../world/World.hpp"
 
 
@@ -35,7 +37,9 @@ public:
 
 private:
        Environment &env;
+       BlockTypeRegistry block_types;
        World world;
+       ChunkRenderer chunk_renderer;
        Spawner spawner;
        Interface interface;
 
index a08d69c3c288784ac312b84c32cdb461c209baa4..bd041f2e89cf20aba12487b1db2352ea010ebfac 100644 (file)
@@ -3,6 +3,7 @@
 #include "filesystem.hpp"
 
 #include <cctype>
+#include <cstring>
 #include <fstream>
 #include <iostream>
 #include <limits>
index 8978c91e23510d7d332b7015dc3bf1729086e4fa..1917b130c926772b5518806c1fc04af157447271 100644 (file)
@@ -23,6 +23,7 @@ public:
        HUD(const HUD &) = delete;
        HUD &operator =(const HUD &) = delete;
 
+       void DisplayNone();
        void Display(const Block &);
 
        void Render(Viewport &) noexcept;
index 037fcb510dc16a55d96f1ca638d08ba48fe47229..acf877fd1da6811dca1679d80461d7c86105f0ee 100644 (file)
@@ -59,6 +59,10 @@ HUD::HUD(const BlockTypeRegistry &types, const Font &font)
 }
 
 
+void HUD::DisplayNone() {
+       block_visible = false;
+}
+
 void HUD::Display(const Block &b) {
        const BlockType &type = types.Get(b.type);
 
@@ -120,7 +124,7 @@ Interface::Interface(
 , place_timer(256)
 , remove_timer(256)
 , remove(0)
-, selection(1)
+, selection(0)
 , place_sound(env.assets.LoadSound("thump"))
 , remove_sound(env.assets.LoadSound("plop"))
 , fwd(0)
@@ -146,7 +150,7 @@ Interface::Interface(
        messages.Position(glm::vec3(25.0f, -25.0f, 0.0f), Gravity::SOUTH_WEST);
        messages.Foreground(glm::vec4(1.0f));
        messages.Background(glm::vec4(0.5f));
-       hud.Display(selection);
+       hud.DisplayNone();
 }
 
 
index 5f52d173882903af05a8346561842d0f77006f52..4b4ea210596bbd8d3c6adb0f63e5131cf6065708 100644 (file)
@@ -66,6 +66,22 @@ struct Block {
                }
        }
 
+       /// returns 1 for pro-axis, -1 for retro-axis, 0 for invalid faces
+       static int Direction(Face f) noexcept {
+               switch (f) {
+                       case FACE_RIGHT:
+                       case FACE_UP:
+                       case FACE_FRONT:
+                               return 1;
+                       case FACE_LEFT:
+                       case FACE_DOWN:
+                       case FACE_BACK:
+                               return -1;
+                       default:
+                               return 0;
+               }
+       }
+
        static glm::ivec3 FaceNormal(Face face) noexcept {
                return face2normal[face];
        }
index 0a1ebf0ebc4f31a369fdc5eada961d12eef4d093..38afac4b6be98b18a8ad2273d284bf5e7a18f14d 100644 (file)
@@ -19,6 +19,9 @@ public:
        size_t Size() const noexcept { return types.size(); }
 
        BlockType &operator [](Block::Type id) { return types[id]; }
+       const BlockType &operator [](Block::Type id) const { return types[id]; }
+
+       BlockType &Get(Block::Type id) { return types[id]; }
        const BlockType &Get(Block::Type id) const { return types[id]; }
 
 private:
index 61ec83bd0aaad9f048fd50721a67e63eba0070f4..0440f9c7bb8a97aa10a639cefed469b304df0a7b 100644 (file)
@@ -3,7 +3,6 @@
 
 #include "Block.hpp"
 #include "BlockTypeRegistry.hpp"
-#include "../model/BlockModel.hpp"
 #include "../model/geometry.hpp"
 
 #include <vector>
@@ -167,18 +166,13 @@ public:
        bool ShouldUpdateModel() const noexcept { return dirty_model; }
        bool ShouldUpdateSave() const noexcept { return dirty_save; }
 
-       void CheckUpdate() noexcept;
-       void Draw() noexcept;
-
-private:
-       void Update() noexcept;
+       void Update(BlockModel &) noexcept;
 
 private:
        const BlockTypeRegistry *types;
        Chunk *neighbor[Block::FACE_COUNT];
        Block blocks[size];
        unsigned char light[size];
-       BlockModel model;
        Pos position;
        bool dirty_model;
        bool dirty_save;
diff --git a/src/world/ChunkRenderer.hpp b/src/world/ChunkRenderer.hpp
new file mode 100644 (file)
index 0000000..3240c3d
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef BLANK_WORLD_CHUNKRENDERER_HPP_
+#define BLANK_WORLD_CHUNKRENDERER_HPP_
+
+#include "Block.hpp"
+#include "Chunk.hpp"
+#include "../graphics/ArrayTexture.hpp"
+#include "../model/BlockModel.hpp"
+
+#include <vector>
+
+
+namespace blank {
+
+class Assets;
+class TextureIndex;
+class Viewport;
+class World;
+
+class ChunkRenderer {
+
+public:
+       /// render_distance in chunks, excluding the base chunk which is always rendered
+       ChunkRenderer(World &, int render_distance);
+
+       void LoadTextures(const Assets &, const TextureIndex &);
+       void FogDensity(float d) noexcept { fog_density = d; }
+
+       bool InRange(const Chunk::Pos &) const noexcept;
+       int IndexOf(const Chunk::Pos &) const noexcept;
+
+       int TotalChunks() const noexcept { return total_length; }
+       int IndexedChunks() const noexcept { return total_indexed; }
+       int MissingChunks() const noexcept { return total_length - total_indexed; }
+
+       void Rebase(const Chunk::Pos &);
+       void Rescan();
+       void Scan();
+       void Update(int dt);
+
+       void Render(Viewport &);
+
+private:
+       int GetCol(int) const noexcept;
+
+       void Shift(Block::Face);
+
+private:
+       World &world;
+       ArrayTexture block_tex;
+
+       int render_dist;
+       int side_length;
+       int total_length;
+       int total_indexed;
+       glm::ivec3 stride;
+       std::vector<BlockModel> models;
+       std::vector<Chunk *> chunks;
+
+       Chunk::Pos base;
+
+       float fog_density;
+
+};
+
+}
+
+#endif
index 7ac9e18a6287e80ef989657f57b10d71c35b9ce3..592558b303a943e655fac9eec3f43f5dc7471755 100644 (file)
@@ -3,7 +3,6 @@
 #include "EntityCollision.hpp"
 #include "WorldCollision.hpp"
 #include "../app/Assets.hpp"
-#include "../app/TextureIndex.hpp"
 #include "../graphics/Format.hpp"
 #include "../graphics/Viewport.hpp"
 
 
 namespace blank {
 
-World::World(const Assets &assets, const Config &config, const WorldSave &save)
-: block_type()
-, block_tex()
+World::World(const BlockTypeRegistry &types, const Config &config, const WorldSave &save)
+: block_type(types)
 , generate(config.gen)
-, chunks(config.load, block_type, generate, save)
+, chunks(config.load, types, generate, save)
 , player()
 , entities()
 , light_direction(config.light_direction)
 , fog_density(config.fog_density) {
-       TextureIndex tex_index;
-       assets.LoadBlockTypes("default", block_type, tex_index);
-
-       block_tex.Bind();
-       assets.LoadTextures(tex_index, block_tex);
-       block_tex.FilterNearest();
-
        generate.Space(0);
        generate.Light(13);
        generate.Solids({ 1, 4, 7, 10 });
@@ -202,21 +193,6 @@ void World::Resolve(Entity &e, std::vector<WorldCollision> &col) {
 
 
 void World::Render(Viewport &viewport) {
-       viewport.WorldPosition(player->Transform(player->ChunkCoords()));
-
-       BlockLighting &chunk_prog = viewport.ChunkProgram();
-       chunk_prog.SetTexture(block_tex);
-       chunk_prog.SetFogDensity(fog_density);
-
-       for (Chunk &chunk : chunks.Loaded()) {
-               glm::mat4 m(chunk.Transform(player->ChunkCoords()));
-               chunk_prog.SetM(m);
-               glm::mat4 mvp(chunk_prog.GetVP() * m);
-               if (!CullTest(Chunk::Bounds(), mvp)) {
-                       chunk.Draw();
-               }
-       }
-
        DirectionalLighting &entity_prog = viewport.EntityProgram();
        entity_prog.SetLightDirection(light_direction);
        entity_prog.SetFogDensity(fog_density);
index e0209c96aaf273eb4fab523fd4734b2353e5af28..76cdeb23ccd3aabcb882a8d8cd211e14aa84b81f 100644 (file)
@@ -1,11 +1,9 @@
 #ifndef BLANK_WORLD_WORLD_HPP_
 #define BLANK_WORLD_WORLD_HPP_
 
-#include "BlockTypeRegistry.hpp"
 #include "ChunkLoader.hpp"
 #include "Entity.hpp"
 #include "Generator.hpp"
-#include "../graphics/ArrayTexture.hpp"
 
 #include <list>
 #include <vector>
@@ -14,7 +12,7 @@
 
 namespace blank {
 
-class Assets;
+class BlockTypeRegistry;
 class EntityCollision;
 class Viewport;
 class WorldCollision;
@@ -37,7 +35,7 @@ public:
                ChunkLoader::Config load = ChunkLoader::Config();
        };
 
-       World(const Assets &, const Config &, const WorldSave &);
+       World(const BlockTypeRegistry &, const Config &, const WorldSave &);
 
        /// check if this ray hits a block
        /// depth in the collision is the distance between the ray's
@@ -62,7 +60,7 @@ public:
        bool Intersection(const Entity &e, std::vector<WorldCollision> &);
        void Resolve(Entity &e, std::vector<WorldCollision> &);
 
-       BlockTypeRegistry &BlockTypes() noexcept { return block_type; }
+       const BlockTypeRegistry &BlockTypes() noexcept { return block_type; }
        ChunkLoader &Loader() noexcept { return chunks; }
 
        Entity &Player() { return *player; }
@@ -75,9 +73,7 @@ public:
        void Render(Viewport &);
 
 private:
-       BlockTypeRegistry block_type;
-
-       ArrayTexture block_tex;
+       const BlockTypeRegistry &block_type;
 
        Generator generate;
        ChunkLoader chunks;
index 83c94e3403a14ddd97283739dfe34e0e50fa9696..11c9d36bdaedee1682725db27c31d3341b89b305 100644 (file)
@@ -25,7 +25,6 @@ Chunk::Chunk(const BlockTypeRegistry &types) noexcept
 , neighbor{0}
 , blocks{}
 , light{0}
-, model()
 , position(0, 0, 0)
 , dirty_model(false)
 , dirty_save(false) {
@@ -34,7 +33,6 @@ Chunk::Chunk(const BlockTypeRegistry &types) noexcept
 
 Chunk::Chunk(Chunk &&other) noexcept
 : types(other.types)
-, model(std::move(other.model))
 , position(other.position)
 , dirty_model(other.dirty_model)
 , dirty_save(other.dirty_save) {
@@ -48,7 +46,6 @@ Chunk &Chunk::operator =(Chunk &&other) noexcept {
        std::copy(other.neighbor, other.neighbor + sizeof(neighbor), neighbor);
        std::copy(other.blocks, other.blocks + sizeof(blocks), blocks);
        std::copy(other.light, other.light + sizeof(light), light);
-       model = std::move(other.model);
        position = other.position;
        dirty_model = other.dirty_save;
        dirty_save = other.dirty_save;
@@ -429,14 +426,6 @@ bool Chunk::IsSurface(const Pos &pos) const noexcept {
 }
 
 
-void Chunk::Draw() noexcept {
-       if (ShouldUpdateModel()) {
-               Update();
-       }
-       model.Draw();
-}
-
-
 bool Chunk::Intersection(
        const Ray &ray,
        const glm::mat4 &M,
@@ -511,13 +500,7 @@ BlockModel::Buffer buf;
 
 }
 
-void Chunk::CheckUpdate() noexcept {
-       if (ShouldUpdateModel()) {
-               Update();
-       }
-}
-
-void Chunk::Update() noexcept {
+void Chunk::Update(BlockModel &model) noexcept {
        int vtx_count = 0, idx_count = 0;
        for (const auto &block : blocks) {
                const Shape *shape = Type(block).shape;
diff --git a/src/world/render.cpp b/src/world/render.cpp
new file mode 100644 (file)
index 0000000..f701faf
--- /dev/null
@@ -0,0 +1,174 @@
+#include "ChunkRenderer.hpp"
+
+#include "World.hpp"
+#include "../app/Assets.hpp"
+#include "../graphics/BlockLighting.hpp"
+#include "../graphics/Viewport.hpp"
+
+
+namespace blank {
+
+ChunkRenderer::ChunkRenderer(World &world, int rd)
+: world(world)
+, block_tex()
+, render_dist(rd)
+, side_length(2 * rd + 1)
+, total_length(side_length * side_length * side_length)
+, total_indexed(0)
+, stride(1, side_length, side_length * side_length)
+, models(total_length)
+, chunks(total_length)
+, base(0, 0, 0)
+, fog_density(0.0f) {
+
+}
+
+
+void ChunkRenderer::LoadTextures(const Assets &assets, const TextureIndex &tex_index) {
+       block_tex.Bind();
+       assets.LoadTextures(tex_index, block_tex);
+       block_tex.FilterNearest();
+}
+
+
+bool ChunkRenderer::InRange(const Chunk::Pos &pos) const noexcept {
+       return manhattan_radius(pos - base) <= render_dist;
+}
+
+int ChunkRenderer::IndexOf(const Chunk::Pos &pos) const noexcept {
+       Chunk::Pos mod_pos(
+               GetCol(pos.x),
+               GetCol(pos.y),
+               GetCol(pos.z)
+       );
+       return mod_pos.x * stride.x
+               +  mod_pos.y * stride.y
+               +  mod_pos.z * stride.z;
+}
+
+
+void ChunkRenderer::Rebase(const Chunk::Pos &new_base) {
+       if (new_base == base) return;
+
+       Chunk::Pos diff(new_base - base);
+
+       if (manhattan_radius(diff) > render_dist) {
+               // that's more than half, so probably not worth shifting
+               base = new_base;
+               Rescan();
+               return;
+       }
+
+       while (diff.x > 0) {
+               Shift(Block::FACE_RIGHT);
+               --diff.x;
+       }
+       while (diff.x < 0) {
+               Shift(Block::FACE_LEFT);
+               ++diff.x;
+       }
+       while (diff.y > 0) {
+               Shift(Block::FACE_UP);
+               --diff.y;
+       }
+       while (diff.y < 0) {
+               Shift(Block::FACE_DOWN);
+               ++diff.y;
+       }
+       while (diff.z > 0) {
+               Shift(Block::FACE_FRONT);
+               --diff.z;
+       }
+       while (diff.z < 0) {
+               Shift(Block::FACE_BACK);
+               ++diff.z;
+       }
+}
+
+int ChunkRenderer::GetCol(int c) const noexcept {
+       c %= side_length;
+       if (c < 0) c += side_length;
+       return c;
+}
+
+void ChunkRenderer::Shift(Block::Face f) {
+       int a_axis = Block::Axis(f);
+       int b_axis = (a_axis + 1) % 3;
+       int c_axis = (a_axis + 2) % 3;
+       int dir = Block::Direction(f);
+       base[a_axis] += dir;
+       int a = GetCol(base[a_axis] + (render_dist * dir));
+       int a_stride = a * stride[a_axis];
+       for (int b = 0; b < side_length; ++b) {
+               int b_stride = b * stride[b_axis];
+               for (int c = 0; c < side_length; ++c) {
+                       int bc_stride = b_stride + c * stride[c_axis];
+                       int index = a_stride + bc_stride;
+                       if (chunks[index]) {
+                               chunks[index] = nullptr;
+                               --total_indexed;
+                       }
+                       int neighbor = ((a - dir + side_length) % side_length) * stride[a_axis] + bc_stride;
+                       if (chunks[neighbor] && chunks[neighbor]->HasNeighbor(f)) {
+                               chunks[index] = &chunks[neighbor]->GetNeighbor(f);
+                               chunks[index]->InvalidateModel();
+                               ++total_indexed;
+                       }
+               }
+       }
+}
+
+
+void ChunkRenderer::Rescan() {
+       chunks.assign(total_length, nullptr);
+       total_indexed = 0;
+       Scan();
+}
+
+void ChunkRenderer::Scan() {
+       for (Chunk &chunk : world.Loader().Loaded()) {
+               if (!InRange(chunk.Position())) continue;
+               int index = IndexOf(chunk.Position());
+               if (!chunks[index]) {
+                       chunks[index] = &chunk;
+                       chunk.InvalidateModel();
+                       ++total_indexed;
+               }
+       }
+}
+
+void ChunkRenderer::Update(int dt) {
+       if (MissingChunks()) {
+               Scan();
+       }
+
+       // maximum of 1000 per second too high?
+       for (int i = 0, updates = 0; i < total_length && updates < dt; ++i) {
+               if (chunks[i] && chunks[i]->ShouldUpdateModel()) {
+                       chunks[i]->Update(models[i]);
+                       ++updates;
+               }
+       }
+}
+
+
+void ChunkRenderer::Render(Viewport &viewport) {
+       BlockLighting &chunk_prog = viewport.ChunkProgram();
+       chunk_prog.SetTexture(block_tex);
+       chunk_prog.SetFogDensity(fog_density);
+
+       for (int i = 0; i < total_length; ++i) {
+               if (!chunks[i]) continue;
+               glm::mat4 m(chunks[i]->Transform(base));
+               glm::mat4 mvp(chunk_prog.GetVP() * m);
+               if (!CullTest(Chunk::Bounds(), mvp)) {
+                       if (chunks[i]->ShouldUpdateModel()) {
+                               chunks[i]->Update(models[i]);
+                       }
+                       chunk_prog.SetM(m);
+                       models[i].Draw();
+               }
+       }
+}
+
+}
index b12d04bc178e945b16ec0d9257b2823311713e5a..ff1ce710c25c80912d4ab90ed2fd18e61a8d75fd 100644 (file)
@@ -1,5 +1,3 @@
-#include "app/init.hpp"
-
 #include <cppunit/extensions/TestFactoryRegistry.h>
 #include <cppunit/ui/text/TestRunner.h>
 
@@ -8,8 +6,6 @@ using CppUnit::TextUi::TestRunner;
 
 
 int main(int, char **) {
-       blank::Init init;
-
        TestRunner runner;
        TestFactoryRegistry &registry = TestFactoryRegistry::getRegistry();
        runner.addTest(registry.makeTest());