]> git.lizzy.rs Git - nothing.git/blobdiff - src/game/camera.c
(#1153) Remove TODO for #1157 (sorry!) and cleanup key handling.
[nothing.git] / src / game / camera.c
index fa1f3641999b896bd3e1887c36279a36d53f5119..a044ea319b6456508f57ed80282e18f6e3bdde33 100644 (file)
-#include <SDL2/SDL.h>
-#include <assert.h>
+#include <SDL.h>
+#include "system/stacktrace.h"
 #include <math.h>
+#include <stdbool.h>
+#include <stdlib.h>
 
 #include "camera.h"
 #include "sdl/renderer.h"
-#include "system/error.h"
+#include "system/nth_alloc.h"
+#include "system/log.h"
 
 #define RATIO_X 16.0f
 #define RATIO_Y 9.0f
 
-struct camera_t {
-    int debug_mode;
-    int blackwhite_mode;
-    point_t position;
-    SDL_Renderer *renderer;
-    sprite_font_t *font;
-};
-
-static vec_t effective_ratio(const SDL_Rect *view_port);
-static vec_t effective_scale(const SDL_Rect *view_port);
-static vec_t camera_point(const camera_t *camera,
-                          const SDL_Rect *view_port,
-                          const vec_t p);
-static rect_t camera_rect(const camera_t *camera,
-                          const SDL_Rect *view_port,
-                          const rect_t rect);
-static triangle_t camera_triangle(const camera_t *camera,
-                                  const SDL_Rect *view_port,
-                                  const triangle_t t);
-
-camera_t *create_camera(SDL_Renderer *renderer,
-                        sprite_font_t *font)
-{
-    camera_t *camera = malloc(sizeof(camera_t));
-
-    if (camera == NULL) {
-        throw_error(ERROR_TYPE_LIBC);
-        return NULL;
-    }
-
-    camera->position = vec(0.0f, 0.0f);
-    camera->debug_mode = 0;
-    camera->blackwhite_mode = 0;
-    camera->renderer = renderer;
-    camera->font = font;
+static Vec2f effective_ratio(const SDL_Rect *view_port);
+static Vec2f effective_scale(const SDL_Rect *view_port);
+static Triangle camera_triangle(const Camera *camera,
+                                const Triangle t);
 
-    return camera;
+static SDL_Color camera_sdl_color(const Camera *camera, Color color)
+{
+    return color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
 }
 
-void destroy_camera(camera_t *camera)
+Camera create_camera(SDL_Renderer *renderer,
+                     Sprite_font *font)
 {
-    assert(camera);
+    trace_assert(renderer);
+    trace_assert(font);
 
-    free(camera);
-}
+    Camera camera = {
+        .scale = 1.0f,
+        .renderer = renderer,
+        .font = font
+    };
 
+    return camera;
+}
 
-int camera_fill_rect(camera_t *camera,
-                     rect_t rect,
-                     color_t color)
+int camera_fill_rect(const Camera *camera,
+                     Rect rect,
+                     Color color)
 {
-    assert(camera);
-
-    SDL_Rect view_port;
-    SDL_RenderGetViewport(camera->renderer, &view_port);
+    trace_assert(camera);
 
     const SDL_Rect sdl_rect = rect_for_sdl(
-        camera_rect(camera, &view_port, rect));
+        camera_rect(camera, rect));
 
-    const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
+    const SDL_Color sdl_color = camera_sdl_color(camera, color);
 
     if (camera->debug_mode) {
         if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a / 2) < 0) {
-            throw_error(ERROR_TYPE_SDL2);
+            log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
             return -1;
         }
     } else {
         if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
-            throw_error(ERROR_TYPE_SDL2);
+            log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
             return -1;
         }
     }
 
     if (SDL_RenderFillRect(camera->renderer, &sdl_rect) < 0) {
-        throw_error(ERROR_TYPE_SDL2);
+        log_fail("SDL_RenderFillRect: %s\n", SDL_GetError());
         return -1;
     }
 
     return 0;
 }
 
