diff --git a/copying.md b/copying.md index 1002c8321a..ec1ddd2a46 100644 --- a/copying.md +++ b/copying.md @@ -155,6 +155,7 @@ _the openage authors_ are: | Michael Seibt | RoboSchmied | github à roboschmie dawt de | | Nikhil Ghosh | NikhilGhosh75 | nghosh606 à gmail dawt com | | Edvin Lindholm | EdvinLndh | edvinlndh à gmail dawt com | +| Jeremiah Morgan | jere8184 | jeremiahmorgan dawt bham à outlook dawt com | If you're a first-time committer, add yourself to the above list. This is not just for legal reasons, but also to keep an overview of all those nicknames. diff --git a/libopenage/presenter/presenter.cpp b/libopenage/presenter/presenter.cpp index 33c798bcef..a37362be95 100644 --- a/libopenage/presenter/presenter.cpp +++ b/libopenage/presenter/presenter.cpp @@ -121,7 +121,17 @@ void Presenter::init_graphics(bool debug) { this->camera->resize(w, h); }); + // Camera manager this->camera_manager = std::make_shared(this->camera); + // TODO: Make boundaries dynamic based on map size. + this->camera_manager->set_camera_boundaries( + renderer::camera::CameraBoundaries{ + renderer::camera::X_BOUND_MIN, + renderer::camera::X_BOUND_MAX, + renderer::camera::Y_BOUND_MIN, + renderer::camera::Y_BOUND_MAX, + renderer::camera::Z_BOUND_MIN, + renderer::camera::Z_BOUND_MAX}); // Skybox this->skybox_renderer = std::make_shared( diff --git a/libopenage/renderer/camera/CMakeLists.txt b/libopenage/renderer/camera/CMakeLists.txt index aea6391e7a..71de5c7bd1 100644 --- a/libopenage/renderer/camera/CMakeLists.txt +++ b/libopenage/renderer/camera/CMakeLists.txt @@ -1,4 +1,5 @@ add_sources(libopenage + boundaries.cpp camera.cpp definitions.cpp frustum_2d.cpp diff --git a/libopenage/renderer/camera/boundaries.cpp b/libopenage/renderer/camera/boundaries.cpp new file mode 100644 index 0000000000..ca77344c7e --- /dev/null +++ b/libopenage/renderer/camera/boundaries.cpp @@ -0,0 +1,9 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + +#include "boundaries.h" + + +namespace openage::renderer::camera { + + +} // namespace openage::renderer::camera diff --git a/libopenage/renderer/camera/boundaries.h b/libopenage/renderer/camera/boundaries.h new file mode 100644 index 0000000000..484a398455 --- /dev/null +++ b/libopenage/renderer/camera/boundaries.h @@ -0,0 +1,25 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + +#pragma once + +namespace openage::renderer::camera { + +/** + * Defines boundaries for the camera's view. + */ +struct CameraBoundaries { + /// The minimum boundary for the camera's X-coordinate. + float x_min; + /// The maximum boundary for the camera's X-coordinate. + float x_max; + /// The minimum boundary for the camera's Y-coordinate. + float y_min; + /// The maximum boundary for the camera's Y-coordinate. + float y_max; + /// The minimum boundary for the camera's Z-coordinate. + float z_min; + /// The maximum boundary for the camera's Z-coordinate. + float z_max; +}; + +} // namespace openage::renderer::camera diff --git a/libopenage/renderer/camera/camera.cpp b/libopenage/renderer/camera/camera.cpp index f70efbee64..14504998e0 100644 --- a/libopenage/renderer/camera/camera.cpp +++ b/libopenage/renderer/camera/camera.cpp @@ -61,38 +61,7 @@ Camera::Camera(const std::shared_ptr &renderer, } void Camera::look_at_scene(Eigen::Vector3f scene_pos) { - if (scene_pos[1] > this->scene_pos[1]) { - // TODO: camera can't look at a position that's - // higher than it's own position - } - - // TODO: Although the below method should be faster, calculating and adding the direction - // vector from scene_pos to new_pos may be easier to understand - // i.e. new_pos = scene_pos + b/sin(30) * direction_vec - - // due to the fixed angle, the centered scene position - // and the new camera position form a right triangle. - // - // c - + new camera pos - // - |b - // center +------+ - // a - // - // we can calculate the new camera position via the offset a - // using the angle and length of side b. - auto y_delta = this->scene_pos[1] - scene_pos[1]; // b (vertical distance) - auto xz_distance = y_delta * std::numbers::sqrt3; // a (horizontal distance); a = b * (cos(30°) / sin(30°)) - - // get x and z offsets - // the camera is pointed diagonally to the negative x and z axis - // a is the length of the diagonal from camera.xz to scene_pos.xz - // so the x and z offest are sides of a square with the same diagonal - auto side_length = xz_distance / std::numbers::sqrt2; - auto new_pos = Eigen::Vector3f( - scene_pos[0] + side_length, - this->scene_pos[1], // height unchanged - scene_pos[2] + side_length); - + auto new_pos = calc_look_at(scene_pos); this->move_to(new_pos); } @@ -102,15 +71,17 @@ void Camera::look_at_coord(coord::scene3 coord_pos) { this->look_at_scene(scene_pos); } -void Camera::move_to(Eigen::Vector3f scene_pos) { - // TODO: Check and set bounds for where the camera can go and check them here +void Camera::move_to(Eigen::Vector3f scene_pos, const CameraBoundaries &camera_boundaries) { + scene_pos[0] = std::clamp(scene_pos[0], camera_boundaries.x_min, camera_boundaries.x_max); + scene_pos[1] = std::clamp(scene_pos[1], camera_boundaries.y_min, camera_boundaries.y_max); + scene_pos[2] = std::clamp(scene_pos[2], camera_boundaries.z_min, camera_boundaries.z_max); this->scene_pos = scene_pos; this->moved = true; } -void Camera::move_rel(Eigen::Vector3f direction, float delta) { - this->move_to(this->scene_pos + (direction * delta)); +void Camera::move_rel(Eigen::Vector3f direction, float delta, const CameraBoundaries &camera_boundaries) { + this->move_to(this->scene_pos + (direction * delta), camera_boundaries); } void Camera::set_zoom(float zoom) { @@ -292,8 +263,43 @@ void Camera::init_uniform_buffer(const std::shared_ptr &renderer) { this->uniform_buffer = renderer->add_uniform_buffer(ubo_info); } +Eigen::Vector3f Camera::calc_look_at(Eigen::Vector3f target) { + if (target[1] > this->scene_pos[1]) { + // TODO: camera can't look at a position that's + // higher than it's own position + } + + // TODO: Although the below method should be faster, calculating and adding the direction + // vector from scene_pos to new_pos may be easier to understand + // i.e. new_pos = scene_pos + b/sin(30) * direction_vec + + // due to the fixed angle, the centered scene position + // and the new camera position form a right triangle. + // + // c - + new camera pos + // - |b + // center +------+ + // a + // + // we can calculate the new camera position via the offset a + // using the angle and length of side b. + auto y_delta = this->scene_pos[1] - target[1]; // b (vertical distance) + auto xz_distance = y_delta * std::numbers::sqrt3; // a (horizontal distance); a = b * (cos(30°) / sin(30°)) + + // get x and z offsets + // the camera is pointed diagonally to the negative x and z axis + // a is the length of the diagonal from camera.xz to scene_pos.xz + // so the x and z offest are sides of a square with the same diagonal + auto side_length = xz_distance / std::numbers::sqrt2; + return Eigen::Vector3f( + target[0] + side_length, + this->scene_pos[1], // height unchanged + target[2] + side_length); +} + inline float Camera::get_real_zoom_factor() const { return 0.5f * this->default_zoom_ratio * this->zoom; } + } // namespace openage::renderer::camera diff --git a/libopenage/renderer/camera/camera.h b/libopenage/renderer/camera/camera.h index eccb5b40e6..5e5759c06e 100644 --- a/libopenage/renderer/camera/camera.h +++ b/libopenage/renderer/camera/camera.h @@ -4,7 +4,9 @@ #include #include +#include #include +#include #include @@ -12,6 +14,7 @@ #include "coord/scene.h" #include "util/vector.h" +#include "renderer/camera/boundaries.h" #include "renderer/camera/definitions.h" #include "renderer/camera/frustum_2d.h" #include "renderer/camera/frustum_3d.h" @@ -83,18 +86,21 @@ class Camera { * Move the camera position in the direction of a given vector. * * @param scene_pos New 3D position of the camera in the scene. + * @param camera_boundaries 3D boundaries for the camera. */ - void move_to(Eigen::Vector3f scene_pos); + void move_to(Eigen::Vector3f scene_pos, const CameraBoundaries &camera_boundaries = DEFAULT_CAM_BOUNDARIES); /** - * Move the camera position in the direction of a given vector. + * Move the camera position in the direction of a given vector taking the + * camera boundaries into account. * * @param direction Direction vector. Added to the current position. * @param delta Delta for controlling the amount by which the camera is moved. The * value is multiplied with the directional vector before its applied to * the positional vector. + * @param camera_boundaries 3D boundaries for the camera. */ - void move_rel(Eigen::Vector3f direction, float delta = 1.0f); + void move_rel(Eigen::Vector3f direction, float delta = 1.0f, const CameraBoundaries &camera_boundaries = DEFAULT_CAM_BOUNDARIES); /** * Set the zoom level of the camera. Values smaller than 1.0f let the @@ -200,6 +206,7 @@ class Camera { */ const Frustum3d get_frustum_3d() const; + private: /** * Create the uniform buffer for the camera. @@ -208,6 +215,13 @@ class Camera { */ void init_uniform_buffer(const std::shared_ptr &renderer); + /** + * Calculates the camera's position needed to center its view on the given target. + * + * @param target The target position in the 3D scene the camera should focus on. + */ + Eigen::Vector3f calc_look_at(Eigen::Vector3f target); + /** * Get the zoom factor applied to the camera projection. * diff --git a/libopenage/renderer/camera/definitions.h b/libopenage/renderer/camera/definitions.h index 9586239a2f..7c3bbdd5d3 100644 --- a/libopenage/renderer/camera/definitions.h +++ b/libopenage/renderer/camera/definitions.h @@ -3,7 +3,9 @@ #pragma once #include +#include +#include "renderer/camera/boundaries.h" namespace openage::renderer::camera { @@ -58,4 +60,23 @@ static constexpr float DEFAULT_MAX_ZOOM_OUT = 64.0f; */ static constexpr float DEFAULT_ZOOM_RATIO = 1.0f / 49; +static constexpr CameraBoundaries DEFAULT_CAM_BOUNDARIES{ + std::numeric_limits::lowest(), + std::numeric_limits::max(), + std::numeric_limits::lowest(), + std::numeric_limits::max(), + std::numeric_limits::lowest(), + std::numeric_limits::max()}; + +/** + * Constant values for the camera bounds (based on current fix terrain grid of 20x20). + * TODO: Make boundaries dynamic based on map size. + */ +static constexpr float X_BOUND_MIN = 12.25f; +static constexpr float X_BOUND_MAX = 32.25f; +static constexpr float Y_BOUND_MIN = 0.0f; +static constexpr float Y_BOUND_MAX = 20.0f; +static constexpr float Z_BOUND_MIN = -8.25f; +static constexpr float Z_BOUND_MAX = 12.25f; + } // namespace openage::renderer::camera diff --git a/libopenage/renderer/demo/demo_3.cpp b/libopenage/renderer/demo/demo_3.cpp index 9c294285f9..7de6372303 100644 --- a/libopenage/renderer/demo/demo_3.cpp +++ b/libopenage/renderer/demo/demo_3.cpp @@ -52,6 +52,18 @@ void renderer_demo_3(const util::Path &path) { // it is updated each frame before the render stages auto cam_manager = std::make_shared(camera); + // Set boundaries for camera movement in the scene + // this restricts camera movement to the area defined by the boundaries + // i.e. the map terrain in this case + cam_manager->set_camera_boundaries( + camera::CameraBoundaries{ + 12.25f, + 22.25f, + 0.0f, + 20.0f, + 2.25f, + 12.25f}); + // Render stages // every stage use a different subrenderer that manages renderables, // shaders, textures & more. diff --git a/libopenage/renderer/stages/camera/manager.cpp b/libopenage/renderer/stages/camera/manager.cpp index 39eddd2b52..d3cbd3f3b2 100644 --- a/libopenage/renderer/stages/camera/manager.cpp +++ b/libopenage/renderer/stages/camera/manager.cpp @@ -3,19 +3,21 @@ #include "manager.h" #include +#include -#include "renderer/camera/camera.h" #include "renderer/uniform_buffer.h" #include "renderer/uniform_input.h" namespace openage::renderer::camera { -CameraManager::CameraManager(const std::shared_ptr &camera) : +CameraManager::CameraManager(const std::shared_ptr &camera, + const CameraBoundaries &camera_boundaries) : camera{camera}, move_motion_directions{static_cast(MoveDirection::NONE)}, zoom_motion_direction{static_cast(ZoomDirection::NONE)}, move_motion_speed{0.2f}, - zoom_motion_speed{0.05f} { + zoom_motion_speed{0.05f}, + camera_boundaries{camera_boundaries} { this->uniforms = this->camera->get_uniform_buffer()->new_uniform_input( "view", camera->get_view_matrix(), @@ -33,18 +35,18 @@ void CameraManager::move_frame(MoveDirection direction, float speed) { case MoveDirection::LEFT: // half the speed because the relationship between forward/back and // left/right is 1:2 in our ortho projection. - this->camera->move_rel(Eigen::Vector3f(-1.0f, 0.0f, 1.0f), speed / 2); + this->camera->move_rel(Eigen::Vector3f(-1.0f, 0.0f, 1.0f), speed / 2, this->camera_boundaries); break; case MoveDirection::RIGHT: // half the speed because the relationship between forward/back and // left/right is 1:2 in our ortho projection. - this->camera->move_rel(Eigen::Vector3f(1.0f, 0.0f, -1.0f), speed / 2); + this->camera->move_rel(Eigen::Vector3f(1.0f, 0.0f, -1.0f), speed / 2, this->camera_boundaries); break; case MoveDirection::FORWARD: - this->camera->move_rel(Eigen::Vector3f(-1.0f, 0.0f, -1.0f), speed); + this->camera->move_rel(Eigen::Vector3f(-1.0f, 0.0f, -1.0f), speed, this->camera_boundaries); break; case MoveDirection::BACKWARD: - this->camera->move_rel(Eigen::Vector3f(1.0f, 0.0f, 1.0f), speed); + this->camera->move_rel(Eigen::Vector3f(1.0f, 0.0f, 1.0f), speed, this->camera_boundaries); break; default: @@ -66,6 +68,10 @@ void CameraManager::zoom_frame(ZoomDirection direction, float speed) { } } +void CameraManager::set_camera_boundaries(const CameraBoundaries &camera_boundaries) { + this->camera_boundaries = camera_boundaries; +} + void CameraManager::update_motion() { if (this->move_motion_directions != static_cast(MoveDirection::NONE)) { Eigen::Vector3f move_dir{0.0f, 0.0f, 0.0f}; @@ -83,7 +89,7 @@ void CameraManager::update_motion() { move_dir += Eigen::Vector3f(1.0f, 0.0f, 1.0f); } - this->camera->move_rel(move_dir, this->move_motion_speed); + this->camera->move_rel(move_dir, this->move_motion_speed, this->camera_boundaries); } if (this->zoom_motion_direction != static_cast(ZoomDirection::NONE)) { diff --git a/libopenage/renderer/stages/camera/manager.h b/libopenage/renderer/stages/camera/manager.h index 13d876b25f..36d605e959 100644 --- a/libopenage/renderer/stages/camera/manager.h +++ b/libopenage/renderer/stages/camera/manager.h @@ -3,7 +3,9 @@ #pragma once #include +#include +#include "renderer/camera/camera.h" namespace openage::renderer { class UniformBufferInput; @@ -47,8 +49,10 @@ class CameraManager { * Create a new camera manager. * * @param camera Camera to manage. + * @param camera_boundaries Boundaries for the camera movement in the scene. */ - CameraManager(const std::shared_ptr &camera); + CameraManager(const std::shared_ptr &camera, + const CameraBoundaries &camera_boundaries = DEFAULT_CAM_BOUNDARIES); ~CameraManager() = default; /** @@ -103,6 +107,13 @@ class CameraManager { */ void set_zoom_motion_speed(float speed); + /** + * Set boundaries for camera movement in the scene. + * + * @param camera_boundaries XYZ boundaries for the camera movement. + */ + void set_camera_boundaries(const CameraBoundaries &camera_boundaries); + private: /** * Update the camera parameters. @@ -143,6 +154,11 @@ class CameraManager { * Uniform buffer input for the camera. */ std::shared_ptr uniforms; + + /** + * Camera boundaries for X and Z movement. Contains minimum and maximum values for each axes. + */ + CameraBoundaries camera_boundaries; }; } // namespace camera