camera.h

cross platform rendering playground

src/scene/camera.h

2.53 KB
#pragma once

#include <algorithm>

#include "core/globals.h"
#include "core/platform.h"
#include "shaders/renderer_types.h"

using NodeHandle = u32;
constexpr NodeHandle NODE_INVALID = 0xffffffffu;

struct Camera {
    NodeHandle node = NODE_INVALID;

    vec3 position = vec3(0.0f, 0.0f, 3.0f);

    f32 aspect = 0;

    // Degrees
    f32 yaw_deg = 0.0f; // -Z forward
    f32 pitch_deg = 0.0f;

    f32 fov_y_deg = 60.0f;
    f32 near_plane = 0.01f;
    f32 far_plane = 1000.0f;

    f32 move_speed = 10.0f;
    f32 fast_multiplier = 5.0f;
    f32 look_sensitivity = 0.10f; // deg per pixel

    static constexpr f32 DEG_TO_RAD = 0.017453292519943295769f;

    vec3 forward() const {
        f32 yaw = yaw_deg * DEG_TO_RAD;
        f32 pitch = pitch_deg * DEG_TO_RAD;
        vec3 fwd;
        fwd.x = std::cos(yaw) * std::cos(pitch);
        fwd.y = std::sin(yaw) * std::cos(pitch);
        fwd.z = std::sin(pitch);
        return fwd.normalized();
    }

    vec3 right() const {
        return cross(forward(), vec3(0.0f, 0.0f, 1.0f)).normalized();
    }

    vec3 up() const {
        return cross(right(), forward()).normalized();
    }

    mat4 view;
    mat4 proj;
    mat4 view_proj;
    mat4 inv_view;
    mat4 inv_proj;
    mat4 inv_view_proj;
};

static void update_camera(Camera &camera, PlatformInput &input) {
    camera.yaw_deg -= input.mouse_dx * camera.look_sensitivity;
    camera.pitch_deg -= input.mouse_dy * camera.look_sensitivity;
    camera.pitch_deg = std::clamp(camera.pitch_deg, -89.0f, 89.0f);

    vec3 move_dir(0.0f);
    if (input.move_forward)
        move_dir += camera.forward();
    if (input.move_backward)
        move_dir -= camera.forward();
    if (input.move_right)
        move_dir += camera.right();
    if (input.move_left)
        move_dir -= camera.right();
    if (input.move_up)
        move_dir += vec3(0.0f, 0.0f, 1.0f);
    if (input.move_down)
        move_dir -= vec3(0.0f, 0.0f, 1.0f);

    if (move_dir.dot(move_dir) > 0.0f)
        move_dir = move_dir.normalized();

    f32 speed = camera.move_speed;
    if (input.fast)
        speed *= camera.fast_multiplier;

    camera.position += move_dir * speed * input.dt;

    vec3 upv = vec3(0.0f, 0.0f, 1.0f);
    camera.view = look_at(camera.position, camera.position + camera.forward(), upv);
    camera.proj = perspective(radians(camera.fov_y_deg), camera.aspect, camera.near_plane);
    camera.view_proj = camera.view * camera.proj;
    camera.inv_view = inverse(camera.view);
    camera.inv_proj = inverse(camera.proj);
    camera.inv_view_proj = inverse(camera.view_proj);
}