-#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;
}
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));
}
}
-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;
}