From 8881c507009521d08648560984c0f50166224542 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Tue, 24 Feb 2015 08:47:09 +0100 Subject: [PATCH] place and remove blocks via mouse --- src/app.cpp | 44 +++++++++++++++++++++++-- src/app.hpp | 4 +++ src/geometry.cpp | 83 ++++++++++++++++++++++++++++++++---------------- src/geometry.hpp | 7 +++- src/world.cpp | 17 ++++++++-- src/world.hpp | 15 ++++++--- 6 files changed, 132 insertions(+), 38 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 5a5d6fb..9ec9384 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -41,7 +41,12 @@ Application::Application() , left(false) , right(false) , up(false) -, down(false) { +, down(false) +, place(false) +, remove(false) +, pick(false) +, remove_id(0) +, place_id(1) { GLContext::EnableVSync(); GLContext::EnableDepthTest(); GLContext::EnableBackfaceCulling(); @@ -210,6 +215,18 @@ void Application::HandleEvents() { break; } break; + case SDL_MOUSEBUTTONDOWN: + if (event.button.button == 1) { + // left + remove = true; + } else if (event.button.button == 2) { + // middle + pick = true; + } else if (event.button.button == 3) { + // right + place = true; + } + break; case SDL_MOUSEMOTION: cam.RotateYaw(event.motion.xrel * yaw_sensitivity); cam.RotatePitch(event.motion.yrel * pitch_sensitivity); @@ -256,13 +273,36 @@ void Application::Update(int dt) { Ray aim = cam.Aim(); int blkid; float dist; - if (chunk.Intersection(aim, glm::mat4(1.0f), &blkid, &dist)) { + glm::vec3 normal; + if (chunk.Intersection(aim, glm::mat4(1.0f), &blkid, &dist, &normal)) { glm::vec3 pos = Chunk::ToCoords(blkid); outline_visible = true; outline_transform = glm::translate(glm::mat4(1.0f), pos); } else { outline_visible = false; } + + if (pick) { + if (outline_visible) { + place_id = chunk.BlockAt(blkid).type->id; + } + pick = false; + } + if (remove) { + chunk.BlockAt(blkid).type = blockType[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(); + } + } + place = false; + } } void Application::Render() { diff --git a/src/app.hpp b/src/app.hpp index 0015403..28c7536 100644 --- a/src/app.hpp +++ b/src/app.hpp @@ -66,6 +66,10 @@ private: bool running; bool front, back, left, right, up, down; + bool place, remove, pick; + + int remove_id; + int place_id; }; diff --git a/src/geometry.cpp b/src/geometry.cpp index c5f8069..df48ad3 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -1,31 +1,43 @@ #include "geometry.hpp" +#include + namespace blank { -bool Intersection(const Ray &ray, const AABB &aabb, const glm::mat4 &M, float *dist) { +bool Intersection( + const Ray &ray, + const AABB &aabb, + const glm::mat4 &M, + float *dist, + glm::vec3 *normal +) { float t_min = 0.0f; float t_max = 1.0e5f; const glm::vec3 aabb_pos(M[3].x, M[3].y, M[3].z); const glm::vec3 delta = aabb_pos - ray.orig; + glm::vec3 t1(t_min, t_min, t_min), t2(t_max, t_max, t_max); + bool x_swap = false, y_swap = false, z_swap = false; + { // X const glm::vec3 xaxis(M[0].x, M[0].y, M[0].z); const float e = glm::dot(xaxis, delta); const float f = glm::dot(ray.dir, xaxis); - if (std::abs(f) > 0.001f) { - float t1 = (e + aabb.min.x) / f; - float t2 = (e + aabb.max.x) / f; + if (std::abs(f) > std::numeric_limits::epsilon()) { + t1.x = (e + aabb.min.x) / f; + t2.x = (e + aabb.max.x) / f; - if (t1 > t2) { - std::swap(t1, t2); + if (t1.x > t2.x) { + std::swap(t1.x, t2.x); + x_swap = true; } - if (t1 > t_min) { - t_min = t1; + if (t1.x > t_min) { + t_min = t1.x; } - if (t2 < t_max) { - t_max = t2; + if (t2.x < t_max) { + t_max = t2.x; } if (t_max < t_min) { return false; @@ -42,18 +54,19 @@ bool Intersection(const Ray &ray, const AABB &aabb, const glm::mat4 &M, float *d const float e = glm::dot(yaxis, delta); const float f = glm::dot(ray.dir, yaxis); - if (std::abs(f) > 0.001f) { - float t1 = (e + aabb.min.y) / f; - float t2 = (e + aabb.max.y) / f; + if (std::abs(f) > std::numeric_limits::epsilon()) { + t1.y = (e + aabb.min.y) / f; + t2.y = (e + aabb.max.y) / f; - if (t1 > t2) { - std::swap(t1, t2); + if (t1.y > t2.y) { + std::swap(t1.y, t2.y); + y_swap = true; } - if (t1 > t_min) { - t_min = t1; + if (t1.y > t_min) { + t_min = t1.y; } - if (t2 < t_max) { - t_max = t2; + if (t2.y < t_max) { + t_max = t2.y; } if (t_max < t_min) { return false; @@ -70,18 +83,19 @@ bool Intersection(const Ray &ray, const AABB &aabb, const glm::mat4 &M, float *d const float e = glm::dot(zaxis, delta); const float f = glm::dot(ray.dir, zaxis); - if (std::abs(f) > 0.001f) { - float t1 = (e + aabb.min.z) / f; - float t2 = (e + aabb.max.z) / f; + if (std::abs(f) > std::numeric_limits::epsilon()) { + t1.z = (e + aabb.min.z) / f; + t2.z = (e + aabb.max.z) / f; - if (t1 > t2) { - std::swap(t1, t2); + if (t1.z > t2.z) { + std::swap(t1.z, t2.z); + z_swap = true; } - if (t1 > t_min) { - t_min = t1; + if (t1.z > t_min) { + t_min = t1.z; } - if (t2 < t_max) { - t_max = t2; + if (t2.z < t_max) { + t_max = t2.z; } if (t_max < t_min) { return false; @@ -96,6 +110,19 @@ bool Intersection(const Ray &ray, const AABB &aabb, const glm::mat4 &M, float *d if (dist) { *dist = t_min; } + if (normal) { + if (t1.x > t1.y) { + if (t1.x > t1.z) { + *normal = glm::vec3(x_swap ? 1 : -1, 0, 0); + } else { + *normal = glm::vec3(0, 0, z_swap ? 1 : -1); + } + } else if (t1.y > t1.z) { + *normal = glm::vec3(0, y_swap ? 1 : -1, 0); + } else { + *normal = glm::vec3(0, 0, z_swap ? 1 : -1); + } + } return true; } diff --git a/src/geometry.hpp b/src/geometry.hpp index e8ead98..bcc9c9a 100644 --- a/src/geometry.hpp +++ b/src/geometry.hpp @@ -23,7 +23,12 @@ struct Ray { glm::vec3 dir; }; -bool Intersection(const Ray &, const AABB &, const glm::mat4 &M, float *dist = nullptr); +bool Intersection( + const Ray &, + const AABB &, + const glm::mat4 &M, + float *dist = nullptr, + glm::vec3 *normal = nullptr); } diff --git a/src/world.cpp b/src/world.cpp index c958a65..e3c10b1 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -89,7 +89,12 @@ void Chunk::Draw() { } -bool Chunk::Intersection(const Ray &ray, const glm::mat4 &M, int *blkid, float *dist) const { +bool Chunk::Intersection( + const Ray &ray, + const glm::mat4 &M, + int *blkid, + float *dist, + glm::vec3 *normal) const { { // rough check const AABB bb{{0, 0, 0}, {Width(), Height(), Depth()}}; if (!blank::Intersection(ray, bb, M)) { @@ -97,7 +102,7 @@ bool Chunk::Intersection(const Ray &ray, const glm::mat4 &M, int *blkid, float * } } - if (!blkid && !dist) { + if (!blkid && !dist && !normal) { return true; } @@ -105,6 +110,7 @@ bool Chunk::Intersection(const Ray &ray, const glm::mat4 &M, int *blkid, float * int id = 0; int closest_id = -1; float closest_dist = std::numeric_limits::infinity(); + glm::vec3 closest_normal(0, 1, 0); for (int z = 0; z < Depth(); ++z) { for (int y = 0; y < Height(); ++y) { for (int x = 0; x < Width(); ++x, ++id) { @@ -113,10 +119,12 @@ bool Chunk::Intersection(const Ray &ray, const glm::mat4 &M, int *blkid, float * } const AABB bb{{x, y, z}, {x+1, y+1, z+1}}; float cur_dist; - if (blank::Intersection(ray, bb, M, &cur_dist)) { + glm::vec3 cur_norm; + if (blank::Intersection(ray, bb, M, &cur_dist, &cur_norm)) { if (cur_dist < closest_dist) { closest_id = id; closest_dist = cur_dist; + closest_normal = cur_norm; } } } @@ -133,6 +141,9 @@ bool Chunk::Intersection(const Ray &ray, const glm::mat4 &M, int *blkid, float * if (dist) { *dist = closest_dist; } + if (normal) { + *normal = closest_normal; + } return true; } diff --git a/src/world.hpp b/src/world.hpp index b7ed84b..67ee355 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -93,10 +93,17 @@ public: void Invalidate() { dirty = true; } - Block &BlockAt(const glm::vec3 &pos) { return blocks[ToIndex(pos)]; } - const Block &BlockAt(const glm::vec3 &pos) const { return blocks[ToIndex(pos)]; } - - bool Intersection(const Ray &, const glm::mat4 &M, int *blkid = nullptr, float *dist = nullptr) const; + Block &BlockAt(int index) { return blocks[index]; } + const Block &BlockAt(int index) const { return blocks[index]; } + Block &BlockAt(const glm::vec3 &pos) { return BlockAt(ToIndex(pos)); } + const Block &BlockAt(const glm::vec3 &pos) const { return BlockAt(ToIndex(pos)); } + + bool Intersection( + const Ray &, + const glm::mat4 &M, + int *blkid = nullptr, + float *dist = nullptr, + glm::vec3 *normal = nullptr) const; void Draw(); -- 2.39.2