]> git.localhorst.tv Git - blank.git/commitdiff
use collision structures for ray tests
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Tue, 18 Aug 2015 11:23:47 +0000 (13:23 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Tue, 18 Aug 2015 13:45:44 +0000 (15:45 +0200)
src/ai/ai.cpp
src/ui/Interface.hpp
src/ui/ui.cpp
src/world/BlockLookup.hpp
src/world/Chunk.hpp
src/world/EntityCollision.hpp [new file with mode: 0644]
src/world/World.cpp
src/world/World.hpp
src/world/WorldCollision.hpp
src/world/chunk.cpp

index 6b380e4d1027a8e7e2cc1cba11f5d1d24bb539e3..5f5474b5f3320030e2f7e902badbb86c58328a79 100644 (file)
@@ -5,6 +5,7 @@
 #include "../model/geometry.hpp"
 #include "../world/Entity.hpp"
 #include "../world/World.hpp"
+#include "../world/WorldCollision.hpp"
 
 #include <glm/glm.hpp>
 
@@ -34,12 +35,9 @@ void Chaser::Update(int dt) {
        bool line_of_sight = true;
        // FIXME: this only works if target is in the reference chunk (which is true for the player)
        Ray aim{Target().Position() - diff, norm_diff};
-       Chunk *chunk;
-       int blkid;
-       float distance;
-       glm::vec3 normal;
-       if (world.Intersection(aim, glm::mat4(1.0f), chunk, blkid, distance, normal)) {
-               line_of_sight = distance > dist;
+       WorldCollision coll;
+       if (world.Intersection(aim, glm::mat4(1.0f), coll)) {
+               line_of_sight = coll.depth > dist;
        }
 
        if (!line_of_sight) {
index 907f9c234a320e5434c0da1f21bd2244c397c958..2538c46cc9176f9a677c255738370504edd283d2 100644 (file)
@@ -10,6 +10,8 @@
 #include "../model/geometry.hpp"
 #include "../model/OutlineModel.hpp"
 #include "../world/Block.hpp"
+#include "../world/EntityCollision.hpp"
+#include "../world/WorldCollision.hpp"
 
 #include <string>
 #include <glm/glm.hpp>
@@ -18,8 +20,6 @@
 
 namespace blank {
 
-class Chunk;
-class Entity;
 class Environment;
 class Viewport;
 class World;
@@ -94,10 +94,8 @@ private:
        HUD hud;
 
        Ray aim;
-       Chunk *aim_chunk;
-       Entity *aim_entity;
-       int aim_block;
-       glm::vec3 aim_normal;
+       WorldCollision aim_world;
+       EntityCollision aim_entity;
 
        OutlineModel outline;
        glm::mat4 outline_transform;
index c063099e9c230cf2c8e550c6758c64bbe5b5c560..1de6237e32cee5899b9d6ab0e647270f98461382 100644 (file)
@@ -11,6 +11,7 @@
 #include "../graphics/Viewport.hpp"
 #include "../io/TokenStreamReader.hpp"
 #include "../model/shapes.hpp"
+#include "../world/BlockLookup.hpp"
 #include "../world/World.hpp"
 
 #include <algorithm>
@@ -103,9 +104,8 @@ Interface::Interface(
 , ctrl(world.Player())
 , hud(world.BlockTypes(), env.assets.small_ui_font)
 , aim{{ 0, 0, 0 }, { 0, 0, -1 }}
-, aim_chunk(nullptr)
-, aim_block(0)
-, aim_normal()
+, aim_world()
+, aim_entity()
 , outline()
 , outline_transform(1.0f)
 , counter_text()
@@ -276,7 +276,7 @@ void Interface::ToggleCollision() {
 
 void Interface::PrintBlockInfo() {
        std::cout << std::endl;
-       if (!aim_chunk) {
+       if (!aim_world) {
                PostMessage("not looking at any block");
                Ray aim = ctrl.Aim();
                std::stringstream s;
@@ -285,53 +285,53 @@ void Interface::PrintBlockInfo() {
                return;
        }
        std::stringstream s;
-       s << "looking at block " << aim_block
-               << " " << Chunk::ToCoords(aim_block)
-               << " of chunk " << aim_chunk->Position()
+       s << "looking at block " << aim_world.block
+               << " " << aim_world.BlockCoords()
+               << " of chunk " << aim_world.GetChunk().Position()
        ;
        PostMessage(s.str());
-       Print(aim_chunk->BlockAt(aim_block));
+       Print(aim_world.GetBlock());
 }
 
 void Interface::PrintChunkInfo() {
        std::cout << std::endl;
-       if (!aim_chunk) {
+       if (!aim_world) {
                PostMessage("not looking at any block");
                return;
        }
        std::stringstream s;
-       s << "looking at chunk " << aim_chunk->Position();
+       s << "looking at chunk " << aim_world.GetChunk().Position();
        PostMessage(s.str());
 
        PostMessage("  neighbors:");
-       if (aim_chunk->HasNeighbor(Block::FACE_LEFT)) {
+       if (aim_world.GetChunk().HasNeighbor(Block::FACE_LEFT)) {
                s.str("");
-               s << " left  " << aim_chunk->GetNeighbor(Block::FACE_LEFT).Position();
+               s << " left  " << aim_world.GetChunk().GetNeighbor(Block::FACE_LEFT).Position();
                PostMessage(s.str());
        }
-       if (aim_chunk->HasNeighbor(Block::FACE_RIGHT)) {
+       if (aim_world.GetChunk().HasNeighbor(Block::FACE_RIGHT)) {
                s.str("");
-               s << " right " << aim_chunk->GetNeighbor(Block::FACE_RIGHT).Position();
+               s << " right " << aim_world.GetChunk().GetNeighbor(Block::FACE_RIGHT).Position();
                PostMessage(s.str());
        }
-       if (aim_chunk->HasNeighbor(Block::FACE_UP)) {
+       if (aim_world.GetChunk().HasNeighbor(Block::FACE_UP)) {
                s.str("");
-               s << " up    " << aim_chunk->GetNeighbor(Block::FACE_UP).Position();
+               s << " up    " << aim_world.GetChunk().GetNeighbor(Block::FACE_UP).Position();
                PostMessage(s.str());
        }
-       if (aim_chunk->HasNeighbor(Block::FACE_DOWN)) {
+       if (aim_world.GetChunk().HasNeighbor(Block::FACE_DOWN)) {
                s.str("");
-               s << " down  " << aim_chunk->GetNeighbor(Block::FACE_DOWN).Position();
+               s << " down  " << aim_world.GetChunk().GetNeighbor(Block::FACE_DOWN).Position();
                PostMessage(s.str());
        }
-       if (aim_chunk->HasNeighbor(Block::FACE_FRONT)) {
+       if (aim_world.GetChunk().HasNeighbor(Block::FACE_FRONT)) {
                s.str("");
-               s << " front " << aim_chunk->GetNeighbor(Block::FACE_FRONT).Position();
+               s << " front " << aim_world.GetChunk().GetNeighbor(Block::FACE_FRONT).Position();
                PostMessage(s.str());
        }
-       if (aim_chunk->HasNeighbor(Block::FACE_BACK)) {
+       if (aim_world.GetChunk().HasNeighbor(Block::FACE_BACK)) {
                s.str("");
-               s << " back  " << aim_chunk->GetNeighbor(Block::FACE_BACK).Position();
+               s << " back  " << aim_world.GetChunk().GetNeighbor(Block::FACE_BACK).Position();
                PostMessage(s.str());
        }
        std::cout << std::endl;
@@ -411,12 +411,12 @@ void Interface::UpdateOrientation() {
 }
 
 void Interface::UpdateBlockInfo() {
-       if (aim_chunk) {
-               const Block &block = aim_chunk->BlockAt(aim_block);
+       if (aim_world) {
+               const Block &block = aim_world.GetBlock();
                if (last_displayed != block) {
                        std::stringstream s;
                        s << "Block: "
-                               << aim_chunk->Type(block).label
+                               << aim_world.GetType().label
                                << ", face: " << block.GetFace()
                                << ", turn: " << block.GetTurn();
                        block_text.Set(env.assets.small_ui_font, s.str());
@@ -464,38 +464,37 @@ void Interface::HandleRelease(const SDL_MouseButtonEvent &event) {
 }
 
 void Interface::PickBlock() {
-       if (!aim_chunk) return;
-       selection = aim_chunk->BlockAt(aim_block);
+       if (!aim_world) return;
+       selection = aim_world.GetBlock();
        hud.Display(selection);
 }
 
 void Interface::PlaceBlock() {
-       if (!aim_chunk) return;
-       Chunk *mod_chunk = aim_chunk;
-       glm::vec3 next_pos = Chunk::ToCoords(aim_block) + aim_normal;
-       if (!Chunk::InBounds(next_pos)) {
-               mod_chunk = &world.Next(*aim_chunk, aim_normal);
-               next_pos -= aim_normal * glm::vec3(Chunk::Extent());
+       if (!aim_world) return;
+
+       glm::vec3 next_pos = aim_world.BlockCoords() + aim_world.normal;
+       BlockLookup next_block(&aim_world.GetChunk(), next_pos);
+       if (next_block) {
        }
-       mod_chunk->SetBlock(next_pos, selection);
+       next_block.SetBlock(selection);
 
        if (config.audio_disabled) return;
        const Entity &player = ctrl.Controlled();
        env.audio.Play(
                place_sound,
-               mod_chunk->ToSceneCoords(player.ChunkCoords(), next_pos)
+               aim_world.GetChunk().ToSceneCoords(player.ChunkCoords(), next_pos)
        );
 }
 
 void Interface::RemoveBlock() noexcept {
-       if (!aim_chunk) return;
-       aim_chunk->SetBlock(aim_block, remove);
+       if (!aim_world) return;
+       aim_world.SetBlock(remove);
 
        if (config.audio_disabled) return;
        const Entity &player = ctrl.Controlled();
        env.audio.Play(
                remove_sound,
-               aim_chunk->ToSceneCoords(player.ChunkCoords(), Chunk::ToCoords(aim_block))
+               aim_world.GetChunk().ToSceneCoords(player.ChunkCoords(), aim_world.BlockCoords())
        );
 }
 
@@ -576,32 +575,22 @@ OutlineModel::Buffer outl_buf;
 }
 
 void Interface::CheckAim() {
-       float chunk_dist;
-       glm::vec3 chunk_normal;
-       if (world.Intersection(aim, glm::mat4(1.0f), aim_chunk, aim_block, chunk_dist, chunk_normal)) {
-       } else {
-               aim_chunk = nullptr;
+       if (!world.Intersection(aim, glm::mat4(1.0f), aim_world)) {
+               aim_world = WorldCollision();
        }
-       float entity_dist;
-       glm::vec3 entity_normal;
-       if (!world.Intersection(aim, glm::mat4(1.0f), aim_entity, entity_dist, entity_normal)) {
-               aim_entity = nullptr;
+       if (!world.Intersection(aim, glm::mat4(1.0f), aim_entity)) {
+               aim_entity = EntityCollision();
        }
-       if (aim_chunk && aim_entity) {
+       if (aim_world && aim_entity) {
                // got both, pick the closest one
-               if (chunk_dist < entity_dist) {
-                       aim_normal = chunk_normal;
+               if (aim_world.depth < aim_entity.depth) {
                        UpdateOutline();
-                       aim_entity = nullptr;
+                       aim_entity = EntityCollision();
                } else {
-                       aim_normal = entity_normal;
-                       aim_chunk = nullptr;
+                       aim_world = WorldCollision();
                }
-       } else if (aim_chunk) {
-               aim_normal = chunk_normal;
+       } else if (aim_world) {
                UpdateOutline();
-       } else if (aim_entity) {
-               aim_normal = entity_normal;
        }
        if (debug) {
                UpdateBlockInfo();
@@ -610,10 +599,10 @@ void Interface::CheckAim() {
 
 void Interface::UpdateOutline() {
        outl_buf.Clear();
-       aim_chunk->Type(aim_chunk->BlockAt(aim_block)).FillOutlineModel(outl_buf);
+       aim_world.GetType().FillOutlineModel(outl_buf);
        outline.Update(outl_buf);
-       outline_transform = aim_chunk->Transform(world.Player().ChunkCoords());
-       outline_transform *= aim_chunk->ToTransform(Chunk::ToPos(aim_block), aim_block);
+       outline_transform = aim_world.GetChunk().Transform(world.Player().ChunkCoords());
+       outline_transform *= aim_world.BlockTransform();
        outline_transform *= glm::scale(glm::vec3(1.005f));
 }
 
@@ -621,7 +610,7 @@ void Interface::UpdateOutline() {
 void Interface::Render(Viewport &viewport) noexcept {
        if (config.visual_disabled) return;
 
-       if (aim_chunk) {
+       if (aim_world) {
                PlainColor &outline_prog = viewport.WorldOutlineProgram();
                outline_prog.SetM(outline_transform);
                outline.Draw();
index 4c8b12ba41a6a50f14c4f5033b685ce42ddaeca3..122b3c76f7e76374eaf50aa264513d54564b43c6 100644 (file)
@@ -10,13 +10,13 @@ namespace blank {
 class BlockLookup {
 
 public:
-       // resolve chunk/position from oob coordinates
+       /// resolve chunk/position from oob coordinates
        BlockLookup(Chunk *c, const Chunk::Pos &p) noexcept;
 
-       // resolve chunk/position from ib coordinates and direction
+       /// resolve chunk/position from ib coordinates and direction
        BlockLookup(Chunk *c, const Chunk::Pos &p, Block::Face dir) noexcept;
 
-       // check if lookup was successful
+       /// check if lookup was successful
        operator bool() const { return chunk; }
 
        // only valid if lookup was successful
@@ -26,6 +26,8 @@ public:
        const BlockType &GetType() const noexcept { return GetChunk().Type(GetBlock()); }
        int GetLight() const noexcept { return GetChunk().GetLight(GetBlockPos()); }
 
+       void SetBlock(const Block &b) noexcept { GetChunk().SetBlock(GetBlockPos(), b); }
+
        // traverse in given direction
        BlockLookup Next(Block::Face f) const { return BlockLookup(chunk, pos, f); }
 
index e9a075b2168bef5238c3d3562fd0b1b4f0d0d7dd..61ec83bd0aaad9f048fd50721a67e63eba0070f4 100644 (file)
@@ -142,15 +142,13 @@ public:
        bool Intersection(
                const Ray &,
                const glm::mat4 &M,
-               int &blkid,
-               float &dist,
-               glm::vec3 &normal) const noexcept;
+               WorldCollision &) noexcept;
 
        bool Intersection(
                const AABB &box,
                const glm::mat4 &Mbox,
                const glm::mat4 &Mchunk,
-               std::vector<WorldCollision> &) const noexcept;
+               std::vector<WorldCollision> &) noexcept;
 
        void Position(const Pos &pos) noexcept { position = pos; }
        const Pos &Position() const noexcept { return position; }
diff --git a/src/world/EntityCollision.hpp b/src/world/EntityCollision.hpp
new file mode 100644 (file)
index 0000000..be1a82d
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef BLANK_WORLD_ENTITYCOLLISION_HPP_
+#define BLANK_WORLD_ENTITYCOLLISION_HPP_
+
+
+namespace blank {
+
+class Entity;
+
+struct EntityCollision {
+
+       Entity *entity;
+
+       float depth;
+       glm::vec3 normal;
+
+       EntityCollision()
+       : entity(nullptr), depth(0.0f), normal(0.0f) { }
+       EntityCollision(Entity *e, float d, const glm::vec3 &n)
+       : entity(e), depth(d), normal(n) { }
+
+       /// check if an actual collision
+       operator bool() const noexcept { return entity; }
+
+};
+
+}
+
+#endif
index 2c0d164d5b4acb8f09bc4eba77b8a83faf881967..997a5f0b83346238890a8c952e589613b84c2930 100644 (file)
@@ -1,5 +1,6 @@
 #include "World.hpp"
 
+#include "EntityCollision.hpp"
 #include "WorldCollision.hpp"
 #include "../app/Assets.hpp"
 #include "../app/TextureIndex.hpp"
@@ -57,10 +58,7 @@ std::vector<Candidate> candidates;
 bool World::Intersection(
        const Ray &ray,
        const glm::mat4 &M,
-       Chunk *&chunk,
-       int &blkid,
-       float &dist,
-       glm::vec3 &normal
+       WorldCollision &coll
 ) {
        candidates.clear();
 
@@ -73,37 +71,30 @@ bool World::Intersection(
 
        if (candidates.empty()) return false;
 
-       chunk = nullptr;
-       dist = std::numeric_limits<float>::infinity();
-       blkid = -1;
+       coll.chunk = nullptr;
+       coll.block = -1;
+       coll.depth = std::numeric_limits<float>::infinity();
 
        for (Candidate &cand : candidates) {
-               if (cand.dist > dist) continue;
-               int cur_blkid;
-               float cur_dist;
-               glm::vec3 cur_normal;
-               if (cand.chunk->Intersection(ray, M * cand.chunk->Transform(player->ChunkCoords()), cur_blkid, cur_dist, cur_normal)) {
-                       if (cur_dist < dist) {
-                               chunk = cand.chunk;
-                               blkid = cur_blkid;
-                               dist = cur_dist;
-                               normal = cur_normal;
+               if (cand.dist > coll.depth) continue;
+               WorldCollision cur_coll;
+               if (cand.chunk->Intersection(ray, M * cand.chunk->Transform(player->ChunkCoords()), cur_coll)) {
+                       if (cur_coll.depth < coll.depth) {
+                               coll = cur_coll;
                        }
                }
        }
 
-       return chunk;
+       return coll.chunk;
 }
 
 bool World::Intersection(
        const Ray &ray,
        const glm::mat4 &M,
-       Entity *&entity,
-       float &dist,
-       glm::vec3 &normal
+       EntityCollision &coll
 ) {
-       entity = nullptr;
-       dist = std::numeric_limits<float>::infinity();
+       coll.entity = nullptr;
+       coll.depth = std::numeric_limits<float>::infinity();
        for (Entity &cur_entity : entities) {
                // TODO: better check for skipping self (because the check might not be for the player)
                if (&cur_entity == player) {
@@ -113,15 +104,15 @@ bool World::Intersection(
                glm::vec3 cur_normal;
                if (blank::Intersection(ray, cur_entity.Bounds(), M * cur_entity.Transform(player->ChunkCoords()), &cur_dist, &cur_normal)) {
                        // TODO: fine grained check goes here? maybe?
-                       if (cur_dist < dist) {
-                               entity = &cur_entity;
-                               dist = cur_dist;
-                               normal = cur_normal;
+                       if (cur_dist < coll.depth) {
+                               coll.entity = &cur_entity;
+                               coll.depth = cur_dist;
+                               coll.normal = cur_normal;
                        }
                }
        }
 
-       return entity;
+       return coll.entity;
 }
 
 bool World::Intersection(const Entity &e, std::vector<WorldCollision> &col) {
index 6d27d12b8ab97f03fc6ef05688ae771a4348ccdd..a1385138edd5fa135d84dba21025b2f4253f9e8b 100644 (file)
@@ -15,6 +15,7 @@
 namespace blank {
 
 class Assets;
+class EntityCollision;
 class Viewport;
 class WorldCollision;
 
@@ -38,23 +39,21 @@ public:
 
        World(const Assets &, const Config &, const WorldSave &);
 
-       // check if this ray hits a block
+       /// check if this ray hits a block
+       /// depth in the collision is the distance between the ray's
+       /// origin and the intersection point
        bool Intersection(
                const Ray &,
                const glm::mat4 &M,
-               Chunk *&chunk,
-               int &blkid,
-               float &dist,
-               glm::vec3 &normal);
+               WorldCollision &);
 
-       // check if this ray hits an entity
+       /// check if this ray hits an entity
        bool Intersection(
                const Ray &,
                const glm::mat4 &M,
-               Entity *&entity,
-               float &dist,
-               glm::vec3 &normal);
+               EntityCollision &);
 
+       /// check if given entity intersects with the world
        bool Intersection(const Entity &e, std::vector<WorldCollision> &);
        void Resolve(Entity &e, std::vector<WorldCollision> &);
 
index ebf01c17cd0362bfda3f1ba15f674367b8205bc2..3c81595b714d9bd94104048633950a98da9a4a1a 100644 (file)
@@ -11,18 +11,33 @@ namespace blank {
 
 struct WorldCollision {
 
-       const Chunk *chunk;
+       Chunk *chunk;
        int block;
 
        float depth;
        glm::vec3 normal;
 
-       WorldCollision(const Chunk *c, int b, float d, const glm::vec3 &n)
+       WorldCollision()
+       : chunk(nullptr), block(-1), depth(0.0f), normal(0.0f) { }
+       WorldCollision(Chunk *c, int b, float d, const glm::vec3 &n)
        : chunk(c), block(b), depth(d), normal(n) { }
 
+       /// check if an actual collision
+       operator bool() const noexcept { return chunk; }
+
+       // following only valid if test true
+       Chunk &GetChunk() noexcept { return *chunk; }
+       const Chunk &GetChunk() const noexcept { return *chunk; }
+       const Block &GetBlock() const noexcept { return GetChunk().BlockAt(block); }
+       const BlockType &GetType() const noexcept { return GetChunk().Type(GetBlock()); }
+
+       void SetBlock(const Block &b) noexcept { GetChunk().SetBlock(block, b); }
+
        bool Blocks() const noexcept { return chunk->Type(block).collide_block; }
 
+       glm::vec3 BlockPos() const noexcept { return Chunk::ToPos(block); }
        glm::vec3 BlockCoords() const noexcept { return Chunk::ToCoords(block); }
+       glm::mat4 BlockTransform() const noexcept { return GetChunk().ToTransform(BlockPos(), block); }
 
 };
 
index a6decf70906408558fc68f08a790da5225c126b8..83c94e3403a14ddd97283739dfe34e0e50fa9696 100644 (file)
@@ -440,13 +440,12 @@ void Chunk::Draw() noexcept {
 bool Chunk::Intersection(
        const Ray &ray,
        const glm::mat4 &M,
-       int &blkid,
-       float &dist,
-       glm::vec3 &normal
-) const noexcept {
+       WorldCollision &coll
+) noexcept {
        int idx = 0;
-       blkid = -1;
-       dist = std::numeric_limits<float>::infinity();
+       coll.chunk = this;
+       coll.block = -1;
+       coll.depth = std::numeric_limits<float>::infinity();
        for (int z = 0; z < depth; ++z) {
                for (int y = 0; y < height; ++y) {
                        for (int x = 0; x < width; ++x, ++idx) {
@@ -457,20 +456,20 @@ bool Chunk::Intersection(
                                float cur_dist;
                                glm::vec3 cur_norm;
                                if (type.shape->Intersects(ray, M * ToTransform(Pos(x, y, z), idx), cur_dist, cur_norm)) {
-                                       if (cur_dist < dist) {
-                                               blkid = idx;
-                                               dist = cur_dist;
-                                               normal = cur_norm;
+                                       if (cur_dist < coll.depth) {
+                                               coll.block = idx;
+                                               coll.depth = cur_dist;
+                                               coll.normal = cur_norm;
                                        }
                                }
                        }
                }
        }
 
-       if (blkid < 0) {
+       if (coll.block < 0) {
                return false;
        } else {
-               normal = glm::vec3(BlockAt(blkid).Transform() * glm::vec4(normal, 0.0f));
+               coll.normal = glm::vec3(BlockAt(coll.block).Transform() * glm::vec4(coll.normal, 0.0f));
                return true;
        }
 }
@@ -480,7 +479,7 @@ bool Chunk::Intersection(
        const glm::mat4 &Mbox,
        const glm::mat4 &Mchunk,
        std::vector<WorldCollision> &col
-) const noexcept {
+) noexcept {
        bool any = false;
        float penetration;
        glm::vec3 normal;