summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Entities/Player.cpp107
-rw-r--r--src/Entities/Player.hpp24
-rw-r--r--src/GFX/Util/MeshBuilder.hpp4
-rw-r--r--src/GFX/Util/Primitives.cpp26
-rw-r--r--src/GFX/Util/Primitives.hpp14
-rw-r--r--src/Math/Grid.cpp36
-rw-r--r--src/Math/Grid.hpp6
-rw-r--r--src/Math/Perlin.cpp8
8 files changed, 187 insertions, 38 deletions
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index ae82e83..e9b183f 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -1,8 +1,29 @@
 #include "Player.hpp"
 #include "../Common/Casts.hpp"
+#include "../Math/MVP.hpp"
 #include <unordered_set>
 
 namespace MC::Entities {
+Player::Player(Position::World position, Real ascept, Real fov, Real near, Real far)
+    : m_transform(position),
+    m_outline_program(
+        {GFX::Shading::Shader::Type::Vertex, outline_vertex},
+        {GFX::Shading::Shader::Type::Fragment, outline_fragment}
+    ),
+    m_outline_mesh(create_outline_cube_mesh()),
+    m_outline_model_uniform(), m_outline_view_uniform(), m_outline_projection_uniform() {
+    m_outline_program.bind();
+
+    m_outline_model_uniform = m_outline_program.uniform("model_matrix");
+    m_outline_view_uniform = m_outline_program.uniform("view_matrix");
+    m_outline_projection_uniform = m_outline_program.uniform("projection_matrix");
+
+    m_outline_model_uniform.set(Math::MVP::model<F32>({}, {}, {}));
+    m_outline_view_uniform.set(Math::MVP::view<F32>({}, {}));
+    m_outline_projection_uniform.set(Math::MVP::perspective_projection<F32>(ascept, fov, near, far));
+
+    m_outline_program.unbind();
+}
 
 void Player::update(const Time& time, GFX::Window& window, GFX::Camera& camera, World::World& world) {
     auto const input_direction = directional_input(window);
@@ -26,9 +47,31 @@ void Player::update(const Time& time, GFX::Window& window, GFX::Camera& camera,
 
     update_camera_position(camera);
 
+    update_targeted_block(world);
     actions(window, world);
 }
 
+// TODO: Proof-of-concept, will all be moved to the rendering system.
+void Player::render(const GFX::Camera& camera) {
+    // Render currently targeted block outline.
+
+    if (m_targeted_block.has_value()) {
+        auto targeted_block = m_targeted_block.value();
+
+        m_outline_program.bind();
+
+        m_outline_view_uniform.set(Math::MVP::view<F32>(camera.position(), camera.angles()));
+        m_outline_model_uniform.set(Math::MVP::model<F32>(Vec3(targeted_block.position), Vec3::one(), {}));
+
+        m_outline_mesh.bind();
+        // TODO: These are very thin lines, do we have any better easy options?
+        glDrawElements(GL_LINES, m_outline_mesh.size(), GL_UNSIGNED_INT, nullptr);
+        m_outline_mesh.unbind();
+
+        m_outline_program.unbind();
+    }
+}
+
 void Player::move(Position::WorldOffset by) {
     m_transform.position() += by;
 }
@@ -120,26 +163,32 @@ Vec3 Player::noclip_velocity(GFX::Window& window, const Time& time, Vec3 input_d
     return direction * (base_move_speed + boost) * time.delta();
 }
 
-void Player::actions(GFX::Window& window, World::World& world) {
+void Player::update_targeted_block(World::World& world) {
     auto constexpr max_block_reach = 4.0;
 
+    auto const look_transform = camera_transform();
+    Ray const ray{look_transform.position(), -look_transform.forward()};
+    auto const traversal = world.traverse(
+        ray,
+        [](auto b) { return b.type.is_solid(); },
+        max_block_reach
+    );
+
+    if (traversal.hit) m_targeted_block = {traversal.block, traversal.normal};
+    else m_targeted_block = {};
+}
+
+void Player::actions(GFX::Window& window, World::World& world) {
     // Breaking and placing blocks.
     auto left_click = window.mouse(GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS);
     auto right_click = window.mouse(GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS);
     if (left_click || right_click) {
-        auto const look_transform = camera_transform();
-        Ray const ray{look_transform.position(), -look_transform.forward()};
-        auto const traversal = world.traverse(
-            ray,
-            [](auto b) { return b.type.is_solid(); },
-            max_block_reach
-        );
-
-        if (traversal.hit) {
+        if (m_targeted_block.has_value()) {
+            auto targeted_block = m_targeted_block.value();
             if (left_click) {
-                world.break_block(traversal.block);
+                world.break_block(targeted_block.position);
             } else {
-                auto const new_block = Position::BlockWorld(traversal.block + traversal.normal);
+                auto const new_block = Position::BlockWorld(targeted_block.position + targeted_block.normal);
                 auto const current_box = bounding_box_for_position(m_transform.position());
                 auto const block_box = World::Chunk::block_bounds(new_block);
 
@@ -315,4 +364,38 @@ Position::World Player::position_for_bounding_box(AABB box) {
     return {center.x(), box.min.y(), center.z()};
 }
 
+GFX::Mesh Player::create_outline_cube_mesh() {
+    GFX::Util::MeshBuilder<Vector<3, F32>> builder{};
+    auto slightly_bigger_block_bounds = AABB{{1, 1, 1}}.sum(AABB{{0.01, 0.01, 0.01}});
+    builder.primitive(GFX::Util::Primitives::line_box(slightly_bigger_block_bounds));
+    return builder.mesh();
+}
+
+const Char* Player::outline_vertex = R"v(
+#version 330 core
+
+uniform mat4 model_matrix;
+uniform mat4 view_matrix;
+uniform mat4 projection_matrix;
+
+layout (location = 0) in vec3 position;
+
+void main() {
+    vec4 world_position = model_matrix * vec4(position, 1.0);
+    vec4 view_position = view_matrix * world_position;
+    vec4 clip_position = projection_matrix * view_position;
+
+    gl_Position = clip_position;
+}
+)v";
+
+const Char* Player::outline_fragment = R"f(
+#version 330 core
+
+out vec4 color;
+
+void main() {
+    color = vec4(0.0, 0.0, 0.0, 1.0);
+}
+)f";
 }
diff --git a/src/Entities/Player.hpp b/src/Entities/Player.hpp
index c8a1c1f..c829d1f 100644
--- a/src/Entities/Player.hpp
+++ b/src/Entities/Player.hpp
@@ -5,6 +5,7 @@
 #include "../GFX/Camera.hpp"
 #include "../World/World.hpp"
 #include "../GFX/Window.hpp"
+#include "../GFX/Shading/Program.hpp"
 #include "../Math/AABB.hpp"
 #include "../Math/Rotation.hpp"
 #include "../World/Position.hpp"
@@ -12,9 +13,10 @@
 namespace MC::Entities {
 class Player {
 public:
-    explicit Player(Position::World position) : m_transform(position) {}
+    explicit Player(Position::World position, Real ascept, Real fov, Real near, Real far);
 
     void update(const Time& time, GFX::Window& window, GFX::Camera& camera, World::World& world);
+    void render(const GFX::Camera& camera);
 
     void move(Position::WorldOffset by);
     void move_to(Position::World to);
@@ -43,6 +45,7 @@ private:
     Vec3 flying_velocity(GFX::Window& window, const Time& time, Vec3 input_direction);
     Vec3 noclip_velocity(GFX::Window& window, const Time& time, Vec3 input_direction);
 
+    void update_targeted_block(World::World& world);
     void actions(GFX::Window& window, World::World& world);
 
     Transform camera_transform() const;
@@ -56,6 +59,8 @@ private:
     // Returns position of the center of the bottom face of `box`.
     static Position::World position_for_bounding_box(AABB box);
 
+    static GFX::Mesh create_outline_cube_mesh();
+
     enum class MovementMode {
         // Gravity, collision, and normal movement
         Walking,
@@ -68,9 +73,26 @@ private:
     MovementMode m_movement = MovementMode::Walking;
     Bool m_on_ground = false;
 
+    struct TargetedBlock {
+        Position::BlockWorld position;
+        Position::BlockWorldOffset normal;
+    };
+    std::optional<TargetedBlock> m_targeted_block;
+
     Vec3 m_velocity{};
     Transform m_transform;
     static inline AABB s_bounds{{0.35, 1.8, 0.35}};
+
+    // TODO: Put this into the rendering system
+    static const Char* outline_vertex;
+    static const Char* outline_fragment;
+
+    GFX::Shading::Program m_outline_program;
+    GFX::Mesh m_outline_mesh;
+
+    GFX::Shading::Uniform m_outline_model_uniform;
+    GFX::Shading::Uniform m_outline_view_uniform;
+    GFX::Shading::Uniform m_outline_projection_uniform;
 };
 
 }
diff --git a/src/GFX/Util/MeshBuilder.hpp b/src/GFX/Util/MeshBuilder.hpp
index cab06e1..eec77dd 100644
--- a/src/GFX/Util/MeshBuilder.hpp
+++ b/src/GFX/Util/MeshBuilder.hpp
@@ -55,8 +55,8 @@ public:
         m_indices.insert(m_indices.end(), from.begin(), from.end());
     }
 
-    template<uint PN>
-    void primitive(const Primitives::Primitive<PN>& primitive) {
+    template<uint PN, uint PI>
+    void primitive(const Primitives::BasePrimitive<PN, PI>& primitive) {
         decltype(primitive.indices) relativized_indices{};
         for (Int i = 0; i < primitive.indices.size(); i++) {
             relativized_indices[i] = primitive.indices[i] + m_positions.size();
diff --git a/src/GFX/Util/Primitives.cpp b/src/GFX/Util/Primitives.cpp
index 4b44864..daceb79 100644
--- a/src/GFX/Util/Primitives.cpp
+++ b/src/GFX/Util/Primitives.cpp
@@ -1,4 +1,5 @@
 #include "Primitives.hpp"
+#include "../../Math/Grid.hpp"
 
 namespace MC::GFX::Util::Primitives {
 
@@ -104,4 +105,27 @@ BoxPrimitive box(AABB aabb, FaceSet faces) {
     return box;
 }
 
-}
\ No newline at end of file
+LineBoxPrimitive line_box(AABB aabb) {
+    auto [min, max] = aabb;
+
+    auto cube = Math::cube_cell_from_point(min, max - min);
+
+    using P = Vector<3, F32>;
+    decltype(LineBoxPrimitive::positions) positions = {{
+        P(cube.front_top_left()), P(cube.front_top_right()),
+        P(cube.front_bottom_left()), P(cube.front_bottom_right()),
+        P(cube.back_top_left()), P(cube.back_top_right()),
+        P(cube.back_bottom_left()), P(cube.back_bottom_right()),
+    }};
+
+    decltype(LineBoxPrimitive::indices) indices = {{
+        0, 1, 1, 3, 3, 2, 2, 0, // Front
+        4, 5, 5, 7, 7, 6, 6, 4, // Back
+        0, 4, 1, 5, 2, 6, 3, 7, // Sides
+    }};
+
+    // TODO: Allow Primitives to not have normals.
+    return {positions, {{}}, indices};
+}
+
+}
diff --git a/src/GFX/Util/Primitives.hpp b/src/GFX/Util/Primitives.hpp
index a267130..6654da6 100644
--- a/src/GFX/Util/Primitives.hpp
+++ b/src/GFX/Util/Primitives.hpp
@@ -31,17 +31,25 @@ private:
     Value m_set;
 };
 
-template <uint N>
-struct Primitive {
+// A base primitive, could represent lines, triangles, quads primitives, etc.
+template <uint N, uint I>
+struct BasePrimitive {
     std::array<Vector<3, F32>, N> positions;
     std::array<Vector<3, F32>, N> normals;
-    std::array<U32, N + N / 2> indices;
+    std::array<U32, I> indices;
 };
 
+// Primitive made out of triangles (GL_TRIANGLES)
+template <uint N>
+using Primitive = BasePrimitive<N, N + N / 2>;
+
 using PlanePrimitive = Primitive<4>;
 PlanePrimitive plane(AABB aabb, FaceSet face);
 
 using BoxPrimitive = Primitive<4 * 6>;
 BoxPrimitive box(AABB aabb, FaceSet faces = FaceSet::all());
 
+using LineBoxPrimitive = BasePrimitive<4 * 2, 4 * 6>;
+LineBoxPrimitive line_box(AABB aabb);
+
 }
diff --git a/src/Math/Grid.cpp b/src/Math/Grid.cpp
index 422cf87..de5fa69 100644
--- a/src/Math/Grid.cpp
+++ b/src/Math/Grid.cpp
@@ -1,12 +1,18 @@
 #include "Grid.hpp"
 
+#include "../Common/Lambda.hpp"
+
 namespace Math {
 
-GridCellBoundaries grid_cell_for_point(Vector<2> point) {
-    auto x1 = std::trunc(point.x());
-    auto y1 = std::trunc(point.y());
-    auto x2 = x1 + 1.0f;
-    auto y2 = y1 + 1.0f;
+GridCellBoundaries grid_cell_containing_point(Vec2 point, Vec2 cell_size) {
+    return grid_cell_from_point(point.map(LAMBDA(std::trunc, 1)), cell_size);
+}
+
+GridCellBoundaries grid_cell_from_point(Vec2 point, Vec2 cell_size) {
+    auto x1 = point.x();
+    auto y1 = point.y();
+    auto x2 = x1 + cell_size.x();
+    auto y2 = y1 + cell_size.y();
 
     return GridCellBoundaries{x1, x2, y1, y2};
 }
@@ -27,13 +33,17 @@ Vector<2> GridCellBoundaries::bottom_right() const {
     return {x2, y2};
 }
 
-CubeCellBoundaries cube_cell_for_point(Vector<3> point) {
-    auto x1 = std::trunc(point.x());
-    auto y1 = std::trunc(point.y());
-    auto z1 = std::trunc(point.z());
-    auto x2 = x1 + 1.0f;
-    auto y2 = y1 + 1.0f;
-    auto z2 = z1 + 1.0f;
+CubeCellBoundaries cube_cell_containing_point(Vec3 point, Vec3 cell_size) {
+    return cube_cell_from_point(point.map(LAMBDA(std::trunc, 1)), cell_size);
+}
+
+CubeCellBoundaries cube_cell_from_point(Vec3 point, Vec3 cell_size) {
+    auto x1 = point.x();
+    auto y1 = point.y();
+    auto z1 = point.z();
+    auto x2 = x1 + cell_size.x();
+    auto y2 = y1 + cell_size.y();
+    auto z2 = z1 + cell_size.z();
 
     return CubeCellBoundaries{x1, x2, y1, y2, z1, z2};
 }
@@ -74,4 +84,4 @@ GridCellBoundaries CubeCellBoundaries::grid_cell() const {
     return {x1, x2, y1, y2};
 }
 
-}
\ No newline at end of file
+}
diff --git a/src/Math/Grid.hpp b/src/Math/Grid.hpp
index 8c0c423..e2a5051 100644
--- a/src/Math/Grid.hpp
+++ b/src/Math/Grid.hpp
@@ -13,7 +13,8 @@ struct GridCellBoundaries {
     [[nodiscard]] Vector<2> bottom_right() const;
 };
 
-GridCellBoundaries grid_cell_for_point(Vector<2> point);
+GridCellBoundaries grid_cell_containing_point(Vec2 point, Vec2 cell_size = Vec2(1.0));
+GridCellBoundaries grid_cell_from_point(Vec2 point, Vec2 cell_size = Vec2(1.0));
 
 struct CubeCellBoundaries {
     Real x1, x2, y1, y2, z1, z2;
@@ -30,6 +31,7 @@ struct CubeCellBoundaries {
     [[nodiscard]] GridCellBoundaries grid_cell() const;
 };
 
-CubeCellBoundaries cube_cell_for_point(Vector<3> point);
+CubeCellBoundaries cube_cell_containing_point(Vec3 point, Vec3 cell_size = Vec3(1.0));
+CubeCellBoundaries cube_cell_from_point(Vec3 point, Vec3 cell_size = Vec3(1.0));
 
 }
\ No newline at end of file
diff --git a/src/Math/Perlin.cpp b/src/Math/Perlin.cpp
index 992a08e..9a1c9f8 100644
--- a/src/Math/Perlin.cpp
+++ b/src/Math/Perlin.cpp
@@ -24,10 +24,10 @@ Vector<2> gradient(Vector<2> pos) {
 }
 
 Real raw(Vector<2> pos) {
-    auto cell = grid_cell_for_point(pos);
+    auto cell = grid_cell_containing_point(pos);
     auto uv = pos - cell.top_left();
 
-    auto unit = grid_cell_for_point({});
+    auto unit = grid_cell_containing_point({});
     auto l11 = unit.top_left() - uv;
     auto l21 = unit.top_right() - uv;
     auto l12 = unit.bottom_left() - uv;
@@ -58,10 +58,10 @@ Vector<3> gradient(Vector<3> pos) {
 }
 
 Real raw(Vector<3> pos) {
-    auto cell = cube_cell_for_point(pos);
+    auto cell = cube_cell_containing_point(pos);
     auto uv = pos - cell.front_top_left();
 
-    auto unit = cube_cell_for_point({});
+    auto unit = cube_cell_containing_point({});
     auto l111 = unit.front_top_left() - uv;
     auto l211 = unit.front_top_right() - uv;
     auto l121 = unit.front_bottom_left() - uv;