aboutsummaryrefslogtreecommitdiff
path: root/teensy/renderer.c
diff options
context:
space:
mode:
authoriamcheeseman <[email protected]>2026-05-08 19:30:44 -0400
committeriamcheeseman <[email protected]>2026-05-08 19:30:44 -0400
commit5625a8626fe303748b205c80f87035593cf2f561 (patch)
tree5e5a5adb6f1265358ae21ec47cd384362345df5a /teensy/renderer.c
Initial commit
Diffstat (limited to 'teensy/renderer.c')
-rw-r--r--teensy/renderer.c227
1 files changed, 227 insertions, 0 deletions
diff --git a/teensy/renderer.c b/teensy/renderer.c
new file mode 100644
index 0000000..9e5f824
--- /dev/null
+++ b/teensy/renderer.c
@@ -0,0 +1,227 @@
+#include "renderer.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "context.h"
+#include "dyn_arr.h"
+
+struct ty_renderer r;
+
+static
+void renderer_init_check()
+{
+#ifdef TEENSY_DEBUG
+ if (
+ r.screen.data == NULL ||
+ r.screen.width * r.screen.height == 0
+ ) {
+ ty_log_fatal(
+ TY_ERR_RENDERER_NOT_INIT,
+ "renderer is not yet intialized"
+ );
+ }
+#endif
+}
+
+static
+void image_bounds_check(struct ty_image img, struct ty_vec2i pos)
+{
+#ifdef TEENSY_DEBUG
+ if (
+ pos.x < 0 ||
+ pos.x >= img.width ||
+ pos.y < 0 ||
+ pos.y >= img.height
+ ) {
+ ty_log_fatal(
+ TY_ERR_RENDER_OOB,
+ "rendered at (%d, %d), when bounds are "
+ "(0, 0) to (%d, %d)",
+ pos.x, pos.y,
+ img.width, img.height
+ );
+ }
+#endif
+}
+
+void ty_init_renderer(void)
+{
+ r.screen = ty_create_image(
+ ctx.creation_hints.win_width,
+ ctx.creation_hints.win_height,
+ NULL
+ );
+}
+
+void ty_deinit_renderer(void)
+{
+ renderer_init_check();
+
+ ty_free_image(r.screen);
+}
+
+struct ty_image ty_create_image(int w, int h, const struct ty_color* data)
+{
+ struct ty_image img;
+
+ img.width = w;
+ img.height = h;
+
+ size_t size = sizeof(struct ty_color) * w * h;
+ img.data = ty_alloc(size);
+ if (data)
+ memcpy(img.data, data, size);
+ else
+ memset(img.data, 0, size);
+
+ return img;
+}
+
+void ty_free_image(struct ty_image img)
+{
+ ty_free(img.data);
+}
+
+struct ty_color ty_img_get_pixel(struct ty_image img, struct ty_vec2i pos)
+{
+ image_bounds_check(img, pos);
+ return img.data[pos.y * img.width + pos.x];
+}
+
+void ty_img_set_pixel(
+ struct ty_image img,
+ struct ty_vec2i pos,
+ struct ty_color color
+) {
+ image_bounds_check(img, pos);
+ img.data[pos.y * img.width + pos.x] = color;
+}
+
+void ty_draw_clear(struct ty_color col)
+{
+ renderer_init_check();
+ for (int i = 0; i < r.screen.width * r.screen.height; i++) {
+ r.screen.data[i] = col;
+ }
+}
+
+void ty_draw_image(struct ty_image img, struct ty_vec2i pos)
+{
+ int x1 = fmin(fmax(floor(pos.x), 0), r.screen.width);
+ int y1 = fmin(fmax(floor(pos.y), 0), r.screen.height);
+
+ int x2 = fmin(fmax(floor(pos.x + img.width), 0), r.screen.width);
+ int y2 = fmin(fmax(floor(pos.y + img.height), 0), r.screen.height);
+
+ for (int dx = x1; dx < x2; dx++) {
+ for (int dy = y1; dy < y2; dy++) {
+ struct ty_vec2i tex_coord = ty_vec2i(dx - x1, dy - y1);
+ ty_img_set_pixel(
+ r.screen,
+ (struct ty_vec2i){dx, dy},
+ ty_img_get_pixel(img, tex_coord)
+ );
+ }
+ }
+}
+
+void ty_draw_image_ex(
+ struct ty_image img,
+ struct ty_recti src,
+ struct ty_recti dst
+) {
+ int x1 = fmin(fmax(floor(dst.x), 0), r.screen.width);
+ int y1 = fmin(fmax(floor(dst.y), 0), r.screen.height);
+ int x2 = fmin(fmax(floor(dst.x + dst.w), 0), r.screen.width);
+ int y2 = fmin(fmax(floor(dst.y + dst.h), 0), r.screen.height);
+
+ for (int dx = x1; dx < x2; dx++) {
+ for (int dy = y1; dy < y2; dy++) {
+ int tex_x = (dx - x1) / (dst.w / src.w) + src.x;
+ int tex_y = (dy - y1) / (dst.h / src.h) + src.y;
+
+ ty_img_set_pixel(
+ r.screen,
+ (struct ty_vec2i){dx, dy},
+ ty_img_get_pixel(img, ty_vec2i(tex_x, tex_y))
+ );
+ }
+ }
+}
+
+void ty_draw_rect(struct ty_recti rect, struct ty_color color)
+{
+ int x1 = fmin(fmax(floor(rect.x), 0), r.screen.width);
+ int y1 = fmin(fmax(floor(rect.y), 0), r.screen.height);
+
+ int x2 = fmin(fmax(floor(rect.x + rect.w), 0), r.screen.width);
+ int y2 = fmin(fmax(floor(rect.y + rect.h), 0), r.screen.height);
+
+ for (int dx = x1; dx < x2; dx++) {
+ for (int dy = y1; dy < y2; dy++) {
+ ty_img_set_pixel(
+ r.screen,
+ (struct ty_vec2i){dx, dy},
+ color
+ );
+ }
+ }
+}
+
+void ty_draw_line(
+ struct ty_vec2i start,
+ struct ty_vec2i end,
+ struct ty_color color
+) {
+ int dx = end.x - start.x;
+ int dy = end.y - start.y;
+
+ if (abs(dx) > abs(dy)) {
+ if (start.x > end.x) {
+ int tmp = start.x;
+ start.x = end.x;
+ end.x = tmp;
+
+ tmp = start.y;
+ start.y = end.y;
+ end.y = tmp;
+ }
+
+ for (int x = start.x; x < end.x; x++) {
+ int y = start.y + dy * (x - start.x) / dx;
+
+ ty_img_set_pixel(
+ r.screen,
+ (struct ty_vec2i){x, y},
+ color
+ );
+ }
+ } else {
+ if (start.y > end.y) {
+ int tmp = start.x;
+ start.x = end.x;
+ end.x = tmp;
+
+ tmp = start.y;
+ start.y = end.y;
+ end.y = tmp;
+ }
+
+ for (int y = start.y; y < end.y; y++) {
+ int x = start.x + dx * (y - start.y) / dy;
+
+ ty_img_set_pixel(
+ r.screen,
+ ty_vec2i(x, y),
+ color
+ );
+ }
+ }
+}
+
+void ty_draw_end(void)
+{
+ renderer_init_check();
+}