]> git.lizzy.rs Git - nothing.git/blob - src/camera.c
Make player color customizable (#76)
[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 void camera_center_at(camera_t *camera, point_t position)
171 {
172     assert(camera);
173     camera->position = position;
174 }
175
176 void camera_toggle_debug_mode(camera_t *camera)
177 {
178     assert(camera);
179     camera->debug_mode = !camera->debug_mode;
180 }
181
182 void camera_toggle_blackwhite_mode(camera_t *camera)
183 {
184     assert(camera);
185     camera->blackwhite_mode = !camera->blackwhite_mode;
186 }
187
188 /* ---------- Private Function ---------- */
189
190 static vec_t effective_ratio(const SDL_Rect *view_port)
191 {
192     if ((float) view_port->w / RATIO_X > (float) view_port->h / RATIO_Y) {
193         return vec(RATIO_X, (float) view_port->h / ((float) view_port->w / RATIO_X));
194     } else {
195         return vec((float) view_port->w / ((float) view_port->h / RATIO_Y), RATIO_Y);
196     }
197 }
198
199 static vec_t effective_scale(const SDL_Rect *view_port)
200 {
201     return vec_entry_div(
202         vec((float) view_port->w, (float) view_port->h),
203         vec_scala_mult(effective_ratio(view_port), 50.0f));
204 }
205
206 static vec_t camera_point(const camera_t *camera,
207                           const SDL_Rect *view_port,
208                           const vec_t p)
209
210 {
211     return vec_sum(
212         vec_entry_mult(
213             vec_sum(p, vec_neg(camera->position)),
214             effective_scale(view_port)),
215         vec((float) view_port->w * 0.5f,
216             (float) view_port->h * 0.5f));
217 }
218
219 static triangle_t camera_triangle(const camera_t *camera,
220                                   const SDL_Rect *view_port,
221                                   const triangle_t t)
222 {
223     return triangle(
224         camera_point(camera, view_port, t.p1),
225         camera_point(camera, view_port, t.p2),
226         camera_point(camera, view_port, t.p3));
227 }
228
229 static rect_t camera_rect(const camera_t *camera,
230                           const SDL_Rect *view_port,
231                           const rect_t rect)
232 {
233     return rect_from_vecs(
234         camera_point(
235             camera,
236             view_port,
237             vec(rect.x, rect.y)),
238         vec_entry_mult(
239             effective_scale(view_port),
240             vec(rect.w, rect.h)));
241 }