A 3D game engine from scratch.
1// (c) 2020 Vlad-Stefan Harbuz <vlad@vladh.net>
2
3#include "cameras.hpp"
4#include "intrinsics.hpp"
5
6
7cameras::State *cameras::state = nullptr;
8
9
10cameras::Camera *
11cameras::get_main()
12{
13 return &cameras::state->camera_main;
14}
15
16
17void
18cameras::update_matrices(Camera *camera)
19{
20 WindowSize *window_size = core::get_window_size();
21 if (window_size->width == 0 || window_size->height == 0) {
22 return;
23 }
24
25 if (camera->type == CameraType::perspective) {
26 update_matrices_perspective(camera, window_size->width, window_size->height);
27 } else if (camera->type == CameraType::ortho) {
28 update_matrices_ortho(camera, window_size->width, window_size->height);
29 }
30}
31
32
33void
34cameras::update_ui_matrices(Camera *camera)
35{
36 WindowSize *window_size = core::get_window_size();
37 camera->ui_projection = glm::ortho(0.0f, (f32)window_size->width,
38 0.0f, (f32)window_size->height);
39}
40
41
42void
43cameras::move_front_back(Camera *camera, f32 sign, f64 dt)
44{
45 camera->position += (sign * camera->speed * (f32)dt) * camera->front;
46}
47
48
49void
50cameras::move_left_right(Camera *camera, f32 sign, f64 dt)
51{
52 v3 direction = normalize(cross(
53 camera->front, camera->up
54 ));
55 camera->position += (sign * camera->speed * (f32)dt) * direction;
56}
57
58
59void
60cameras::move_up_down(Camera *camera, f32 sign, f64 dt)
61{
62 camera->position += (sign * camera->speed * (f32)dt) * camera->up;
63}
64
65
66void
67cameras::update_mouse(Camera *camera, v2 mouse_offset)
68{
69 camera->yaw += mouse_offset.x;
70 camera->pitch += mouse_offset.y;
71
72 if (camera->pitch > 89.0f) {
73 camera->pitch = 89.0f;
74 } else if (camera->pitch < -89.0f) {
75 camera->pitch = -89.0f;
76 }
77}
78
79
80void
81cameras::init(
82 cameras::State *cameras_state,
83 u32 window_width,
84 u32 window_height
85) {
86 cameras::state = cameras_state;
87 cameras::state->camera_main.type = CameraType::perspective;
88 cameras::state->camera_main.yaw = -45.0f;
89 cameras::state->camera_main.pitch = 0.0f;
90 cameras::state->camera_main.position = v3(-7.0f, 3.0f, 7.0f);
91 cameras::state->camera_main.front = v3(0.0f, 0.0f, 0.0f);
92 cameras::state->camera_main.up = v3(0.0f, 1.0f, 0.0f);
93 cameras::state->camera_main.speed = 5.0f;
94 cameras::state->camera_main.horizontal_fov = 60.0f;
95 cameras::state->camera_main.vertical_fov = 0.0f; // Filled in later
96 cameras::state->camera_main.near_clip_dist = 0.1f;
97 cameras::state->camera_main.far_clip_dist = 600.0f;
98 cameras::state->camera_main.exposure = 1.0f;
99
100 update_matrices(&cameras::state->camera_main);
101 update_ui_matrices(&cameras::state->camera_main);
102}
103
104
105void
106cameras::update_matrices_ortho(
107 Camera *camera, u32 window_width, u32 window_height
108) {
109 if (window_width == 0 || window_height == 0) {
110 return;
111 }
112
113 camera->view = glm::lookAt(camera->position, v3(0.0f, 0.0f, 0.0f), camera->up);
114
115 camera->projection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f,
116 camera->near_clip_dist, camera->far_clip_dist);
117}
118
119
120void
121cameras::update_matrices_perspective(
122 Camera *camera, u32 window_width, u32 window_height
123) {
124 if (window_width == 0 || window_height == 0) {
125 return;
126 }
127
128 camera->front = normalize(v3(
129 cos(radians(camera->yaw)) * cos(radians(camera->pitch)),
130 -sin(radians(camera->pitch)),
131 sin(radians(camera->yaw)) * cos(radians(camera->pitch))));
132
133 camera->view = glm::lookAt(camera->position,
134 camera->position + camera->front, camera->up);
135
136 camera->projection = glm::perspective(radians(camera->horizontal_fov),
137 (f32)window_width / (f32)window_height,
138 camera->near_clip_dist, camera->far_clip_dist);
139 // https://en.wikipedia.org/wiki/Field_of_view_in_video_games#Field_of_view_calculations
140 camera->vertical_fov = (f32)degrees(2 *
141 atan(tan(radians(camera->horizontal_fov) / 2) * window_height / window_width));
142}