Styles navbar for wider display and consistent spacing

Widens the navbar container to accommodate more content.
Adjusts padding of navbar items for tighter spacing.
Prevents line wrapping and enables horizontal scrolling on smaller screens.
This commit is contained in:
2025-11-01 12:14:36 +03:00
parent 95c0873b8c
commit 8142d800c7
6 changed files with 285 additions and 1 deletions

View File

@@ -0,0 +1,108 @@
# `omath::frostbite_engine::CameraTrait` — plug-in trait for `projection::Camera`
> Header: `omath/engines/frostbite_engine/traits/camera_trait.hpp` • Impl: `omath/engines/frostbite_engine/traits/camera_trait.cpp`
> Namespace: `omath::frostbite_engine`
> Purpose: provide Frostbite-style **look-at**, **view**, and **projection** math to the generic `omath::projection::Camera` (satisfies `CameraEngineConcept`).
---
## Summary
`CameraTrait` exposes three `static` functions:
* `calc_look_at_angle(origin, look_at)` computes Euler angles so the camera at `origin` looks at `look_at`. Implementation normalizes the direction, computes **pitch** as `-asin(dir.y)` and **yaw** as `atan2(dir.x, dir.z)`; **roll** is `0`. Pitch/yaw are returned using the projects strong angle types (`PitchAngle`, `YawAngle`, `RollAngle`).
* `calc_view_matrix(angles, origin)` delegates to Frostbite formulas `frostbite_engine::calc_view_matrix`, producing a `Mat4X4` view matrix for the given angles and origin.
* `calc_projection_matrix(fov, viewport, near, far)` builds a perspective projection by calling `calc_perspective_projection_matrix(fov_degrees, aspect, near, far)`, where `aspect = viewport.aspect_ratio()`. Accepts `FieldOfView` (degrees).
The traits types (`ViewAngles`, `Mat4X4`, angle aliases) and helpers live in the Frostbite engine math headers included by the trait (`formulas.hpp`) and the shared projection header (`projection/camera.hpp`).
---
## API
```cpp
namespace omath::frostbite_engine {
class CameraTrait final {
public:
// Compute Euler angles (pitch/yaw/roll) to look from cam_origin to look_at.
static ViewAngles
calc_look_at_angle(const Vector3<float>& cam_origin,
const Vector3<float>& look_at) noexcept;
// Build view matrix for given angles and origin.
static Mat4X4
calc_view_matrix(const ViewAngles& angles,
const Vector3<float>& cam_origin) noexcept;
// Build perspective projection from FOV (deg), viewport, near/far.
static Mat4X4
calc_projection_matrix(const projection::FieldOfView& fov,
const projection::ViewPort& view_port,
float near, float far) noexcept;
};
} // namespace omath::frostbite_engine
```
Uses: `Vector3<float>`, `ViewAngles` (pitch/yaw/roll), `Mat4X4`, `projection::FieldOfView`, `projection::ViewPort`.
---
## Behavior & conventions
* **Angles from look-at**:
```
dir = normalize(look_at - origin)
pitch = -asin(dir.y) // +Y is up
yaw = atan2(dir.x, dir.z)
roll = 0
```
Returned as `PitchAngle::from_radians(...)`, `YawAngle::from_radians(...)`, etc.
* **View matrix**: built by the Frostbite engine helper `frostbite_engine::calc_view_matrix(angles, origin)` to match the engines handedness and axis conventions.
* **Projection**: uses `calc_perspective_projection_matrix(fov.as_degrees(), viewport.aspect_ratio(), near, far)`. Pass your **vertical FOV** in degrees via `FieldOfView`; the helper computes a standard perspective matrix.
---
## Using with `projection::Camera`
Create a camera whose math is driven by this trait:
```cpp
using Mat4 = Mat4X4; // from Frostbite math headers
using Angs = ViewAngles; // pitch/yaw/roll type
using FBcam = omath::projection::Camera<Mat4, Angs, omath::frostbite_engine::CameraTrait>;
omath::projection::ViewPort vp{1920.f, 1080.f};
auto fov = omath::projection::FieldOfView::from_degrees(70.f);
FBcam cam(
/*position*/ {0.f, 1.7f, -3.f},
/*angles*/ omath::frostbite_engine::CameraTrait::calc_look_at_angle({0,1.7f,-3},{0,1.7f,0}),
/*viewport*/ vp,
/*fov*/ fov,
/*near*/ 0.1f,
/*far*/ 1000.f
);
```
This satisfies `CameraEngineConcept` expected by `projection::Camera` (look-at, view, projection) as declared in the trait header.
---
## Notes & tips
* Ensure your `ViewAngles` aliases (`PitchAngle`, `YawAngle`, `RollAngle`) match the projects angle policy (ranges/normalization). The implementation constructs them **from radians**.
* `aspect_ratio()` is taken directly from `ViewPort` (`width / height`), so keep both positive and non-zero.
* `near` must be > 0 and `< far` for a valid projection matrix (enforced by your math helpers).
---
## See also
* Frostbite math helpers in `omath/engines/frostbite_engine/formulas.hpp` (view/projection builders used above).
* Generic camera wrapper `omath::projection::Camera` and its `CameraEngineConcept` (this trait is designed to plug straight into it).

View File

