2 #include "system/stacktrace.h"
8 #include "sdl/renderer.h"
9 #include "system/nth_alloc.h"
10 #include "system/log.h"
15 static Vec2f effective_ratio(const SDL_Rect *view_port);
16 static Vec2f effective_scale(const SDL_Rect *view_port);
17 static Triangle camera_triangle(const Camera *camera,
20 Camera create_camera(SDL_Renderer *renderer,
23 trace_assert(renderer);
35 int camera_fill_rect(const Camera *camera,
41 const SDL_Rect sdl_rect = rect_for_sdl(
42 camera_rect(camera, rect));
44 const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
46 if (camera->debug_mode) {
47 if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a / 2) < 0) {
48 log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
52 if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
53 log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
58 if (SDL_RenderFillRect(camera->renderer, &sdl_rect) < 0) {
59 log_fail("SDL_RenderFillRect: %s\n", SDL_GetError());
66 int camera_draw_rect(const Camera *camera,
72 const SDL_Rect sdl_rect = rect_for_sdl(
73 camera_rect(camera, rect));
75 const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
77 if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
78 log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
82 if (SDL_RenderDrawRect(camera->renderer, &sdl_rect) < 0) {
83 log_fail("SDL_RenderDrawRect: %s\n", SDL_GetError());
90 int camera_draw_rect_screen(const Camera *camera,
96 const SDL_Rect sdl_rect = rect_for_sdl(rect);
97 const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
99 if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
100 log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
104 if (SDL_RenderDrawRect(camera->renderer, &sdl_rect) < 0) {
105 log_fail("SDL_RenderDrawRect: %s\n", SDL_GetError());
112 int camera_draw_triangle(Camera *camera,
116 trace_assert(camera);
118 const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
120 if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
121 log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
125 if (draw_triangle(camera->renderer, camera_triangle(camera, t)) < 0) {
132 int camera_fill_triangle(const Camera *camera,
136 trace_assert(camera);
138 const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
140 if (camera->debug_mode) {
141 if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a / 2) < 0) {
142 log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
146 if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
147 log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
152 if (fill_triangle(camera->renderer, camera_triangle(camera, t)) < 0) {
159 int camera_render_text(const Camera *camera,
166 SDL_RenderGetViewport(camera->renderer, &view_port);
168 const Vec2f scale = effective_scale(&view_port);
169 const Vec2f screen_position = camera_point(camera, position);
171 if (sprite_font_render_text(
175 vec(size.x * scale.x * camera->scale, size.y * scale.y * camera->scale),
176 camera->blackwhite_mode ? color_desaturate(c) : c,
184 int camera_render_debug_text(const Camera *camera,
188 trace_assert(camera);
191 if (!camera->debug_mode) {
195 if (camera_render_text(
199 rgba(0.0f, 0.0f, 0.0f, 1.0f),
207 int camera_clear_background(const Camera *camera,
210 const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
212 if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
213 log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
217 if (SDL_RenderClear(camera->renderer) < 0) {
218 log_fail("SDL_RenderClear: %s\n", SDL_GetError());
225 void camera_center_at(Camera *camera, Vec2f position)
227 trace_assert(camera);
228 camera->position = position;
231 void camera_scale(Camera *camera, float scale)
233 trace_assert(camera);
234 camera->scale = fmaxf(0.1f, scale);
237 void camera_toggle_debug_mode(Camera *camera)
239 trace_assert(camera);
240 camera->debug_mode = !camera->debug_mode;
243 void camera_disable_debug_mode(Camera *camera)
245 trace_assert(camera);
246 camera->debug_mode = 0;
249 int camera_is_point_visible(const Camera *camera, Vec2f p)
252 SDL_RenderGetViewport(camera->renderer, &view_port);
254 return rect_contains_point(
255 rect_from_sdl(&view_port),
256 camera_point(camera, p));
259 Rect camera_view_port(const Camera *camera)
261 trace_assert(camera);
264 SDL_RenderGetViewport(camera->renderer, &view_port);
266 Vec2f p1 = camera_map_screen(
270 Vec2f p2 = camera_map_screen(
272 view_port.x + view_port.w,
273 view_port.y + view_port.h);
275 return rect_from_points(p1, p2);
278 Rect camera_view_port_screen(const Camera *camera)
280 trace_assert(camera);
283 SDL_RenderGetViewport(camera->renderer, &view_port);
285 return rect_from_sdl(&view_port);
288 int camera_is_text_visible(const Camera *camera,
293 trace_assert(camera);
297 SDL_RenderGetViewport(camera->renderer, &view_port);
299 return rects_overlap(
302 sprite_font_boundary_box(
307 rect_from_sdl(&view_port));
310 /* ---------- Private Function ---------- */
312 static Vec2f effective_ratio(const SDL_Rect *view_port)
314 if ((float) view_port->w / RATIO_X > (float) view_port->h / RATIO_Y) {
315 return vec(RATIO_X, (float) view_port->h / ((float) view_port->w / RATIO_X));
317 return vec((float) view_port->w / ((float) view_port->h / RATIO_Y), RATIO_Y);
321 static Vec2f effective_scale(const SDL_Rect *view_port)
323 return vec_entry_div(
324 vec((float) view_port->w, (float) view_port->h),
325 vec_scala_mult(effective_ratio(view_port), 50.0f));
328 Vec2f camera_point(const Camera *camera, const Vec2f p)
331 SDL_RenderGetViewport(camera->renderer, &view_port);
336 vec_sum(p, vec_neg(camera->position)),
337 effective_scale(&view_port)),
339 vec((float) view_port.w * 0.5f,
340 (float) view_port.h * 0.5f));
343 static Triangle camera_triangle(const Camera *camera,
347 camera_point(camera, t.p1),
348 camera_point(camera, t.p2),
349 camera_point(camera, t.p3));
352 Rect camera_rect(const Camera *camera, const Rect rect)
354 return rect_from_points(
357 vec(rect.x, rect.y)),
360 vec(rect.x + rect.w, rect.y + rect.h)));
363 int camera_render_debug_rect(const Camera *camera,
367 trace_assert(camera);
369 if (!camera->debug_mode) {
373 if (camera_fill_rect(camera, rect, c) < 0) {
380 Vec2f camera_map_screen(const Camera *camera,
383 trace_assert(camera);
386 SDL_RenderGetViewport(camera->renderer, &view_port);
388 Vec2f es = effective_scale(&view_port);
392 const Vec2f p = vec((float) x, (float) y);
399 vec((float) view_port.w * -0.5f,
400 (float) view_port.h * -0.5f)),
401 1.0f / camera->scale),
406 int camera_fill_rect_screen(const Camera *camera,
410 trace_assert(camera);
412 const SDL_Rect sdl_rect = rect_for_sdl(rect);
413 const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
415 if (camera->debug_mode) {
416 if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a / 2) < 0) {
417 log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
421 if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
422 log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
427 if (SDL_RenderFillRect(camera->renderer, &sdl_rect) < 0) {
428 log_fail("SDL_RenderFillRect: %s\n", SDL_GetError());
436 int camera_render_text_screen(const Camera *camera,
442 trace_assert(camera);
445 return sprite_font_render_text(
454 int camera_draw_thicc_rect_screen(const Camera *camera,
459 trace_assert(camera);
462 if (camera_fill_rect_screen(
464 horizontal_thicc_line(
474 if (camera_fill_rect_screen(
476 horizontal_thicc_line(
486 if (camera_fill_rect_screen(
498 if (camera_fill_rect_screen(
512 const Sprite_font *camera_font(const Camera *camera)
517 Rect camera_text_boundary_box(const Camera *camera,
522 trace_assert(camera);
525 return sprite_font_boundary_box(
526 camera->font, position, scale, text);
529 int camera_draw_line(const Camera *camera,
530 Vec2f begin, Vec2f end,
533 trace_assert(camera);
535 const Vec2f camera_begin = camera_point(camera, begin);
536 const Vec2f camera_end = camera_point(camera, end);
538 // TODO: introduce internal function camera_set_render_draw_color
539 // that wraps SDL_SetRenderDrawColor and takes
540 // camera->blackwhite_mode into account
541 const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
543 if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
544 log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
548 if (SDL_RenderDrawLine(
550 (int)roundf(camera_begin.x),
551 (int)roundf(camera_begin.y),
552 (int)roundf(camera_end.x),
553 (int)roundf(camera_end.y)) < 0) {
554 log_fail("SDL_RenderDrawRect: %s\n", SDL_GetError());