]> git.lizzy.rs Git - nothing.git/blob - src/game/camera.c
Extend TODO description
[nothing.git] / src / game / camera.c
1 #include <SDL2/SDL.h>
2 #include <assert.h>
3 #include <math.h>
4
5 #include "camera.h"
6 #include "sdl/renderer.h"
7 #include "system/error.h"
8
9 #define RATIO_X 16.0f
10 #define RATIO_Y 9.0f
11
12 struct camera_t {
13     int debug_mode;
14     int blackwhite_mode;
15     point_t position;
16     SDL_Renderer *renderer;
17 };
18
19 static vec_t effective_ratio(const SDL_Rect *view_port);
20 static vec_t effective_scale(const SDL_Rect *view_port);
21 static vec_t camera_point(const camera_t *camera,
22                           const SDL_Rect *view_port,
23                           const vec_t p);
24 static rect_t camera_rect(const camera_t *camera,
25                           const SDL_Rect *view_port,
26                           const rect_t rect);
27 static triangle_t camera_triangle(const camera_t *camera,
28                                   const SDL_Rect *view_port,
29                                   const triangle_t t);
30
31 camera_t *create_camera_from_renderer(SDL_Renderer *renderer)
32 {
33     camera_t *camera = malloc(sizeof(camera_t));
34
35     if (camera == NULL) {
36         throw_error(ERROR_TYPE_LIBC);
37         return NULL;
38     }
39
40     camera->position = vec(0.0f, 0.0f);
41     camera->debug_mode = 0;
42     camera->blackwhite_mode = 0;
43     camera->renderer = renderer;
44
45     return camera;
46 }
47
48 void destroy_camera(camera_t *camera)
49 {
50     assert(camera);
51
52     free(camera);
53 }
54
55
56 int camera_fill_rect(const camera_t *camera,
57                      rect_t rect,
58                      color_t color)
59 {
60     assert(camera);
61
62     SDL_Rect view_port;
63     SDL_RenderGetViewport(camera->renderer, &view_port);
64
65     const SDL_Rect sdl_rect = rect_for_sdl(
66         camera_rect(camera, &view_port, rect));
67
68     const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
69
70     if (camera->debug_mode) {
71         if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a / 2) < 0) {
72             throw_error(ERROR_TYPE_SDL2);
73             return -1;
74         }
75     } else {
76         if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
77             throw_error(ERROR_TYPE_SDL2);
78             return -1;
79         }
80     }
81
82     if (SDL_RenderFillRect(camera->renderer, &sdl_rect) < 0) {
83         throw_error(ERROR_TYPE_SDL2);
84         return -1;
85     }
86
87     return 0;
88 }
89
90 int camera_draw_rect(const camera_t * camera,
91                      rect_t rect,
92                      color_t color)
93 {
94     assert(camera);
95
96     SDL_Rect view_port;
97     SDL_RenderGetViewport(camera->renderer, &view_port);
98
99     const SDL_Rect sdl_rect = rect_for_sdl(
100         camera_rect(camera, &view_port, rect));
101
102     const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
103
104     if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
105         throw_error(ERROR_TYPE_SDL2);
106         return -1;
107     }
108
109     if (SDL_RenderDrawRect(camera->renderer, &sdl_rect) < 0) {
110         throw_error(ERROR_TYPE_SDL2);
111         return -1;
112     }
113
114     return 0;
115 }
116
117 int camera_draw_triangle(const camera_t *camera,
118                          triangle_t t,
119                          color_t color)
120 {
121     assert(camera);
122
123     SDL_Rect view_port;
124     SDL_RenderGetViewport(camera->renderer, &view_port);
125
126     const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
127
128     if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
129         throw_error(ERROR_TYPE_SDL2);
130         return -1;
131     }
132
133     if (draw_triangle(camera->renderer, camera_triangle(camera, &view_port, t)) < 0) {
134         return -1;
135     }
136
137     return 0;
138 }
139
140 int camera_fill_triangle(const camera_t *camera,
141                          triangle_t t,
142                          color_t color)
143 {
144     assert(camera);
145
146     SDL_Rect view_port;
147     SDL_RenderGetViewport(camera->renderer, &view_port);
148
149     const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
150
151
152
153     if (camera->debug_mode) {
154         if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a / 2) < 0) {
155             throw_error(ERROR_TYPE_SDL2);
156             return -1;
157         }
158     } else {
159         if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
160             throw_error(ERROR_TYPE_SDL2);
161             return -1;
162         }
163     }
164
165     if (fill_triangle(camera->renderer, camera_triangle(camera, &view_port, t)) < 0) {
166         return -1;
167     }
168
169     return 0;
170 }
171
172 int camera_clear_background(const camera_t *camera,
173                             color_t color)
174 {
175     const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
176
177     if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
178         throw_error(ERROR_TYPE_SDL2);
179         return -1;
180     }
181
182     if (SDL_RenderClear(camera->renderer) < 0) {
183         throw_error(ERROR_TYPE_SDL2);
184         return -1;
185     }
186
187     return 0;
188 }
189
190 void camera_present(const camera_t *camera)
191 {
192     SDL_RenderPresent(camera->renderer);
193 }
194
195 void camera_center_at(camera_t *camera, point_t position)
196 {
197     assert(camera);
198     camera->position = position;
199 }
200
201 void camera_toggle_debug_mode(camera_t *camera)
202 {
203     assert(camera);
204     camera->debug_mode = !camera->debug_mode;
205 }
206
207 void camera_disable_debug_mode(camera_t *camera)
208 {
209     assert(camera);
210     camera->debug_mode = 0;
211 }
212
213 void camera_toggle_blackwhite_mode(camera_t *camera)
214 {
215     assert(camera);
216     camera->blackwhite_mode = !camera->blackwhite_mode;
217 }
218
219 int camera_is_point_visible(const camera_t *camera, point_t p)
220 {
221     SDL_Rect view_port;
222     SDL_RenderGetViewport(camera->renderer, &view_port);
223
224     return rect_contains_point(
225         rect_from_sdl(&view_port),
226         camera_point(camera, &view_port, p));
227 }
228
229 rect_t camera_view_port(const camera_t *camera)
230 {
231     assert(camera);
232
233     SDL_Rect view_port;
234     SDL_RenderGetViewport(camera->renderer, &view_port);
235
236     const vec_t s = effective_scale(&view_port);
237     const float w = (float) view_port.w * s.x;
238     const float h = (float) view_port.h * s.y;
239
240     return rect(camera->position.x - w * 0.5f,
241                 camera->position.y - h * 0.5f,
242                 w, h);
243 }
244
245
246 /* ---------- Private Function ---------- */
247
248 static vec_t effective_ratio(const SDL_Rect *view_port)
249 {
250     if ((float) view_port->w / RATIO_X > (float) view_port->h / RATIO_Y) {
251         return vec(RATIO_X, (float) view_port->h / ((float) view_port->w / RATIO_X));
252     } else {
253         return vec((float) view_port->w / ((float) view_port->h / RATIO_Y), RATIO_Y);
254     }
255 }
256
257 static vec_t effective_scale(const SDL_Rect *view_port)
258 {
259     return vec_entry_div(
260         vec((float) view_port->w, (float) view_port->h),
261         vec_scala_mult(effective_ratio(view_port), 50.0f));
262 }
263
264 static vec_t camera_point(const camera_t *camera,
265                           const SDL_Rect *view_port,
266                           const vec_t p)
267
268 {
269     return vec_sum(
270         vec_entry_mult(
271             vec_sum(p, vec_neg(camera->position)),
272             effective_scale(view_port)),
273         vec((float) view_port->w * 0.5f,
274             (float) view_port->h * 0.5f));
275 }
276
277 static triangle_t camera_triangle(const camera_t *camera,
278                                   const SDL_Rect *view_port,
279                                   const triangle_t t)
280 {
281     return triangle(
282         camera_point(camera, view_port, t.p1),
283         camera_point(camera, view_port, t.p2),
284         camera_point(camera, view_port, t.p3));
285 }
286
287 static rect_t camera_rect(const camera_t *camera,
288                           const SDL_Rect *view_port,
289                           const rect_t rect)
290 {
291     return rect_from_vecs(
292         camera_point(
293             camera,
294             view_port,
295             vec(rect.x, rect.y)),
296         vec_entry_mult(
297             effective_scale(view_port),
298             vec(rect.w, rect.h)));
299 }