#include "renderer.h" #include #include #include #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, "OOB (%d, %d). bounds are (%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 dy = y1; dy < y2; dy++) { for (int dx = x1; dx < x2; dx++) { int img_x = ((dx - x1) * src.w) / dst.w + src.x; int img_y = ((dy - y1) * src.h) / dst.h + src.y; ty_img_set_pixel( r.screen, (struct ty_vec2i){dx, dy}, ty_img_get_pixel(img, ty_vec2i(img_x, img_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 dy = y1; dy < y2; dy++) { for (int dx = x1; dx < x2; dx++) { 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(); }