-int camera_draw_rect(camera_t * camera,
-                     rect_t rect,
-                     color_t color)
+int camera_draw_rect(const Camera *camera,
+                     Rect rect,
+                     Color color)
 {
-    assert(camera);
-
-    SDL_Rect view_port;
-    SDL_RenderGetViewport(camera->renderer, &view_port);
+    trace_assert(camera);
 
     const SDL_Rect sdl_rect = rect_for_sdl(
-        camera_rect(camera, &view_port, rect));
+        camera_rect(camera, rect));
 
-    const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
+    const SDL_Color sdl_color = camera_sdl_color(camera, color);
 
     if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
-        throw_error(ERROR_TYPE_SDL2);
+        log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
         return -1;
     }
 
     if (SDL_RenderDrawRect(camera->renderer, &sdl_rect) < 0) {
-        throw_error(ERROR_TYPE_SDL2);
+        log_fail("SDL_RenderDrawRect: %s\n", SDL_GetError());
         return -1;
     }
 
     return 0;
 }
 
-int camera_draw_triangle(camera_t *camera,
-                         triangle_t t,
-                         color_t color)
+int camera_draw_rect_screen(const Camera *camera,
+                            Rect rect,
+                            Color color)
 {
-    assert(camera);
+    trace_assert(camera);
 
-    SDL_Rect view_port;
-    SDL_RenderGetViewport(camera->renderer, &view_port);
-
-    const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
+    const SDL_Rect sdl_rect = rect_for_sdl(rect);
+    const SDL_Color sdl_color = camera_sdl_color(camera, color);
 
     if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
-        throw_error(ERROR_TYPE_SDL2);
+        log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
         return -1;
     }
 
-    if (draw_triangle(camera->renderer, camera_triangle(camera, &view_port, t)) < 0) {
+    if (SDL_RenderDrawRect(camera->renderer, &sdl_rect) < 0) {
+        log_fail("SDL_RenderDrawRect: %s\n", SDL_GetError());
         return -1;
     }
 
     return 0;
 }
 
-int camera_fill_triangle(camera_t *camera,
-                         triangle_t t,
-                         color_t color)
+int camera_draw_triangle(Camera *camera,
+                         Triangle t,
+                         Color color)
 {
-    assert(camera);
+    trace_assert(camera);
 
-    SDL_Rect view_port;
-    SDL_RenderGetViewport(camera->renderer, &view_port);
+    const SDL_Color sdl_color = camera_sdl_color(camera, color);
+
+    if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
+        log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
+        return -1;
+    }
+
+    if (draw_triangle(camera->renderer, camera_triangle(camera, t)) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
 
-    const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
+int camera_fill_triangle(const Camera *camera,
+                         Triangle t,
+                         Color color)
+{
+    trace_assert(camera);
 
+    const SDL_Color sdl_color = camera_sdl_color(camera, color);
 
     if (camera->debug_mode) {
         if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a / 2) < 0) {
-            throw_error(ERROR_TYPE_SDL2);
+            log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
             return -1;
         }
     } else {
         if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
-            throw_error(ERROR_TYPE_SDL2);
+            log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
             return -1;
         }
     }
 
-    if (fill_triangle(camera->renderer, camera_triangle(camera, &view_port, t)) < 0) {
+    if (fill_triangle(camera->renderer, camera_triangle(camera, t)) < 0) {
         return -1;
     }
 
     return 0;
 }
 
