diff --git a/libbettola/include/bettola/math/vec3.h b/libbettola/include/bettola/math/vec3.h index 1b7b419..3e99c5e 100644 --- a/libbettola/include/bettola/math/vec3.h +++ b/libbettola/include/bettola/math/vec3.h @@ -6,4 +6,8 @@ struct Vec3 { float x, y , z; }; +inline Vec3 operator+(const Vec3& a, const Vec3& b) { + return {a.x + b.x, a.y + b.y, a.z + b.z}; +} + } /* namespace BettolaMath. */ diff --git a/src/bettola.cpp b/src/bettola.cpp index b24c892..f93b142 100644 --- a/src/bettola.cpp +++ b/src/bettola.cpp @@ -2,6 +2,8 @@ #include /* FINE LSP!! I'll play your games!!!! */ #include /* ~HJAPPY?!?!?! */ +#include +#include #include #include #include @@ -10,6 +12,7 @@ #include #include #include +#include "game/player.h" #include "bettola.h" @@ -78,6 +81,11 @@ void Bettola::process_events(void) { while(SDL_PollEvent(&event)) { if(event.type == SDL_EVENT_QUIT) { _is_running = false; + } else if(event.type == SDL_EVENT_MOUSE_MOTION) { + /* Y is inverted. */ + _camera.process_mouse_movement((float)event.motion.xrel, (float)-event.motion.yrel); + } else if(event.type == SDL_EVENT_MOUSE_WHEEL) { + _camera.process_mouse_scroll((float)event.wheel.y); } else if(event.type == SDL_EVENT_KEY_DOWN) { switch(event.key.key) { case SDLK_W: _input.up = true; break; @@ -102,6 +110,11 @@ void Bettola::update(double dt) { float dir_y = (_input.down ? 1.0f : 0.0f) - (_input.up ? 1.0f : 0.0f); _game_client.get_player_for_write().set_velocity_direction(dir_x, dir_y); + /* Update camera to follow the player. */ + const auto& player = _game_client.get_player(); + BettolaMath::Vec3 player_pos = { player.get_x(), 0.0f, player.get_y() }; + _camera.update(player_pos); + /* Process network messages and send input to the server. */ _game_client.process_network_messages(); _game_client.send_input(_input, dt); @@ -111,13 +124,15 @@ void Bettola::update(double dt) { } void Bettola::render(void) { - _renderer.render(_game_client.get_player(), _game_client.get_remote_players()); + _renderer.render(_camera.get_view_matrix(), _game_client.get_player(), + _game_client.get_remote_players()); SDL_GL_SwapWindow(_window); } bool Bettola::create_window(void) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); /* Don't you dare f.ckin fail to open!!!!! */ @@ -129,6 +144,9 @@ bool Bettola::create_window(void) { return false; } + /* Capture mouse cursor. */ + SDL_SetWindowRelativeMouseMode(_window, true); + return true; } diff --git a/src/bettola.h b/src/bettola.h index e7fed76..1a70d04 100644 --- a/src/bettola.h +++ b/src/bettola.h @@ -4,6 +4,7 @@ #include #include "graphics/renderer.h" +#include "graphics/camera.h" #include "game_client.h" class Bettola { @@ -29,5 +30,6 @@ private: Renderer _renderer; GameClient _game_client; + Camera _camera; Player::InputState _input; }; diff --git a/src/graphics/camera.cpp b/src/graphics/camera.cpp new file mode 100644 index 0000000..d8e0748 --- /dev/null +++ b/src/graphics/camera.cpp @@ -0,0 +1,76 @@ +#include +#include "math/mat4.h" +#include "math/vec3.h" +#include "camera.h" + + +Camera::Camera(void) : + _position({0.0f, 0.0f, 0.0f}), + _front({0.0f, 0.0f, -1.0f}), + _up({0.0f, 1.0f, 0.0f}), + _right({0.0f, 0.0f, 0.0f}), + _world_up({0.0f, 1.0f, -1.0f}), + _yaw(-90.0f), + _pitch(0.0f), + _distance(10.0f), + _mouse_sensitivity(0.1f), + _zoom_sensitivity(0.5f) { + + _update_camera_vectors(); +} + +void Camera::update(const BettolaMath::Vec3& target_pos) { + _position.x = target_pos.x - _front.x * _distance; + _position.y = target_pos.y - _front.y * _distance; + _position.z = target_pos.z - _front.z * _distance; +} + +void Camera::process_mouse_movement(float x_offset, float y_offset) { + _yaw += x_offset * _mouse_sensitivity; + _pitch += y_offset * _mouse_sensitivity; + + /* Constrain pitch. */ + if(_pitch > 89.0f) _pitch = 89.0f; + if(_pitch < -89.0f) _pitch = -89.0f; + + _update_camera_vectors(); +} + +void Camera::process_mouse_scroll(float y_offset) { + _distance -= y_offset * _zoom_sensitivity; + if(_distance < 2.0f) _distance = 2.0f; + if(_distance > 20.0f) _distance = 20.0f; +} + +BettolaMath::Mat4 Camera::get_view_matrix(void) const { + return BettolaMath::Mat4::look_at(_position, _position + _front, _up); +} + +void Camera::_update_camera_vectors(void) { + BettolaMath::Vec3 front; + float yaw_rad = _yaw*M_PI/180.0f; + float pitch_rad = _pitch*M_PI/180.0f; + + front.x = cos(yaw_rad) * cos(pitch_rad); + front.y = sin(pitch_rad); + front.z = sin(yaw_rad) * cos(pitch_rad); + + /* Normalise the front vector. */ + float f_mag = sqrt(front.x*front.x + front.y*front.y + front.z*front.z); + _front.x = front.x / f_mag; + _front.y = front.y / f_mag; + _front.z = front.z / f_mag; + + _right.x = _front.y * _world_up.z - _front.z * _world_up.y; + _right.y = _front.z * _world_up.x - _front.x * _world_up.z; + _right.z = _front.x * _world_up.y - _front.y * _world_up.x; + float r_mag = sqrt(_right.x*_right.x + _right.y*_right.y + _right.z*_right.z); + _right.x /= r_mag; _right.y /= r_mag; _right.z /= r_mag; + + /* Up vector. */ + _up.x = _right.y * _front.z - _right.z * _front.y; + _up.y = _right.z * _front.x - _right.x * _front.z; + _up.z = _right.x * _front.y - _right.y * _front.x; + +} + diff --git a/src/graphics/camera.h b/src/graphics/camera.h new file mode 100644 index 0000000..90f2d2a --- /dev/null +++ b/src/graphics/camera.h @@ -0,0 +1,32 @@ +#pragma once + +#include "math/mat4.h" +#include "math/vec3.h" + +class Camera { +public: + Camera(void); + + void update(const BettolaMath::Vec3& target_pos); + + void process_mouse_movement(float x_offset, float y_offset); + void process_mouse_scroll(float y_offset); + + BettolaMath::Mat4 get_view_matrix(void) const; +private: + void _update_camera_vectors(void); + + float _yaw; + float _pitch; + float _distance; + + BettolaMath::Vec3 _position; + BettolaMath::Vec3 _front; + BettolaMath::Vec3 _up; + BettolaMath::Vec3 _right; + BettolaMath::Vec3 _world_up; + + + float _mouse_sensitivity; + float _zoom_sensitivity; +}; diff --git a/src/graphics/renderer.cpp b/src/graphics/renderer.cpp index 247047b..f61cd93 100644 --- a/src/graphics/renderer.cpp +++ b/src/graphics/renderer.cpp @@ -1,6 +1,7 @@ #include #include #include +#include "game/player.h" #include #ifndef M_PI @@ -134,7 +135,8 @@ bool Renderer::init(int screen_width, int screen_height) { return true; } -void Renderer::render(const Player& player, const std::vector& remote_players) { +void Renderer::render(const BettolaMath::Mat4& view_matrix, const Player& player, + const std::vector& remote_players) { glClearColor(0.1f, 0.1f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* Need to clear depth buffer too. */ GL_CHECK_ERROR(); @@ -142,11 +144,6 @@ void Renderer::render(const Player& player, const std::vector& rem _shader.use(); GL_CHECK_ERROR(); - /* Make the camera stalk the player. */ - BettolaMath::Vec3 camera_pos = { player.get_x(), 5.0f, player.get_y() + 8.0f }; - BettolaMath::Vec3 player_pos = { player.get_x(), 0.0f, player.get_y() }; - BettolaMath::Mat4 view = BettolaMath::Mat4::look_at(camera_pos, player_pos, {0.0f,1.0f,0.0f}); - BettolaMath::Mat4 projection = BettolaMath::Mat4::perspective((45.0f * M_PI) / 180.0f, 800.0f/600.0f, 0.1f, 100.0f); GLint view_loc = glGetUniformLocation(_shader.get_id(), "view"); @@ -154,7 +151,7 @@ void Renderer::render(const Player& player, const std::vector& rem GLint model_loc = glGetUniformLocation(_shader.get_id(), "model"); GLint color_loc = glGetUniformLocation(_shader.get_id(), "overrideColor"); - glUniformMatrix4fv(view_loc, 1, GL_FALSE, view.get_ptr()); + glUniformMatrix4fv(view_loc, 1, GL_FALSE, view_matrix.get_ptr()); GL_CHECK_ERROR(); glUniformMatrix4fv(proj_loc, 1, GL_FALSE, projection.get_ptr()); GL_CHECK_ERROR(); diff --git a/src/graphics/renderer.h b/src/graphics/renderer.h index ab11a19..8f668cd 100644 --- a/src/graphics/renderer.h +++ b/src/graphics/renderer.h @@ -12,7 +12,8 @@ public: ~Renderer(void); bool init(int screen_width, int screen_height); - void render(const Player& player, const std::vector& remote_players); + void render(const BettolaMath::Mat4& view_matrix, const Player& player, + const std::vector& remote_players); private: bool _init_shaders();