diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Entities/Player.cpp | 107 | ||||
| -rw-r--r-- | src/Entities/Player.hpp | 24 | ||||
| -rw-r--r-- | src/GFX/Util/MeshBuilder.hpp | 4 | ||||
| -rw-r--r-- | src/GFX/Util/Primitives.cpp | 26 | ||||
| -rw-r--r-- | src/GFX/Util/Primitives.hpp | 14 | ||||
| -rw-r--r-- | src/Math/Grid.cpp | 36 | ||||
| -rw-r--r-- | src/Math/Grid.hpp | 6 | ||||
| -rw-r--r-- | src/Math/Perlin.cpp | 8 |
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; |