-int camera_render_text(camera_t *camera,
+int camera_render_text(const Camera *camera,
                        const char *text,
-                       vec_t size,
-                       color_t color,
-                       vec_t position)
+                       Vec2f size,
+                       Color c,
+                       Vec2f position)
 {
     SDL_Rect view_port;
     SDL_RenderGetViewport(camera->renderer, &view_port);
 
-    const vec_t scale = effective_scale(&view_port);
-    const vec_t screen_position = camera_point(camera, &view_port, position);
+    const Vec2f scale = effective_scale(&view_port);
+    const Vec2f screen_position = camera_point(camera, position);
 
     if (sprite_font_render_text(
             camera->font,
             camera->renderer,
             screen_position,
-            vec(size.x * scale.x, size.y * scale.y),
-            camera->blackwhite_mode ? color_desaturate(color) : color,
+            vec(size.x * scale.x * camera->scale, size.y * scale.y * camera->scale),
+            camera->blackwhite_mode ? color_desaturate(c) : c,
             text) < 0) {
         return -1;
     }
@@ -196,77 +186,135 @@ int camera_render_text(camera_t *camera,
     return 0;
 }
 
-int camera_clear_background(camera_t *camera,
-                            color_t color)
+int camera_render_debug_text(const Camera *camera,
+                             const char *text,
+                             Vec2f position)
 {
-    const SDL_Color sdl_color = color_for_sdl(camera->blackwhite_mode ? color_desaturate(color) : color);
+    trace_assert(camera);
+    trace_assert(text);
+
+    if (!camera->debug_mode) {
+        return 0;
+    }
+
+    if (camera_render_text(
+            camera,
+            text,
+            vec(2.0f, 2.0f),
+            rgba(0.0f, 0.0f, 0.0f, 1.0f),
+            position) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int camera_clear_background(const Camera *camera,
+                            Color color)
+{
+    const SDL_Color sdl_color = camera_sdl_color(camera, color);
 
     if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
-        throw_error(ERROR_TYPE_SDL2);
+        log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
         return -1;
     }
 
     if (SDL_RenderClear(camera->renderer) < 0) {
-        throw_error(ERROR_TYPE_SDL2);
+        log_fail("SDL_RenderClear: %s\n", SDL_GetError());
         return -1;
     }
 
     return 0;
 }
 
-void camera_center_at(camera_t *camera, point_t position)
+void camera_center_at(Camera *camera, Vec2f position)
 {
-    assert(camera);
+    trace_assert(camera);
     camera->position = position;
 }
 
-void camera_toggle_debug_mode(camera_t *camera)
+void camera_scale(Camera *camera, float scale)
 {
-    assert(camera);
-    camera->debug_mode = !camera->debug_mode;
+    trace_assert(camera);
+    camera->scale = fmaxf(0.1f, scale);
 }
 
-void camera_disable_debug_mode(camera_t *camera)
+void camera_toggle_debug_mode(Camera *camera)
 {
-    assert(camera);
-    camera->debug_mode = 0;
+    trace_assert(camera);
+    camera->debug_mode = !camera->debug_mode;
 }
 
-void camera_toggle_blackwhite_mode(camera_t *camera)
+void camera_disable_debug_mode(Camera *camera)
 {
-    assert(camera);
-    camera->blackwhite_mode = !camera->blackwhite_mode;
+    trace_assert(camera);
+    camera->debug_mode = 0;
 }
 
-int camera_is_point_visible(const camera_t *camera, point_t p)
+int camera_is_point_visible(const Camera *camera, Vec2f p)
 {
     SDL_Rect view_port;
     SDL_RenderGetViewport(camera->renderer, &view_port);
 
     return rect_contains_point(
         rect_from_sdl(&view_port),
-        camera_point(camera, &view_port, p));
+        camera_point(camera, p));
 }
 
-rect_t camera_view_port(const camera_t *camera)
+Rect camera_view_port(const Camera *camera)
 {
-    assert(camera);
+    trace_assert(camera);
 
     SDL_Rect view_port;
     SDL_RenderGetViewport(camera->renderer, &view_port);
 
-    const vec_t s = effective_scale(&view_port);
-    const float w = (float) view_port.w * s.x;
-    const float h = (float) view_port.h * s.y;
+    Vec2f p1 = camera_map_screen(
+        camera,
+        view_port.x,
+        view_port.y);
+    Vec2f p2 = camera_map_screen(
+        camera,
+        view_port.x + view_port.w,
+        view_port.y + view_port.h);
+
+    return rect_from_points(p1, p2);
+}
+
+Rect camera_view_port_screen(const Camera *camera)
+{
+    trace_assert(camera);
+
+    SDL_Rect view_port;
+    SDL_RenderGetViewport(camera->renderer, &view_port);
 
-    return rect(camera->position.x - w * 0.5f,
-                camera->position.y - h * 0.5f,
-                w, h);
+    return rect_from_sdl(&view_port);
+}
+
+int camera_is_text_visible(const Camera *camera,
+                           Vec2f size,
+                           Vec2f position,
+                           const char *text)
+{
+    trace_assert(camera);
+    trace_assert(text);
+
+    SDL_Rect view_port;
+    SDL_RenderGetViewport(camera->renderer, &view_port);
+
+    return rects_overlap(
+        camera_rect(
+            camera,
+            sprite_font_boundary_box(
+                camera->font,
+                position,
+                size,
+                text)),
+        rect_from_sdl(&view_port));
 }
 
 /* ---------- Private Function ---------- */
 
-static vec_t effective_ratio(const SDL_Rect *view_port)
+static Vec2f effective_ratio(const SDL_Rect *view_port)
 {
     if ((float) view_port->w / RATIO_X > (float) view_port->h / RATIO_Y) {
         return vec(RATIO_X, (float) view_port->h / ((float) view_port->w / RATIO_X));
@@ -275,46 +323,239 @@ static vec_t effective_ratio(const SDL_Rect *view_port)
     }
 }
 
-static vec_t effective_scale(const SDL_Rect *view_port)
+static Vec2f effective_scale(const SDL_Rect *view_port)
 {
     return vec_entry_div(
         vec((float) view_port->w, (float) view_port->h),
         vec_scala_mult(effective_ratio(view_port), 50.0f));
 }
 
-static vec_t camera_point(const camera_t *camera,
-                          const SDL_Rect *view_port,
-                          const vec_t p)
-
+Vec2f camera_point(const Camera *camera, const Vec2f p)
 {
+    SDL_Rect view_port;
+    SDL_RenderGetViewport(camera->renderer, &view_port);
+
     return vec_sum(
-        vec_entry_mult(
-            vec_sum(p, vec_neg(camera->position)),
-            effective_scale(view_port)),
-        vec((float) view_port->w * 0.5f,
-            (float) view_port->h * 0.5f));
+        vec_scala_mult(
+            vec_entry_mult(
+                vec_sum(p, vec_neg(camera->position)),
+                effective_scale(&view_port)),
+            camera->scale),
+        vec((float) view_port.w * 0.5f,
+            (float) view_port.h * 0.5f));
 }
 
