summaryrefslogtreecommitdiff
path: root/src/Entities
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2024-02-06 02:09:17 +0100
committerMel <einebeere@gmail.com>2024-02-06 02:09:17 +0100
commitc61e09ce986fa99debea040a7c0ac42749ad8052 (patch)
tree177b39f7f692723cb4ace8392349f3f8f0d2192b /src/Entities
parent091bf9e418ffdcf36e1735ed78d544f3d1b86785 (diff)
downloadmeowcraft-c61e09ce986fa99debea040a7c0ac42749ad8052.tar.zst
meowcraft-c61e09ce986fa99debea040a7c0ac42749ad8052.zip
Render outlines on currently targeted blocks
Diffstat (limited to 'src/Entities')
-rw-r--r--src/Entities/Player.cpp107
-rw-r--r--src/Entities/Player.hpp24
2 files changed, 118 insertions, 13 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;
};
}