]> git.lizzy.rs Git - nothing.git/blob - src/camera.c
Naive MIN/MAX todo
[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 (camera->debug_mode) {
164         if (draw_triangle(render, camera_triangle(camera, &view_port, t)) < 0) {
165             return -1;
166         }
167
168     } else {
169         if (fill_triangle(render, camera_triangle(camera, &view_port, t)) < 0) {
170             return -1;
171         }
172     }
173
174     return 0;
175 }
176
177 int camera_clear_background(const camera_t *camera,
178                             SDL_Renderer *render,
179                             color_t color)
180 {
181     const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
182
183     if (SDL_SetRenderDrawColor(render, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
184         throw_error(ERROR_TYPE_SDL2);
185         return -1;
186     }
187
188     if (SDL_RenderClear(render) < 0) {
189         throw_error(ERROR_TYPE_SDL2);
190         return -1;
191     }
192
193     return 0;
194 }
195
196 void camera_center_at(camera_t *camera, point_t position)
197 {
198     assert(camera);
199     camera->position = position;
200 }
201
202 void camera_toggle_debug_mode(camera_t *camera)
203 {
204     assert(camera);
205     camera->debug_mode = !camera->debug_mode;
206 }
207
208 void camera_toggle_blackwhite_mode(camera_t *camera)
209 {
210     assert(camera);
211     camera->blackwhite_mode = !camera->blackwhite_mode;
212 }
213
214 int camera_is_point_visible(const camera_t *camera, SDL_Renderer *renderer, point_t p)
215 {
216     SDL_Rect view_port;
217     SDL_RenderGetViewport(renderer, &view_port);
218
219     return rect_contains_point(
220         rect_from_sdl(&view_port),
221         camera_point(camera, &view_port, p));
222 }
223
224 /* ---------- Private Function ---------- */
225
226 static vec_t effective_ratio(const SDL_Rect *view_port)
227 {
228     if ((float) view_port->w / RATIO_X > (float) view_port->h / RATIO_Y) {
229         return vec(RATIO_X, (float) view_port->h / ((float) view_port->w / RATIO_X));
230     } else {
231         return vec((float) view_port->w / ((float) view_port->h / RATIO_Y), RATIO_Y);
232     }
233 }
234
235 static vec_t effective_scale(const SDL_Rect *view_port)
236 {
237     return vec_entry_div(
238         vec((float) view_port->w, (float) view_port->h),
239         vec_scala_mult(effective_ratio(view_port), 50.0f));
240 }
241
242 static vec_t camera_point(const camera_t *camera,
243                           const SDL_Rect *view_port,
244                           const vec_t p)
245
246 {
247     return vec_sum(
248         vec_entry_mult(
249             vec_sum(p, vec_neg(camera->position)),
250             effective_scale(view_port)),
251         vec((float) view_port->w * 0.5f,
252             (float) view_port->h * 0.5f));
253 }
254
255 static triangle_t camera_triangle(const camera_t *camera,
256                                   const SDL_Rect *view_port,
257                                   const triangle_t t)
258 {
259     return triangle(
260         camera_point(camera, view_port, t.p1),
261         camera_point(camera, view_port, t.p2),
262         camera_point(camera, view_port, t.p3));
263 }
264
265 static rect_t camera_rect(const camera_t *camera,
266                           const SDL_Rect *view_port,
267                           const rect_t rect)
268 {
269     return rect_from_vecs(
270         camera_point(
271             camera,
272             view_port,
273             vec(rect.x, rect.y)),
274         vec_entry_mult(
275             effective_scale(view_port),
276             vec(rect.w, rect.h)));
277 }