-static triangle_t camera_triangle(const camera_t *camera,
-                                  const SDL_Rect *view_port,
-                                  const triangle_t t)
+static Triangle camera_triangle(const Camera *camera,
+                                const Triangle t)
 {
     return triangle(
-        camera_point(camera, view_port, t.p1),
-        camera_point(camera, view_port, t.p2),
-        camera_point(camera, view_port, t.p3));
+        camera_point(camera, t.p1),
+        camera_point(camera, t.p2),
+        camera_point(camera, t.p3));
 }
 
-static rect_t camera_rect(const camera_t *camera,
-                          const SDL_Rect *view_port,
-                          const rect_t rect)
+Rect camera_rect(const Camera *camera, const Rect rect)
 {
-    return rect_from_vecs(
+    return rect_from_points(
         camera_point(
             camera,
-            view_port,
             vec(rect.x, rect.y)),
+        camera_point(
+            camera,
+            vec(rect.x + rect.w, rect.y + rect.h)));
+}
+
+int camera_render_debug_rect(const Camera *camera,
+                             Rect rect,
+                             Color c)
+{
+    trace_assert(camera);
+
+    if (!camera->debug_mode) {
+        return 0;
+    }
+
+    if (camera_fill_rect(camera, rect, c) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+Vec2f camera_map_screen(const Camera *camera,
+                      Sint32 x, Sint32 y)
+{
+    trace_assert(camera);
+
+    SDL_Rect view_port;
+    SDL_RenderGetViewport(camera->renderer, &view_port);
+
+    Vec2f es = effective_scale(&view_port);
+    es.x = 1.0f / es.x;
+    es.y = 1.0f / es.y;
+
+    const Vec2f p = vec((float) x, (float) y);
+
+    return vec_sum(
         vec_entry_mult(
-            effective_scale(view_port),
-            vec(rect.w, rect.h)));
+            vec_scala_mult(
+                vec_sum(
+                    p,
+                    vec((float) view_port.w * -0.5f,
+                        (float) view_port.h * -0.5f)),
+                1.0f / camera->scale),
+            es),
+        camera->position);
+}
+
+int camera_fill_rect_screen(const Camera *camera,
+                            Rect rect,
+                            Color color)
+{
+    trace_assert(camera);
+
+    const SDL_Rect sdl_rect = rect_for_sdl(rect);
+    const SDL_Color sdl_color = camera_sdl_color(camera, color);
+
+    if (camera->debug_mode) {
+        if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a / 2) < 0) {
+            log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
+            return -1;
+        }
+    } else {
+        if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
+            log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
+            return -1;
+        }
+    }
+
+    if (SDL_RenderFillRect(camera->renderer, &sdl_rect) < 0) {
+        log_fail("SDL_RenderFillRect: %s\n", SDL_GetError());
+        return -1;
+    }
+
+    return 0;
+
+}
+
+int camera_render_text_screen(const Camera *camera,
+                              const char *text,
+                              Vec2f size,
+                              Color color,
+                              Vec2f position)
+{
+    trace_assert(camera);
+    trace_assert(text);
+
+    return sprite_font_render_text(
+        camera->font,
+        camera->renderer,
+        position,
+        size,
+        color,
+        text);
+}
+
+int camera_draw_thicc_rect_screen(const Camera *camera,
+                                  Rect rect,
+                                  Color color,
+                                  float thiccness)
+{
+    trace_assert(camera);
+
+    // Top
+    if (camera_fill_rect_screen(
+            camera,
+            horizontal_thicc_line(
+               rect.x,
+               rect.x + rect.w,
+               rect.y,
+               thiccness),
+            color) < 0) {
+        return -1;
+    }
+
+    // Bottom
+    if (camera_fill_rect_screen(
+            camera,
+            horizontal_thicc_line(
+                rect.x,
+                rect.x + rect.w,
+                rect.y + rect.h,
+                thiccness),
+            color) < 0) {
+        return -1;
+    }
+
+    // Left
+    if (camera_fill_rect_screen(
+            camera,
+            vertical_thicc_line(
+                rect.y,
+                rect.y + rect.h,
+                rect.x,
+                thiccness),
+            color) < 0) {
+        return -1;
+    }
+
+    // Right
+    if (camera_fill_rect_screen(
+            camera,
+            vertical_thicc_line(
+                rect.y,
+                rect.y + rect.h,
+                rect.x + rect.w,
+                thiccness),
+            color) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+const Sprite_font *camera_font(const Camera *camera)
+{
+    return camera->font;
+}
+
+Rect camera_text_boundary_box(const Camera *camera,
+                              Vec2f position,
+                              Vec2f scale,
+                              const char *text)
+{
+    trace_assert(camera);
+    trace_assert(text);
+
+    return sprite_font_boundary_box(
+        camera->font, position, scale, text);
+}
+
+int camera_draw_line(const Camera *camera,
+                     Vec2f begin, Vec2f end,
+                     Color color)
+{
+    trace_assert(camera);
+
+    const Vec2f camera_begin = camera_point(camera, begin);
+    const Vec2f camera_end = camera_point(camera, end);
+
+    const SDL_Color sdl_color = camera_sdl_color(camera, color);
+
+    if (SDL_SetRenderDrawColor(camera->renderer, sdl_color.r, sdl_color.g, sdl_color.b, sdl_color.a) < 0) {
+        log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
+        return -1;
+    }
+
+    if (SDL_RenderDrawLine(
+            camera->renderer,
+            (int)roundf(camera_begin.x),
+            (int)roundf(camera_begin.y),
+            (int)roundf(camera_end.x),
+            (int)roundf(camera_end.y)) < 0) {
+        log_fail("SDL_RenderDrawRect: %s\n", SDL_GetError());
+        return -1;
+    }
+
+    return 0;
 }