From 576bd27e11ec70bdbd1b9a644d2e227b57586337 Mon Sep 17 00:00:00 2001 From: iamcheeseman Date: Sun, 10 May 2026 00:28:14 -0400 Subject: i ain't splitting alla this up --- teensy/common.c | 30 ------- teensy/common.h | 14 --- teensy/context.c | 61 ------------- teensy/context.h | 10 --- teensy/dyn_arr.c | 12 --- teensy/dyn_arr.h | 49 ---------- teensy/log.c | 33 ------- teensy/log.h | 47 ---------- teensy/mem.c | 171 ----------------------------------- teensy/mem.h | 24 ----- teensy/platform.h | 12 --- teensy/renderer.c | 227 ----------------------------------------------- teensy/renderer.h | 10 --- teensy/teensy.h | 18 ++-- teensy/teensy_common.c | 30 +++++++ teensy/teensy_common.h | 15 ++++ teensy/teensy_context.c | 74 +++++++++++++++ teensy/teensy_context.h | 12 +++ teensy/teensy_list.c | 12 +++ teensy/teensy_list.h | 49 ++++++++++ teensy/teensy_log.c | 33 +++++++ teensy/teensy_log.h | 47 ++++++++++ teensy/teensy_mem.c | 171 +++++++++++++++++++++++++++++++++++ teensy/teensy_mem.h | 24 +++++ teensy/teensy_platform.h | 12 +++ teensy/teensy_renderer.c | 217 ++++++++++++++++++++++++++++++++++++++++++++ teensy/teensy_renderer.h | 10 +++ 27 files changed, 715 insertions(+), 709 deletions(-) delete mode 100644 teensy/common.c delete mode 100644 teensy/common.h delete mode 100644 teensy/context.c delete mode 100644 teensy/context.h delete mode 100644 teensy/dyn_arr.c delete mode 100644 teensy/dyn_arr.h delete mode 100644 teensy/log.c delete mode 100644 teensy/log.h delete mode 100644 teensy/mem.c delete mode 100644 teensy/mem.h delete mode 100644 teensy/platform.h delete mode 100644 teensy/renderer.c delete mode 100644 teensy/renderer.h create mode 100644 teensy/teensy_common.c create mode 100644 teensy/teensy_common.h create mode 100644 teensy/teensy_context.c create mode 100644 teensy/teensy_context.h create mode 100644 teensy/teensy_list.c create mode 100644 teensy/teensy_list.h create mode 100644 teensy/teensy_log.c create mode 100644 teensy/teensy_log.h create mode 100644 teensy/teensy_mem.c create mode 100644 teensy/teensy_mem.h create mode 100644 teensy/teensy_platform.h create mode 100644 teensy/teensy_renderer.c create mode 100644 teensy/teensy_renderer.h (limited to 'teensy') diff --git a/teensy/common.c b/teensy/common.c deleted file mode 100644 index 4da4004..0000000 --- a/teensy/common.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "common.h" - -#include -#include - -char *read_file(const char *path, size_t *size_out) -{ - FILE *file = fopen(path, "r"); - if (!file) - ty_log_fatal(TY_ERR_IO, "could not open file '%s'", path); - - fseek(file, 0L, SEEK_END); - size_t size = ftell(file); - rewind(file); - - char *dat = ty_alloc(sizeof(char) * (size + 1)); - - size_t bytes_read = fread(dat, sizeof(char), size, file); - - if (bytes_read < size) { - ty_log_fatal(TY_ERR_IO, "could not read file '%s'", path); - } - - fclose(file); - - if (size_out) - *size_out = size; - - return dat; -} diff --git a/teensy/common.h b/teensy/common.h deleted file mode 100644 index 6e3e66f..0000000 --- a/teensy/common.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef COMMON_H_ -#define COMMON_H_ - -#include -#include -#include - -#include "log.h" -#include "mem.h" - -#define TY_PI 3.14 -#define TY_DEG2RAD (180 / PI) - -#endif // COMMON_H_ diff --git a/teensy/context.c b/teensy/context.c deleted file mode 100644 index 060254c..0000000 --- a/teensy/context.c +++ /dev/null @@ -1,61 +0,0 @@ -#include "context.h" -#include "renderer.h" - -#include -#include - -#include "platform.h" - -struct ty_ctx ctx; -extern struct ty_renderer r; - -void ty_init(struct ty_creation_hints creation_hints) -{ - ty_init_mem(); - - ctx.creation_hints = creation_hints; - ctx.ticrate = 1.0 / creation_hints.ticrate; - ctx.prev_tic_ts = 0; - - ty_platform_init(&ctx); - ty_init_renderer(); -} - -void ty_deinit(void) -{ - ty_platform_deinit(); - ty_deinit_renderer(); - ty_deinit_mem(); -} - -bool ty_is_game_running(void) -{ - return !ty_platform_os_wants_quit(); -} - -double ty_get_time(void) -{ - return ty_platform_get_time(); -} - -int ty_tick(void) -{ - double current_time = ty_get_time(); - double time_since_tic = current_time - ctx.prev_tic_ts; - - int tics = time_since_tic / ctx.ticrate; - if (tics > 0) { - ctx.prev_tic_ts = current_time; - ty_platform_frame(r.screen); - } - return tics; -} - -// TODO: Find a better place for this -void ty_sleep(uint64_t ms) -{ - struct timespec ts; - ts.tv_sec = ms / 1000; - ts.tv_nsec = (ms % 1000) * 1000000; - nanosleep(&ts, NULL); -} diff --git a/teensy/context.h b/teensy/context.h deleted file mode 100644 index 0bdc5f9..0000000 --- a/teensy/context.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef CONTEXT_H_ -#define CONTEXT_H_ - -#include "common.h" -#include "renderer.h" -#include "teensy.h" - -extern struct ty_ctx ctx; - -#endif // CONTEXT_H_ diff --git a/teensy/dyn_arr.c b/teensy/dyn_arr.c deleted file mode 100644 index 46e619d..0000000 --- a/teensy/dyn_arr.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "dyn_arr.h" - -#include -#include - -void *ty_list_create(void) -{ - struct ty_list_header *header = ty_alloc(sizeof(struct ty_list_header)); - header->cap = 0; - header->len = 0; - return (void*)(header + 1); -} diff --git a/teensy/dyn_arr.h b/teensy/dyn_arr.h deleted file mode 100644 index a764cda..0000000 --- a/teensy/dyn_arr.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef DYN_ARR_H_ -#define DYN_ARR_H_ - -#include "common.h" -#include "mem.h" - -struct ty_list_header { - size_t cap; - size_t len; -}; - -#define TY_LIST_MIN_CAP 8 -#define TY_LIST_GROW_RATE 2 - -#define ty_list_get_header(arr) ((struct ty_list_header*)arr - 1) -#define ty_list_cap(arr) (ty_list_get_header(arr)->cap) -#define ty_list_len(arr) (ty_list_get_header(arr)->len) - - -#define ty_list_reserve(arr, amt) \ - do { \ - struct ty_list_header *header = ty_list_get_header(arr); \ - if (amt > header->cap) { \ - header->cap = header->cap < TY_LIST_MIN_CAP \ - ? TY_LIST_MIN_CAP \ - : header->cap * TY_LIST_GROW_RATE \ - header = ty_realloc( \ - header, \ - (sizeof(*(arr)) * count) + sizeof(struct ty_list_header) \ - ); \ - (arr) = (void*)(header + 1); \ - } \ - } while (0) - -#define ty_list_append(arr, elem) \ - do { \ - struct ty_list_header *header = ty_list_get_header(arr); \ - ty_list_reserve(arr, header->len + 1); \ - (arr)[header->len++] = (elem); \ - } while (0) - -#define ty_list_clear(arr) \ - (ty_list_get_header(arr)->len = 0) - -#define ty_list_free(arr) (ty_free(ty_list_get_header(arr))) - -void *ty_list_create(void); - -#endif // DYN_ARR_H_ diff --git a/teensy/log.c b/teensy/log.c deleted file mode 100644 index fbd96a2..0000000 --- a/teensy/log.c +++ /dev/null @@ -1,33 +0,0 @@ -#include "log.h" - -#include - -#include "common.h" - -void ty_log_msg( - FILE *file, - const char *src_name, - int src_line, - const char *type, - const char *fmt, - ... -) -{ - fprintf(file, "[%s] (%s:%d) ", type, src_name, src_line); - - va_list args; - va_start(args, fmt); - vfprintf(file, fmt, args); - va_end(args); - - putc('\n', file); -} - -void _ty_log_plain(FILE *file, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - vfprintf(file, fmt, args); - va_end(args); - putc('\n', file); -} diff --git a/teensy/log.h b/teensy/log.h deleted file mode 100644 index cebf39b..0000000 --- a/teensy/log.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef LOG_H_ -#define LOG_H_ - -#include -#include - -// Don't include common.h, because this should be included there - -#define ty_log_info(fmt, ...) \ - ty_log_msg(stdout, __FILE__, __LINE__, "info", fmt, ## __VA_ARGS__) -#define ty_log_warn(fmt, ...) \ - ty_log_msg(stderr, __FILE__, __LINE__, "warn", fmt, ## __VA_ARGS__) -#define ty_log_err(fmt, ...) \ - ty_log_msg(stderr, __FILE__, __LINE__, "error", fmt, ## __VA_ARGS__) -#define ty_log_fatal(ec, fmt, ...) \ - (ty_log_msg(stderr, __FILE__, __LINE__, "fatal", fmt, ## __VA_ARGS__), \ - exit(ec)) -#define ty_olog(fmt, ...) \ - _log_plain(stdout, fmt, ## __VA_ARGS__) -#define ty_elog(fmt, ...) \ - _log_plain(stderr, fmt, ## __VA_ARGS__) - -// To be passed as the exit code to log_fatal() - -// General errors -#define TY_ERR_MEM 0x01 -#define TY_ERR_IO 0x02 -#define TY_ERR_MEM_LEAK 0x03 -#define TY_PLATFORM_ERR 0x04 - -// Rendering errors -#define TY_ERR_GLFW_INIT 0x30 -#define TY_ERR_RENDERER_NOT_INIT 0x31 -#define TY_ERR_RENDER_OOB 0x32 // Render out-of-bounds - -void ty_log_msg( - FILE *file, - const char *src_name, - int src_line, - const char *type, - const char *fmt, - ... -); - -void _ty_log_plain(FILE *file, const char *fmt, ...); - -#endif // LOG_H_ diff --git a/teensy/mem.c b/teensy/mem.c deleted file mode 100644 index fa885ca..0000000 --- a/teensy/mem.c +++ /dev/null @@ -1,171 +0,0 @@ -#include "mem.h" - -#include "common.h" -#include "dyn_arr.h" - -// Array to track temp allocations. -void **temp_allocations; - -#ifdef TEENSY_DEBUG - -#include - -#define BACKTRACE_SIZE 16 - -struct alloc { - void *ptr; - size_t size; - int backtrace_len; - char **backtrace; -}; - -int allocations_cap; -int allocations_len; -struct alloc *allocations; - -#endif // TODO TEENSY_DEBUG - -void ty_init_mem(void) -{ -#ifdef TEENSY_DEBUG - allocations_len = 0; - allocations_cap = 8; - allocations = malloc(sizeof(struct alloc) * 8); - if (!allocations) - ty_log_fatal(TY_ERR_MEM, "(%s) (track) ran out of memory", __func__); -#endif // TEENSY_DEBUG - - temp_allocations = ty_list_create(); -} - -void ty_deinit_mem(void) -{ - ty_list_free(temp_allocations); -#ifdef TEENSY_DEBUG - fprintf(stderr, "%d allocations leaked\n", allocations_len); - for (int i = 0; i < allocations_len; i++) { - struct alloc *alloc = &allocations[i]; - fprintf( - stderr, - "leaked %zu bytes at %p\n", - alloc->size, - alloc->ptr - ); - for (int j = 0; j < alloc->backtrace_len; j++) { - fprintf(stderr, "\t%s\n", alloc->backtrace[j]); - } - putc('\n', stderr); - - free(alloc->backtrace); - } - free(allocations); - - if (allocations_len > 0) - exit(TY_ERR_MEM_LEAK); -#endif // TEENSY_DEBUG -} - -void ty_free_temp_allocs(void) -{ - for (size_t i = 0; i < ty_list_len(temp_allocations); i++) { - void *temp = temp_allocations[i]; - ty_free(temp); - } - ty_list_clear(temp_allocations); -} - -void *ty_alloc(size_t size) -{ - void *ptr = malloc(size); - if (!ptr) - ty_log_fatal(TY_ERR_MEM, "(%s) ran out of memory", __func__); - -#ifdef TEENSY_DEBUG - // Log allocation - struct alloc alloc; - void *bt[BACKTRACE_SIZE]; - int bt_len = backtrace(bt, BACKTRACE_SIZE); - char **symbols = backtrace_symbols(bt, bt_len); - - alloc.ptr = ptr; - alloc.size = size; - alloc.backtrace_len = bt_len; - alloc.backtrace = symbols; - - if (allocations_len + 1 > allocations_cap) { - allocations_cap *= 2; - allocations = realloc( - allocations, - sizeof(struct alloc) * allocations_cap - ); - if (!allocations) - ty_log_fatal( - TY_ERR_MEM, - "(%s) (track) ran out of memory", - __func__ - ); - } - - allocations[allocations_len++] = alloc; -#endif // TEENSY_DEBUG - - return ptr; -} - -void *ty_realloc(void *ptr, size_t new_size) -{ - if (new_size == 0) { - ty_free(ptr); - return NULL; - } - - void *new_ptr = realloc(ptr, new_size); - if (!new_ptr) - ty_log_fatal(TY_ERR_MEM, "(%s) ran out of memory", __func__); - -#ifdef TEENSY_DEBUG - for (int i = 0; i < allocations_len; i++) { - struct alloc *alloc = &allocations[i]; - if (alloc->ptr == ptr) { - alloc->ptr = new_ptr; - alloc->size = new_size; - break; - } - } -#endif // TEENSY_DEBUG - - return new_ptr; -} - -void *ty_talloc(size_t size) -{ - void *ptr = ty_alloc(size); - ty_list_append(temp_allocations, ptr); - return ptr; -} - -void ty_free(void *ptr) -{ - free(ptr); - -#ifdef TEENSY_DEBUG - for (int i = 0; i < allocations_len; i++) { - struct alloc *alloc = &allocations[i]; - if (alloc->ptr == ptr) { - free(alloc->backtrace); - *alloc = allocations[allocations_len - 1]; - allocations_len--; - break; - } - } -#endif // TEENSY_DEBUG -} - -int ty_alloc_count(void) -{ -#ifdef TEENSY_DEBUG - return allocations_len; -#else - return -1; -#endif -} diff --git a/teensy/mem.h b/teensy/mem.h deleted file mode 100644 index 61f3ee2..0000000 --- a/teensy/mem.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef MEM_H_ -#define MEM_H_ - -#include - -// NOTE: Overrides GLFW allocator -void ty_init_mem(void); -void ty_deinit_mem(void); -void ty_free_temp_allocs(void); -// Temp allocation. Freed at the end of every frame. Do NOT realloc. -void *ty_talloc(size_t size); - -// These mem_* functions handle the case of a bad allocation. No need to check -// for NULL after allocating with these. In debug builds, they will also track -// allocations and report any memory still in use when the program exits. - -void *ty_alloc(size_t size); -void *ty_realloc(void *ptr, size_t new_size); -void ty_free(void *ptr); - -// Returns -1 in release builds. -int ty_alloc_count(void); - -#endif // MEM_H_ diff --git a/teensy/platform.h b/teensy/platform.h deleted file mode 100644 index df3c5f8..0000000 --- a/teensy/platform.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef PLATFORM_H_ -#define PLATFORM_H_ - -// This platform functions are to be implemented by a platform library. - -void ty_platform_init(struct ty_ctx *ctx); -void ty_platform_deinit(void); -void ty_platform_frame(struct ty_image img); -bool ty_platform_os_wants_quit(void); -double ty_platform_get_time(void); - -#endif // PLATFORM_H_ diff --git a/teensy/renderer.c b/teensy/renderer.c deleted file mode 100644 index 29dc871..0000000 --- a/teensy/renderer.c +++ /dev/null @@ -1,227 +0,0 @@ -#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 - ); - } -#else - (void)img; - (void)pos; -#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 dy = y1; dy < y2; dy++) { - for (int dx = x1; dx < x2; dx++) { - ty_img_set_pixel( - r.screen, - ty_vec2i(dx, dy), - ty_img_get_pixel(img, ty_vec2i(dx - x1, dy - y1)) - ); - } - } -} - -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, - 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, - 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, - 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(); -} diff --git a/teensy/renderer.h b/teensy/renderer.h deleted file mode 100644 index 70eac72..0000000 --- a/teensy/renderer.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef RENDERER_H_ -#define RENDERER_H_ - -#include "common.h" -#include "teensy.h" - -void ty_init_renderer(void); -void ty_deinit_renderer(void); - -#endif // RENDERER_H_ diff --git a/teensy/teensy.h b/teensy/teensy.h index c94986f..1f082f9 100644 --- a/teensy/teensy.h +++ b/teensy/teensy.h @@ -1,9 +1,9 @@ #ifndef TEENSY_H_ #define TEENSY_H_ -#include "common.h" -#include "context.h" -#include "dyn_arr.h" +#include "teensy_common.h" +#include "teensy_context.h" +#include "teensy_list.h" #define ty_vec2(x, y) ((struct ty_vec2){x, y}) #define ty_vec2i(x, y) ((struct ty_vec2i){x, y}) @@ -19,15 +19,15 @@ #define TY_COLOR_CYAN ty_color(0, 255, 255) #define TY_COLOR_WHITE ty_color(255, 255, 255) -struct ty_creation_hints { - int win_width; - int win_height; - const char *win_title; +struct ty_hints { + int scr_width; + int scr_height; + const char *game_title; int ticrate; }; struct ty_ctx { - struct ty_creation_hints creation_hints; + struct ty_hints hints; double ticrate; double prev_tic_ts; }; @@ -72,7 +72,7 @@ struct ty_renderer { struct ty_image screen; }; -void ty_init(struct ty_creation_hints creation_hints); +void ty_init(struct ty_hints hints); void ty_deinit(void); // Whether or not the main loop should continue executing. diff --git a/teensy/teensy_common.c b/teensy/teensy_common.c new file mode 100644 index 0000000..96d589e --- /dev/null +++ b/teensy/teensy_common.c @@ -0,0 +1,30 @@ +#include "teensy_common.h" + +#include +#include + +char *read_file(const char *path, size_t *size_out) +{ + FILE *file = fopen(path, "r"); + if (!file) + ty_log_fatal(TY_ERR_IO, "could not open file '%s'", path); + + fseek(file, 0L, SEEK_END); + size_t size = ftell(file); + rewind(file); + + char *dat = ty_alloc(sizeof(char) * (size + 1)); + + size_t bytes_read = fread(dat, sizeof(char), size, file); + + if (bytes_read < size) { + ty_log_fatal(TY_ERR_IO, "could not read file '%s'", path); + } + + fclose(file); + + if (size_out) + *size_out = size; + + return dat; +} diff --git a/teensy/teensy_common.h b/teensy/teensy_common.h new file mode 100644 index 0000000..dc631cb --- /dev/null +++ b/teensy/teensy_common.h @@ -0,0 +1,15 @@ +#ifndef TEENSY_COMMON_H_ +#define TEENSY_COMMON_H_ + +#include +#include +#include +#include + +#include "teensy_log.h" +#include "teensy_mem.h" + +#define TY_PI 3.14 +#define TY_DEG2RAD (180 / PI) + +#endif // TEENSY_COMMON_H_ diff --git a/teensy/teensy_context.c b/teensy/teensy_context.c new file mode 100644 index 0000000..4a812dd --- /dev/null +++ b/teensy/teensy_context.c @@ -0,0 +1,74 @@ +#include "teensy_context.h" +#include "teensy_renderer.h" + +#include +#include + +#include "teensy_platform.h" + +struct ty_ctx ctx; +extern struct ty_renderer r; + +bool is_init(void) +{ + int scr_size = ctx.hints.scr_width * ctx.hints.scr_height; + return scr_size > 0; +} + +void ty_init(struct ty_hints hints) +{ + ty_init_mem(); + + ctx.hints = hints; + ctx.ticrate = 1.0 / hints.ticrate; + ctx.prev_tic_ts = 0; + + ty_platform_init(&ctx); + ty_init_renderer(); +} + +void ty_deinit(void) +{ + assert(is_init()); + ty_platform_deinit(); + ty_deinit_renderer(); + ty_deinit_mem(); +} + +bool ty_is_game_running(void) +{ + assert(is_init()); + return !ty_platform_os_wants_quit(); +} + +double ty_get_time(void) +{ + assert(is_init()); + return ty_platform_get_time(); +} + +int ty_tick(void) +{ + assert(is_init()); + + double current_time = ty_get_time(); + double time_since_tic = current_time - ctx.prev_tic_ts; + + int tics = time_since_tic / ctx.ticrate; + if (tics > 0) { + ctx.prev_tic_ts = current_time; + ty_platform_frame(r.screen); + } + return tics; +} + +// TODO: Find a better place for this +void ty_sleep(uint64_t ms) +{ + assert(is_init()); + + struct timespec ts; + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * 1000000; + nanosleep(&ts, NULL); +} diff --git a/teensy/teensy_context.h b/teensy/teensy_context.h new file mode 100644 index 0000000..056a0c2 --- /dev/null +++ b/teensy/teensy_context.h @@ -0,0 +1,12 @@ +#ifndef TEENSY_CONTEXT_H_ +#define TEENSY_CONTEXT_H_ + +#include "teensy_common.h" +#include "teensy_renderer.h" +#include "teensy.h" + +extern struct ty_ctx ctx; + +bool is_init(void); + +#endif // TEENSY_CONTEXT_H_ diff --git a/teensy/teensy_list.c b/teensy/teensy_list.c new file mode 100644 index 0000000..c8035b8 --- /dev/null +++ b/teensy/teensy_list.c @@ -0,0 +1,12 @@ +#include "teensy_list.h" + +#include +#include + +void *ty_list_create(void) +{ + struct ty_list_header *header = ty_alloc(sizeof(struct ty_list_header)); + header->cap = 0; + header->len = 0; + return (void*)(header + 1); +} diff --git a/teensy/teensy_list.h b/teensy/teensy_list.h new file mode 100644 index 0000000..dd1e06a --- /dev/null +++ b/teensy/teensy_list.h @@ -0,0 +1,49 @@ +#ifndef TEENSY_LIST_H_ +#define TEENSY_LIST_H_ + +#include "teensy_common.h" +#include "teensy_mem.h" + +struct ty_list_header { + size_t cap; + size_t len; +}; + +#define TY_LIST_MIN_CAP 8 +#define TY_LIST_GROW_RATE 2 + +#define ty_list_get_header(arr) ((struct ty_list_header*)arr - 1) +#define ty_list_cap(arr) (ty_list_get_header(arr)->cap) +#define ty_list_len(arr) (ty_list_get_header(arr)->len) + + +#define ty_list_reserve(arr, amt) \ + do { \ + struct ty_list_header *header = ty_list_get_header(arr); \ + if (amt > header->cap) { \ + header->cap = header->cap < TY_LIST_MIN_CAP \ + ? TY_LIST_MIN_CAP \ + : header->cap * TY_LIST_GROW_RATE; \ + header = ty_realloc( \ + header, \ + (sizeof(*(arr)) * amt) + sizeof(struct ty_list_header) \ + ); \ + (arr) = (void*)(header + 1); \ + } \ + } while (0) + +#define ty_list_append(arr, elem) \ + do { \ + struct ty_list_header *header = ty_list_get_header(arr); \ + ty_list_reserve(arr, header->len + 1); \ + (arr)[header->len++] = (elem); \ + } while (0) + +#define ty_list_clear(arr) \ + (ty_list_get_header(arr)->len = 0) + +#define ty_list_free(arr) (ty_free(ty_list_get_header(arr))) + +void *ty_list_create(void); + +#endif // TEENSY_LIST_H_ diff --git a/teensy/teensy_log.c b/teensy/teensy_log.c new file mode 100644 index 0000000..26672a4 --- /dev/null +++ b/teensy/teensy_log.c @@ -0,0 +1,33 @@ +#include "teensy_log.h" + +#include + +#include "teensy_common.h" + +void ty_log_msg( + FILE *file, + const char *src_name, + int src_line, + const char *type, + const char *fmt, + ... +) +{ + fprintf(file, "[%s] (%s:%d) ", type, src_name, src_line); + + va_list args; + va_start(args, fmt); + vfprintf(file, fmt, args); + va_end(args); + + putc('\n', file); +} + +void _ty_log_plain(FILE *file, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(file, fmt, args); + va_end(args); + putc('\n', file); +} diff --git a/teensy/teensy_log.h b/teensy/teensy_log.h new file mode 100644 index 0000000..825ce55 --- /dev/null +++ b/teensy/teensy_log.h @@ -0,0 +1,47 @@ +#ifndef TEENSY_LOG_H_ +#define TEENSY_LOG_H_ + +#include +#include + +// Don't include common.h, because this should be included there + +#define ty_log_info(fmt, ...) \ + ty_log_msg(stdout, __FILE__, __LINE__, "info", fmt, ## __VA_ARGS__) +#define ty_log_warn(fmt, ...) \ + ty_log_msg(stderr, __FILE__, __LINE__, "warn", fmt, ## __VA_ARGS__) +#define ty_log_err(fmt, ...) \ + ty_log_msg(stderr, __FILE__, __LINE__, "error", fmt, ## __VA_ARGS__) +#define ty_log_fatal(ec, fmt, ...) \ + (ty_log_msg(stderr, __FILE__, __LINE__, "fatal", fmt, ## __VA_ARGS__), \ + exit(ec)) +#define ty_olog(fmt, ...) \ + _log_plain(stdout, fmt, ## __VA_ARGS__) +#define ty_elog(fmt, ...) \ + _log_plain(stderr, fmt, ## __VA_ARGS__) + +// To be passed as the exit code to log_fatal() + +// General errors +#define TY_ERR_MEM 0x01 +#define TY_ERR_IO 0x02 +#define TY_ERR_MEM_LEAK 0x03 +#define TY_PLATFORM_ERR 0x04 + +// Rendering errors +#define TY_ERR_GLFW_INIT 0x30 +#define TY_ERR_RENDERER_NOT_INIT 0x31 +#define TY_ERR_RENDER_OOB 0x32 // Render out-of-bounds + +void ty_log_msg( + FILE *file, + const char *src_name, + int src_line, + const char *type, + const char *fmt, + ... +); + +void _ty_log_plain(FILE *file, const char *fmt, ...); + +#endif // TEENSY_LOG_H_ diff --git a/teensy/teensy_mem.c b/teensy/teensy_mem.c new file mode 100644 index 0000000..2a6d992 --- /dev/null +++ b/teensy/teensy_mem.c @@ -0,0 +1,171 @@ +#include "teensy_mem.h" + +#include "teensy_common.h" +#include "teensy_list.h" + +// Array to track temp allocations. +void **temp_allocations; + +#ifdef TEENSY_DEBUG + +#include + +#define BACKTRACE_SIZE 16 + +struct alloc { + void *ptr; + size_t size; + int backtrace_len; + char **backtrace; +}; + +int allocations_cap; +int allocations_len; +struct alloc *allocations; + +#endif // TODO TEENSY_DEBUG + +void ty_init_mem(void) +{ +#ifdef TEENSY_DEBUG + allocations_len = 0; + allocations_cap = 8; + allocations = malloc(sizeof(struct alloc) * 8); + if (!allocations) + ty_log_fatal(TY_ERR_MEM, "(%s) (track) ran out of memory", __func__); +#endif // TEENSY_DEBUG + + temp_allocations = ty_list_create(); +} + +void ty_deinit_mem(void) +{ + ty_list_free(temp_allocations); +#ifdef TEENSY_DEBUG + fprintf(stderr, "%d allocations leaked\n", allocations_len); + for (int i = 0; i < allocations_len; i++) { + struct alloc *alloc = &allocations[i]; + fprintf( + stderr, + "leaked %zu bytes at %p\n", + alloc->size, + alloc->ptr + ); + for (int j = 0; j < alloc->backtrace_len; j++) { + fprintf(stderr, "\t%s\n", alloc->backtrace[j]); + } + putc('\n', stderr); + + free(alloc->backtrace); + } + free(allocations); + + if (allocations_len > 0) + exit(TY_ERR_MEM_LEAK); +#endif // TEENSY_DEBUG +} + +void ty_free_temp_allocs(void) +{ + for (size_t i = 0; i < ty_list_len(temp_allocations); i++) { + void *temp = temp_allocations[i]; + ty_free(temp); + } + ty_list_clear(temp_allocations); +} + +void *ty_alloc(size_t size) +{ + void *ptr = malloc(size); + if (!ptr) + ty_log_fatal(TY_ERR_MEM, "(%s) ran out of memory", __func__); + +#ifdef TEENSY_DEBUG + // Log allocation + struct alloc alloc; + void *bt[BACKTRACE_SIZE]; + int bt_len = backtrace(bt, BACKTRACE_SIZE); + char **symbols = backtrace_symbols(bt, bt_len); + + alloc.ptr = ptr; + alloc.size = size; + alloc.backtrace_len = bt_len; + alloc.backtrace = symbols; + + if (allocations_len + 1 > allocations_cap) { + allocations_cap *= 2; + allocations = realloc( + allocations, + sizeof(struct alloc) * allocations_cap + ); + if (!allocations) + ty_log_fatal( + TY_ERR_MEM, + "(%s) (track) ran out of memory", + __func__ + ); + } + + allocations[allocations_len++] = alloc; +#endif // TEENSY_DEBUG + + return ptr; +} + +void *ty_realloc(void *ptr, size_t new_size) +{ + if (new_size == 0) { + ty_free(ptr); + return NULL; + } + + void *new_ptr = realloc(ptr, new_size); + if (!new_ptr) + ty_log_fatal(TY_ERR_MEM, "(%s) ran out of memory", __func__); + +#ifdef TEENSY_DEBUG + for (int i = 0; i < allocations_len; i++) { + struct alloc *alloc = &allocations[i]; + if (alloc->ptr == ptr) { + alloc->ptr = new_ptr; + alloc->size = new_size; + break; + } + } +#endif // TEENSY_DEBUG + + return new_ptr; +} + +void *ty_talloc(size_t size) +{ + void *ptr = ty_alloc(size); + ty_list_append(temp_allocations, ptr); + return ptr; +} + +void ty_free(void *ptr) +{ + free(ptr); + +#ifdef TEENSY_DEBUG + for (int i = 0; i < allocations_len; i++) { + struct alloc *alloc = &allocations[i]; + if (alloc->ptr == ptr) { + free(alloc->backtrace); + *alloc = allocations[allocations_len - 1]; + allocations_len--; + break; + } + } +#endif // TEENSY_DEBUG +} + +int ty_alloc_count(void) +{ +#ifdef TEENSY_DEBUG + return allocations_len; +#else + return -1; +#endif +} diff --git a/teensy/teensy_mem.h b/teensy/teensy_mem.h new file mode 100644 index 0000000..da2fed9 --- /dev/null +++ b/teensy/teensy_mem.h @@ -0,0 +1,24 @@ +#ifndef TEENSY_MEM_H_ +#define TEENSY_MEM_H_ + +#include + +// NOTE: Overrides GLFW allocator +void ty_init_mem(void); +void ty_deinit_mem(void); +void ty_free_temp_allocs(void); +// Temp allocation. Freed at the end of every frame. Do NOT realloc. +void *ty_talloc(size_t size); + +// These mem_* functions handle the case of a bad allocation. No need to check +// for NULL after allocating with these. In debug builds, they will also track +// allocations and report any memory still in use when the program exits. + +void *ty_alloc(size_t size); +void *ty_realloc(void *ptr, size_t new_size); +void ty_free(void *ptr); + +// Returns -1 in release builds. +int ty_alloc_count(void); + +#endif // TEENSY_MEM_H_ diff --git a/teensy/teensy_platform.h b/teensy/teensy_platform.h new file mode 100644 index 0000000..7733be1 --- /dev/null +++ b/teensy/teensy_platform.h @@ -0,0 +1,12 @@ +#ifndef TEENSY_PLATFORM_H_ +#define TEENSY_PLATFORM_H_ + +// This platform functions are to be implemented by a platform library. + +void ty_platform_init(struct ty_ctx *ctx); +void ty_platform_deinit(void); +void ty_platform_frame(struct ty_image img); +bool ty_platform_os_wants_quit(void); +double ty_platform_get_time(void); + +#endif // TEENSY_PLATFORM_H_ diff --git a/teensy/teensy_renderer.c b/teensy/teensy_renderer.c new file mode 100644 index 0000000..b29e485 --- /dev/null +++ b/teensy/teensy_renderer.c @@ -0,0 +1,217 @@ +#include "teensy_renderer.h" + +#include +#include +#include + +#include "teensy_context.h" +#include "teensy_list.h" + +struct ty_renderer r; + +static +bool is_renderer_init(void) +{ + return r.screen.data != NULL && r.screen.width * r.screen.height != 0; +} + +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 + ); + } +#else + (void)img; + (void)pos; +#endif +} + +void ty_init_renderer(void) +{ + r.screen = ty_create_image( + ctx.hints.scr_width, + ctx.hints.scr_height, + NULL + ); +} + +void ty_deinit_renderer(void) +{ + assert(is_renderer_init()); + + 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) +{ + assert(is_renderer_init()); + 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 dy = y1; dy < y2; dy++) { + for (int dx = x1; dx < x2; dx++) { + ty_img_set_pixel( + r.screen, + ty_vec2i(dx, dy), + ty_img_get_pixel(img, ty_vec2i(dx - x1, dy - y1)) + ); + } + } +} + +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, + 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, + 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, + 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) +{ + assert(is_renderer_init()); +} diff --git a/teensy/teensy_renderer.h b/teensy/teensy_renderer.h new file mode 100644 index 0000000..7002890 --- /dev/null +++ b/teensy/teensy_renderer.h @@ -0,0 +1,10 @@ +#ifndef TEENSY_RENDERER_H_ +#define TEENSY_RENDERER_H_ + +#include "teensy_common.h" +#include "teensy.h" + +void ty_init_renderer(void); +void ty_deinit_renderer(void); + +#endif // TEENSY_RENDERER_H_ -- cgit v1.3-2-g0d8e