@@ -0,0 +1,59 @@
Nice! A clean little “types + constants” header. A few quick fixes and polish:
## Issues / suggestions
1. **Mat3X3 alias is wrong**
* You wrote `using Mat3X3 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;`
* That should be `Mat<3, 3, ...>`.
2. **`constexpr` globals in a header → make them `inline constexpr`**
* Since this is in a header included by multiple TUs, use `inline constexpr` to avoid ODR/link issues (C++17+).
3. **Consider column-major vs row-major**
* Most game/graphics stacks (GLSL/HLSL, many engines) lean column-major and column vectors. If the rest of your math lib or shaders assume column-major, align these typedefs now to avoid silent transposes later. If row-major is intentional, all good—just be consistent.
4. **Naming consistency**
* If you prefer `k_` prefix, keep it; otherwise consider `kAbsUp`/`ABS_UP` to match your codebases conventions.
5. **`Mat1X3` as a “row vector”**
* If you actually use it as a 3-component vector, consider just `Vector3<float>` (clearer) and reserve `Mat1X3` for real row-vector math.
---
## Tidied version
```cpp
// Created by Vlad on 10/21/2025.
#pragma once
#include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <omath/trigonometry/angle.hpp>
#include <omath/trigonometry/view_angles.hpp>
namespace omath::frostbite_engine
{
// Inline to avoid ODR across translation units
inline constexpr Vector3<float> k_abs_up = {0.0f, 1.0f, 0.0f};
inline constexpr Vector3<float> k_abs_right = {1.0f, 0.0f, 0.0f};
inline constexpr Vector3<float> k_abs_forward = {0.0f, 0.0f, 1.0f};
// NOTE: verify row/column major matches the rest of your engine
using Mat4X4 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
using Mat3X3 = Mat<3, 3, float, MatStoreType::ROW_MAJOR>;
using Mat1X3 = Mat<1, 3, float, MatStoreType::ROW_MAJOR>;
using PitchAngle = Angle<float, -90.0f, 90.0f, AngleFlags::Clamped >;
using YawAngle = Angle<float,-180.0f, 180.0f, AngleFlags::Normalized>;
using RollAngle = Angle<float,-180.0f, 180.0f, AngleFlags::Normalized>;
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
} // namespace omath::frostbite_engine
```
If you share how your matrices multiply vectors (row vs column) and your world handedness, I can double-check the axis constants and angle normalization to make sure yaw/pitch signs line up with your camera and `atan2` usage.

View File

View File

@@ -0,0 +1,105 @@
// Created by Vlad on 8/6/2025.
#pragma once
#include <cmath> // sqrt, hypot, tan, asin, atan2
#include <optional>
#include "omath/engines/frostbite_engine/formulas.hpp"
#include "omath/projectile_prediction/projectile.hpp"
#include "omath/projectile_prediction/target.hpp"
namespace omath::frostbite_engine
{
class PredEngineTrait final
{
public:
// Predict projectile position given launch angles (degrees), time (s), and world gravity (m/s^2).
// Note: kept runtime function; remove constexpr to avoid CTAD surprises across toolchains.
static Vector3<float> predict_projectile_position(
const projectile_prediction::Projectile& projectile,
float pitch_deg, float yaw_deg,
float time, float gravity) noexcept
{
// Engine convention: negative pitch looks up (your original used -pitch).
const auto fwd = forward_vector({
PitchAngle::from_degrees(-pitch_deg),
YawAngle::from_degrees(yaw_deg),
RollAngle::from_degrees(0.0f)
});
Vector3<float> pos =
projectile.m_origin +
fwd * (projectile.m_launch_speed * time);
// s = 1/2 a t^2 downward
pos.y -= (gravity * projectile.m_gravity_scale) * (time * time) * 0.5f;
return pos;
}
[[nodiscard]]
static Vector3<float> predict_target_position(
const projectile_prediction::Target& target,
float time, float gravity) noexcept
{
Vector3<float> predicted = target.m_origin + target.m_velocity * time;
if (target.m_is_airborne) {
// If targets also have a gravity scale in your model, multiply here.
predicted.y -= gravity * (time * time) * 0.5f;
}
return predicted;
}
[[nodiscard]]
static float calc_vector_2d_distance(const Vector3<float>& delta) noexcept
{
// More stable than sqrt(x*x + z*z)
return std::hypot(delta.x, delta.z);
}
[[nodiscard]]
static float get_vector_height_coordinate(const Vector3<float>& vec) noexcept
{
return vec.y;
}
// Computes a viewpoint above the predicted target, using an optional projectile pitch.
// If pitch is absent, we leave Y unchanged (or you can choose a sensible default).
[[nodiscard]]
static Vector3<float> calc_viewpoint_from_angles(
const projectile_prediction::Projectile& projectile,
const Vector3<float>& predicted_target_position,
const std::optional<float> projectile_pitch_deg) noexcept
{
// Lateral separation from projectile to target (X/Z plane).
const auto delta2d = calc_vector_2d_distance(predicted_target_position - projectile.m_origin);
float y = predicted_target_position.y;
if (projectile_pitch_deg.has_value()) {
const float pitch_rad = angles::degrees_to_radians(*projectile_pitch_deg);
const float height = delta2d * std::tan(pitch_rad);
y += height;
}
// Use the target's Z, not the projectile's Z (likely bugfix).
return { predicted_target_position.x, y, predicted_target_position.z };
}
// Due to maybe_calculate_projectile_launch_pitch_angle spec: +89° up, -89° down.
[[nodiscard]]
static float calc_direct_pitch_angle(const Vector3<float>& origin,
const Vector3<float>& view_to) noexcept
{
const auto direction = (view_to - origin).normalized();
return angles::radians_to_degrees(std::asin(direction.y));
}
[[nodiscard]]
static float calc_direct_yaw_angle(const Vector3<float>& origin,
const Vector3<float>& view_to) noexcept
{
const auto direction = (view_to - origin).normalized();
return angles::radians_to_degrees(std::atan2(direction.x, direction.z));
}
};
} // namespace omath::frostbite_engine