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