From 2d7cc7f8218ce7d8edec9b2009a2d38086a40644 Mon Sep 17 00:00:00 2001 From: kdx Date: Sat, 4 Mar 2023 18:09:04 +0100 Subject: initial commit --- .gitignore | 4 + Makefile | 30 +++ TZR.c | 682 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ TZR.h | 244 +++++++++++++++++++ compile_flags.txt | 5 + main.c | 25 ++ 6 files changed, 990 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 TZR.c create mode 100644 TZR.h create mode 100644 compile_flags.txt create mode 100644 main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bbf637d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +7drl2023 +tags +a.out diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9224fc5 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +CC := gcc +LD := $(CC) +SDL2-CONFIG := sdl2-config +DEBUGFLAGS := -g -O0 +CFLAGS := $(DEBUGFLAGS) -std=c99 -Wall -Wextra -Wno-override-init \ + $(shell $(SDL2-CONFIG) --cflags) +LDFLAGS := $(DEBUGFLAGS) -lm $(shell $(SDL2-CONFIG) --libs) -lSDL2_image +SRC := $(wildcard *.c) +OBJ := $(patsubst %.c,%.o,$(SRC)) +NAME := 7drl2023 + +all: $(NAME) + +$(NAME): $(OBJ) + $(LD) -o $(NAME) $(OBJ) $(LDFLAGS) + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +run: all + ./$(NAME) + +clean: + rm -f $(NAME) $(OBJ) + +re: + make --no-print-directory clean + make --no-print-directory all + +.PHONY: all run clean re diff --git a/TZR.c b/TZR.c new file mode 100644 index 0000000..8ee0ec1 --- /dev/null +++ b/TZR.c @@ -0,0 +1,682 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "TZR.h" +#include + +/* sources/drain.h */ + +static void *drain_error(void) +{ + perror("TZR_LoadResourceTyped:drain"); + return NULL; +} + +static char *drain(FILE *fp, size_t *size) +{ + if (fseek(fp, 0, SEEK_END) < 0) + return drain_error(); + *size = ftell(fp); + if (fseek(fp, 0, SEEK_SET) < 0) + return drain_error(); + char *data = malloc(*size); + if (data == NULL) + return drain_error(); + if (fread(data, 1, *size, fp) != *size) + return free(data), drain_error(); + return data; +} + +/* sources/sdl_error.h */ + +static int sdl_error(int rv) +{ + SDL_Log("%s\n", SDL_GetError()); + return rv; +} +/* sources/sdl_rect_to_rect.h */ + +static void TZR_RectFromSDLRect(TZR_Rect *dest, const SDL_Rect *src) +{ + dest->from.x = src->x; + dest->from.y = src->y; + dest->to.x = src->x + src->w - 1; + dest->to.y = src->y + src->h - 1; +} +/* sources/globals.c */ + +TZR_Config ___tzr_config = {0}; +TZR_Color ___tzr_color = {0, 0.0f, 0.0f, 0.0f, 1.0f}; +TZR_Resource *___tzr_resources = NULL; +size_t ___tzr_resources_capacity = 0; +size_t ___tzr_resources_size = 0; +SDL_Window *___tzr_window = NULL; +SDL_Renderer *___tzr_renderer = NULL; +SDL_Texture *___tzr_target = NULL; +unsigned long ___tzr_tick = 0; +unsigned long ___tzr_next_time = 0; +unsigned long ___tzr_min_dt = 0; +int ___tzr_should_quit = 0; +int ___tzr_mouse_x = 0; +int ___tzr_mouse_y = 0; +const char *___tzr_command[___TZR_RES_COUNT] = {0}; +TZR_KeyState ___tzr_keystates[SDL_NUM_SCANCODES] = {0}; +/* sources/TZR_CycleEvents.c */ + +void TZR_CycleEvents(void) +{ + TZR_ResourcesWatch(); + for (int i = 0; i < SDL_NUM_SCANCODES; i++) { + TZR_KeyState *const keystate = &___tzr_keystates[i]; + switch (*keystate) { + case TZR_KEYSTATE_RELEASE: + case TZR_KEYSTATE_UP: + *keystate = TZR_KEYSTATE_UP; + break; + case TZR_KEYSTATE_PRESS: + case TZR_KEYSTATE_DOWN: + *keystate = TZR_KEYSTATE_DOWN; + break; + default: + break; + } + } + TZR_Event e; + while (TZR_PollEvent(&e)) + ; +} +/* sources/TZR_DestroyResource.c */ + +void TZR_DestroyResource(TZR_Resource *res, int free_path) +{ + if (res->path != NULL && free_path) + free(res->path); + switch (res->type) { + case TZR_RES_RAW: + if (res->raw.data != NULL) + free(res->raw.data); + break; + case TZR_RES_IMAGE: + if (res->image.ptr != NULL) + SDL_DestroyTexture(res->image.ptr); + break; + default: + fprintf(stderr, "unknown resource type %u\n", res->type); + break; + } +} + +/* sources/TZR_DirectResourceLoad.c */ + +int TZR_DirectResourceLoad(TZR_Resource *res, const void *data, int size) +{ + switch (res->type) { + case TZR_RES_RAW: + res->raw.size = size; + res->raw.data = malloc(size); + if (res->raw.data == NULL) { + perror("TZR_DirectResourceLoad"); + return -1; + } + memcpy(res->raw.data, data, size); + break; + case TZR_RES_IMAGE: { + SDL_RWops *const rw = SDL_RWFromConstMem(data, size); + if (rw == NULL) + return sdl_error(-1); + SDL_Surface *const surf = IMG_Load_RW(rw, 0); + SDL_RWclose(rw); + if (surf == NULL) + return sdl_error(-1); + SDL_Texture *const tex = + SDL_CreateTextureFromSurface(___tzr_renderer, surf); + SDL_FreeSurface(surf); + if (tex == NULL) + return sdl_error(-1); + if (SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND) < 0) { + SDL_DestroyTexture(tex); + return sdl_error(-1); + } + if (SDL_QueryTexture(tex, NULL, NULL, + &res->image.width, &res->image.height)) { + SDL_DestroyTexture(tex); + return sdl_error(-1); + } + res->image.ptr = tex; + } break; + default: + fprintf(stderr, "invalid type\n"); + return -1; + } + return 0; +} +/* sources/TZR_DrawBegin.c */ + +int TZR_DrawBegin(void) +{ + if (SDL_SetRenderTarget(___tzr_renderer, ___tzr_target) < 0) + return sdl_error(-1); + return 0; +} +/* sources/TZR_DrawClear.c */ + +int TZR_DrawClear(void) +{ + if (SDL_RenderClear(___tzr_renderer) < 0) + return sdl_error(-1); + return 0; +} +/* sources/TZR_DrawEnd.c */ + +int TZR_DrawEnd(void) +{ + if (SDL_SetRenderTarget(___tzr_renderer, NULL) < 0) + return sdl_error(-1); + if (SDL_SetRenderDrawColor(___tzr_renderer, 0, 0, 0, 255) < 0) + return sdl_error(-1); + if (SDL_RenderClear(___tzr_renderer) < 0) + return sdl_error(-1); + + int win_w, win_h; + SDL_GetWindowSize(___tzr_window, &win_w, &win_h); + win_w = win_w ? win_w : 1; + win_h = win_h ? win_h : 1; + + const float ratio_w = win_w / (float)___tzr_config.width; + const float ratio_h = win_h / (float)___tzr_config.height; + float scale = (ratio_w < ratio_h) ? ratio_w : ratio_h; + if (scale > 1.0f && ___tzr_config.pixel_perfect) + scale = (int)scale; + const int off_x = (win_w - ___tzr_config.width * scale) / 2; + const int off_y = (win_h - ___tzr_config.height * scale) / 2; + const SDL_Rect dest = { + off_x, + off_y, + ___tzr_config.width * scale, + ___tzr_config.height * scale + }; + + if (SDL_RenderCopy(___tzr_renderer, ___tzr_target, NULL, &dest) < 0) + return sdl_error(-1); + if (___tzr_config.target_fps > 0) { + ___tzr_next_time += ___tzr_min_dt; + const unsigned long cur_time = SDL_GetTicks64(); + if (___tzr_next_time <= cur_time) + ___tzr_next_time = cur_time; + else + SDL_Delay(___tzr_next_time - cur_time); + } + SDL_RenderPresent(___tzr_renderer); + ___tzr_tick += 1; + return 0; +} +/* sources/TZR_DrawImage.c */ + +int _TZR_DrawImage(const TZR_DrawImageArgs *args) +{ + if (TZR_GetResourceType(args->id) != TZR_RES_IMAGE) { + fprintf(stderr, "%u isn't an image\n", args->id); + return -1; + } + TZR_Resource *const res = TZR_GetResourcePointer(args->id); + const TZR_Image *const img = &res->image; + + if (SDL_SetTextureColorMod(img->ptr, ___tzr_color.r * 255, + ___tzr_color.g * 255, ___tzr_color.b * 255)) + return sdl_error(-1); + if (SDL_SetTextureAlphaMod(img->ptr, ___tzr_color.a * 255)) + return sdl_error(-1); + + float scale_x = args->sx; + float scale_y = args->sy; + + int simg_width = (args->w == INT_MIN) ? img->width : args->w; + if (simg_width < 0) { + simg_width *= -1; + scale_x *= -1; + } + if (simg_width + args->ix > img->width) + simg_width = img->width - args->ix; + + int simg_height = (args->h == INT_MIN) ? img->height : args->h; + if (simg_height < 0) { + simg_height *= -1; + scale_y *= -1; + } + if (simg_height + args->iy > img->height) + simg_height = img->height - args->iy; + + const int flip = (SDL_FLIP_HORIZONTAL * (scale_x < 0.0f)) | + (SDL_FLIP_VERTICAL * (scale_y < 0.0f)); + const SDL_Rect src = { + args->ix, + args->iy, + simg_width, + simg_height + }; + + const int width = simg_width * fabs(scale_x); + const int height = simg_height * fabs(scale_y); + const int x = args->x - (scale_x < 0.0f ? width : 0); + const int y = args->y - (scale_y < 0.0f ? height : 0); + + const SDL_Rect dest = { + x - (args->center ? (simg_width * scale_x / 2) : 0), + y - (args->center ? (simg_height * scale_y / 2) : 0), + width, + height + }; + if (SDL_RenderCopyEx(___tzr_renderer, img->ptr, &src, &dest, + args->r * 360, NULL, flip) < 0) + return sdl_error(-1); + TZR_Rect area; + TZR_RectFromSDLRect(&area, &dest); + return 0; +} +/* sources/TZR_DrawLine.c */ + +int TZR_DrawLine(int x0, int y0, int x1, int y1) +{ + if (SDL_RenderDrawLine(___tzr_renderer, x0, y0, x1, y1) < 0) + return sdl_error(-1); + return 0; +} +/* sources/TZR_DrawPoint.c */ + +int TZR_DrawPoint(int x, int y) +{ + if (SDL_RenderDrawPoint(___tzr_renderer, x, y) < 0) + return sdl_error(-1); + return 0; +} +/* sources/TZR_DrawRectangle.c */ + +int TZR_DrawRectangle(bool fill, int x, int y, int w, int h) +{ + const SDL_Rect rect = { x, y, w, h }; + if (fill) { + if (SDL_RenderFillRect(___tzr_renderer, &rect) < 0) + return sdl_error(-1); + } else { + if (SDL_RenderDrawRect(___tzr_renderer, &rect) < 0) + return sdl_error(-1); + } + return 0; +} +/* sources/TZR_DrawSetColor.c */ + +int _TZR_DrawSetColor(const TZR_Color *color) +{ + ___tzr_color.r = (color->r < 0.0f) ? ___tzr_color.r : color->r; + ___tzr_color.g = (color->g < 0.0f) ? ___tzr_color.g : color->g; + ___tzr_color.b = (color->b < 0.0f) ? ___tzr_color.b : color->b; + ___tzr_color.a = (color->a < 0.0f) ? ___tzr_color.a : color->a; + const uint8_t r = ___tzr_color.r * 255; + const uint8_t g = ___tzr_color.g * 255; + const uint8_t b = ___tzr_color.b * 255; + const uint8_t a = ___tzr_color.a * 255; + if (SDL_SetRenderDrawColor(___tzr_renderer, r, g, b, a) < 0) + return sdl_error(-1); + return 0; +} +/* sources/TZR_GetImageHeight.c */ + +int TZR_GetImageHeight(TZR_Uint id) +{ + return TZR_GetResourcePointer(id)->image.height; +} +/* sources/TZR_GetImageWidth.c */ + +int TZR_GetImageWidth(TZR_Uint id) +{ + return TZR_GetResourcePointer(id)->image.width; +} +/* sources/TZR_GetKeyState.c */ + +TZR_KeyState TZR_GetKeyState(int scancode) +{ + return ___tzr_keystates[scancode]; +} +/* sources/TZR_GetRawResource.c */ + +TZR_Raw *TZR_GetRawResource(TZR_Uint id) +{ + return &TZR_GetResourcePointer(id)->raw; +} +/* sources/TZR_GetResourcePath.c */ + +const char *TZR_GetResourcePath(TZR_Uint id) +{ + return TZR_GetResourcePointer(id)->path; +} +/* sources/TZR_GetResourcePointer.c */ + +TZR_Resource *TZR_GetResourcePointer(TZR_Uint id) +{ + return &___tzr_resources[id - 1]; +} +/* sources/TZR_GetResourceType.c */ + +TZR_ResourceType TZR_GetResourceType(TZR_Uint id) +{ + return TZR_GetResourcePointer(id)->type; +} +/* sources/TZR_GetTick.c */ + +unsigned long TZR_GetTick(void) +{ + return ___tzr_tick; +} +/* sources/TZR_Init.c */ + +static int _sdl_error(void) +{ + sdl_error(-1); + TZR_Quit(); + return -1; +} + +int _TZR_Init(const TZR_Config *config) +{ + if (SDL_Init(SDL_INIT_VIDEO) < 0) + return _sdl_error(); + if (IMG_Init(IMG_INIT_PNG) < 0) + return _sdl_error(); + + memcpy(&___tzr_config, config, sizeof(TZR_Config)); + char *const basepath = SDL_GetBasePath(); + if (basepath == NULL) + return _sdl_error(); + const int chdir_rv = chdir(basepath); + SDL_free(basepath); + if (chdir_rv < 0) + return perror("TZR_Init"), -1; + + ___tzr_window = SDL_CreateWindow("TZR", SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + ___tzr_config.width, + ___tzr_config.height, + SDL_WINDOW_RESIZABLE); + if (___tzr_window == NULL) + return _sdl_error(); + + ___tzr_renderer = SDL_CreateRenderer(___tzr_window, -1, + SDL_RENDERER_ACCELERATED); + if (___tzr_renderer == NULL) + return _sdl_error(); + + ___tzr_target = SDL_CreateTexture(___tzr_renderer, + SDL_PIXELFORMAT_RGB888, + SDL_TEXTUREACCESS_TARGET, + ___tzr_config.width, + ___tzr_config.height); + if (___tzr_target == NULL) + return _sdl_error(); + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, 0); + ___tzr_tick = 0; + + if (___tzr_config.target_fps > 0) { + ___tzr_min_dt = 1000 / ___tzr_config.target_fps; + ___tzr_next_time = SDL_GetTicks64(); + } + + ___tzr_command[TZR_RES_RAW] = getenv("TZR_EDIT_RAW"); + if (___tzr_command[TZR_RES_RAW] == NULL) + ___tzr_command[TZR_RES_RAW] = "foot nvim"; + ___tzr_command[TZR_RES_IMAGE] = getenv("TZR_EDIT_IMAGE"); + if (___tzr_command[TZR_RES_IMAGE] == NULL) + ___tzr_command[TZR_RES_IMAGE] = "gimp"; + return 0; +} +/* sources/TZR_IsKeyDown.c */ + +bool TZR_IsKeyDown(int scancode) +{ + const TZR_KeyState state = TZR_GetKeyState(scancode); + return (state == TZR_KEYSTATE_DOWN || state == TZR_KEYSTATE_PRESS); +} +/* sources/TZR_IsKeyPressed.c */ + +bool TZR_IsKeyPressed(int scancode) +{ + return (TZR_GetKeyState(scancode) == TZR_KEYSTATE_PRESS); +} +/* sources/TZR_IsKeyReleased.c */ + +bool TZR_IsKeyReleased(int scancode) +{ + if (TZR_GetKeyState(scancode) == TZR_KEYSTATE_RELEASE) + return true; + return false; +} +/* sources/TZR_IsKeyUp.c */ + +bool TZR_IsKeyUp(int scancode) +{ + const TZR_KeyState state = TZR_GetKeyState(scancode); + return (state == TZR_KEYSTATE_UP || state == TZR_KEYSTATE_RELEASE); +} +/* sources/TZR_LoadResource.c */ + +static TZR_ResourceType deduce_type(const char *path) +{ + const char *const path_extension = strrchr(path, '.'); + if (path_extension == NULL) + return TZR_RES_RAW; + if (strcasecmp(path_extension, ".bmp") == 0) + return TZR_RES_IMAGE; + return TZR_RES_RAW; +} + +TZR_Uint TZR_LoadResource(const char *path) +{ + return TZR_LoadResourceTyped(deduce_type(path), path); +} +/* sources/TZR_LoadResourceFromMemory.c */ + +static int reserve_ressources(size_t size) +{ + if (size <= ___tzr_resources_capacity) + return 0; + size_t target = 16; + while (target < size * sizeof(TZR_Resource)) + target *= 2; + TZR_Resource *new_resources; + if (___tzr_resources == NULL) + new_resources = malloc(target); + else + new_resources = realloc(___tzr_resources, target); + if (new_resources == NULL) { + perror("TZR_LoadResourceFromMemory:reserve_ressources"); + return 1; + } + ___tzr_resources = new_resources; + return 0; +} + +TZR_Uint TZR_LoadResourceFromMemory(TZR_ResourceType type, const void *data, int size) +{ + if (reserve_ressources(___tzr_resources_size + 1)) { + fprintf(stderr, "failed to reserve for new ressource\n"); + return 0; + } + TZR_Resource *const res = &___tzr_resources[___tzr_resources_size]; + res->type = type; + res->path = NULL; + if (TZR_DirectResourceLoad(res, data, size)) + return 0; + ___tzr_resources_size += 1; + return ___tzr_resources_size; +} +/* sources/TZR_LoadResourceTyped.c */ + +TZR_Uint TZR_LoadResourceTyped(TZR_ResourceType type, const char *path) +{ + for (TZR_Uint i = 0; i < ___tzr_resources_size; i++) + if (___tzr_resources[i].type == type && + strcmp(___tzr_resources[i].path, path) == 0) + return i; + FILE *const fp = fopen(path, "rb"); + if (fp == NULL) { + perror(path); + return 0; + } + size_t size; + char *const data = drain(fp, &size); + fclose(fp); + if (data == NULL) + return 0; + const TZR_Uint id = TZR_LoadResourceFromMemory(type, data, size); + free(data); + if (id == 0) + return 0; + TZR_Resource *const res = TZR_GetResourcePointer(id); + + const size_t path_len = strlen(path); + struct stat st = {0}; + (void)stat(path, &st); + res->path = malloc(path_len + 1); + res->mtime = 0; + if (res->path == NULL) + perror("TZR_LoadResourceTyped"); + else + strcpy(res->path, path); + return id; +} +/* sources/TZR_PollEvent.c */ + +int TZR_PollEvent(TZR_Event *e) +{ + TZR_Event discard; + if (e == NULL) + e = &discard; + + SDL_Event se; + while (SDL_PollEvent(&se)) switch (se.type) { + case SDL_QUIT: + e->type = TZR_EV_QUIT; + ___tzr_should_quit = 1; + return 1; + case SDL_KEYDOWN: + if (se.key.repeat) + break; + e->type = TZR_EV_KEYDOWN; + e->button = se.key.keysym.scancode; + ___tzr_keystates[e->button] = TZR_KEYSTATE_PRESS; + break; + case SDL_KEYUP: + e->type = TZR_EV_KEYUP; + e->button = se.key.keysym.scancode; + ___tzr_keystates[e->button] = TZR_KEYSTATE_RELEASE; + break; + case SDL_MOUSEBUTTONDOWN: + ___tzr_mouse_x = se.button.x; + ___tzr_mouse_y = se.button.y; + break; + case SDL_MOUSEBUTTONUP: + ___tzr_mouse_x = se.button.x; + ___tzr_mouse_y = se.button.y; + break; + case SDL_MOUSEMOTION: + ___tzr_mouse_x = se.motion.x; + ___tzr_mouse_y = se.motion.y; + break; + default: + break; + } + return 0; +} +/* sources/TZR_Quit.c */ + +void TZR_Quit(void) +{ + for (size_t i = 0; i < ___tzr_resources_size; i++) + TZR_DestroyResource(&___tzr_resources[i], 1); + if (___tzr_resources != NULL) + free(___tzr_resources); + ___tzr_resources = NULL; + ___tzr_resources_size = 0; + ___tzr_resources_capacity = 0; + if (___tzr_target != NULL) { + SDL_DestroyTexture(___tzr_target); + ___tzr_target = NULL; + } + if (___tzr_renderer != NULL) { + SDL_DestroyRenderer(___tzr_renderer); + ___tzr_renderer = NULL; + } + if (___tzr_window != NULL) { + SDL_DestroyWindow(___tzr_window); + ___tzr_window = NULL; + } + IMG_Quit(); + SDL_Quit(); +} +/* sources/TZR_ReloadResource.c */ + +int TZR_ReloadResource(TZR_Uint id) +{ + TZR_Resource *const res = TZR_GetResourcePointer(id); + if (res->path == NULL) { + fprintf(stderr, "resource path of %u is NULL\n", id); + return -1; + } + FILE *const fp = fopen(res->path, "rb"); + if (fp == NULL) { + perror(res->path); + return -1; + } + size_t size; + char *const data = drain(fp, &size); + fclose(fp); + if (data == NULL) + return -1; + TZR_Resource new_res; + memcpy(&new_res, res, sizeof(TZR_Resource)); + const int load_rv = TZR_DirectResourceLoad(&new_res, data, size); + free(data); + if (load_rv) + return -1; + TZR_DestroyResource(res, 0); + memcpy(res, &new_res, sizeof(TZR_Resource)); + return 0; +} +/* sources/TZR_ResourcesWatch.c */ + +void TZR_ResourcesWatch(void) +{ + for (TZR_Uint i = 0; i < ___tzr_resources_size; i++) { + TZR_Resource *const res = TZR_GetResourcePointer(i + 1); + if (res->path == NULL) + continue; + struct stat st = {0}; + (void)stat(res->path, &st); + if (st.st_mtime != res->mtime) { + if (res->mtime != 0) + TZR_ReloadResource(i + 1); + res->mtime = st.st_mtime; + } + } +} +/* sources/TZR_ShouldQuit.c */ + +int TZR_ShouldQuit(void) +{ + return ___tzr_should_quit; +} + +/* commit hash: 41400167398f1ab5f5e8ee67a76358189085f17f */ diff --git a/TZR.h b/TZR.h new file mode 100644 index 0000000..2c1c1d2 --- /dev/null +++ b/TZR.h @@ -0,0 +1,244 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +/* headers/TZR_types.h */ + +enum TZR_ResourceType { + TZR_RES_RAW, + TZR_RES_IMAGE, + ___TZR_RES_COUNT +}; + +enum TZR_EventType { + TZR_EV_QUIT, + TZR_EV_KEYDOWN, + TZR_EV_KEYUP +}; + +enum TZR_KeyState { + TZR_KEYSTATE_UP, + TZR_KEYSTATE_DOWN, + TZR_KEYSTATE_RELEASE, + TZR_KEYSTATE_PRESS +}; + +typedef unsigned int TZR_Uint; +typedef struct TZR_Config TZR_Config; +typedef struct TZR_Point TZR_Point; +typedef struct TZR_Color TZR_Color; +typedef struct TZR_Rect TZR_Rect; +typedef enum TZR_ResourceType TZR_ResourceType; +typedef struct TZR_Raw TZR_Raw; +typedef struct TZR_Image TZR_Image; +typedef struct TZR_Resource TZR_Resource; +typedef enum TZR_EventType TZR_EventType; +typedef struct TZR_Event TZR_Event; +typedef struct TZR_DrawImageArgs TZR_DrawImageArgs; +typedef enum TZR_KeyState TZR_KeyState; + +struct TZR_Config { + int _; + int width; + int height; + int target_fps; + bool pixel_perfect; + const char *title; +}; + +struct TZR_Point { + int x; + int y; +}; + +struct TZR_Color { + int _; + float r; + float g; + float b; + float a; +}; + +struct TZR_Rect { + TZR_Point from; + TZR_Point to; +}; + +struct TZR_Raw { + void *data; + size_t size; +}; + +struct TZR_Image { + int width; + int height; + SDL_Texture *ptr; +}; + +struct TZR_Resource { + TZR_ResourceType type; + char *path; /* allocated and freed by TZR; can be NULL */ + long mtime; + union { + TZR_Raw raw; /* raw file data */ + TZR_Image image; + }; +}; + +struct TZR_Event { + TZR_EventType type; + int button; +}; + +struct TZR_DrawImageArgs { + int _; + TZR_Uint id; + int x; + int y; + int ix; + int iy; + int w; + int h; + float r; + float sx; + float sy; + bool center; +}; +/* headers/TZR_globals.h */ + +extern TZR_Config ___tzr_config; +extern TZR_Color ___tzr_color; +extern TZR_Resource *___tzr_resources; +extern size_t ___tzr_resources_capacity; +extern size_t ___tzr_resources_size; +extern SDL_Window *___tzr_window; +extern SDL_Renderer *___tzr_renderer; +extern SDL_Texture *___tzr_target; +extern unsigned long ___tzr_tick; +extern unsigned long ___tzr_next_time; +extern unsigned long ___tzr_min_dt; +extern int ___tzr_should_quit; +extern int ___tzr_mouse_x; +extern int ___tzr_mouse_y; +extern const char *___tzr_command[___TZR_RES_COUNT]; +extern TZR_KeyState ___tzr_keystates[SDL_NUM_SCANCODES]; +/* headers/TZR_resource.h */ + +/* Return 0 on error. */ +TZR_Uint TZR_LoadResourceFromMemory(TZR_ResourceType type, const void *data, int size); +TZR_Uint TZR_LoadResourceTyped(TZR_ResourceType type, const char *path); + +/* Return 0 on error; try to autodetect resource type from file extension. */ +TZR_Uint TZR_LoadResource(const char *path); + +/* Doesn't handle invalid ID. Pointer might get invalidated by resource + * creation calls, use with caution. */ +TZR_Resource *TZR_GetResourcePointer(TZR_Uint id); + +/* Doesn't handle invalid ID. Pointer might get invalidated by resource + * creation calls, use with caution. */ +TZR_Raw *TZR_GetRawResource(TZR_Uint id); + +/* Doesn't handle invalid ID. */ +TZR_ResourceType TZR_GetResourceType(TZR_Uint id); + +/* Doesn't handle invalid ID. */ +const char *TZR_GetResourcePath(TZR_Uint id); + +/* Doesn't handle invalid ID. */ +int TZR_GetImageWidth(TZR_Uint id); + +/* Doesn't handle invalid ID. */ +int TZR_GetImageHeight(TZR_Uint id); + +/* Reload ressource. Returns -1 on error and doesn't apply changes. */ +int TZR_ReloadResource(TZR_Uint id); + +/* Watch for changes on managed resources and hotreload if appropriate. */ +void TZR_ResourcesWatch(void); + +/* Used internaly. */ +int TZR_DirectResourceLoad(TZR_Resource *res, const void *data, int size); +void TZR_DestroyResource(TZR_Resource *res, int free_path); +/* headers/TZR_events.h */ + +/* Write event data to `e`. Return 0 when event queue is empty. */ +int TZR_PollEvent(TZR_Event *e); + +/* Drain queued events with TZR_PollEvent and call TZR_ResourcesWatch. */ +void TZR_CycleEvents(void); +/* headers/TZR_render.h */ + +/* All draw calls should happen between TZR_DrawBegin and TZR_DrawEnd. + * Return -1 on error. */ +int TZR_DrawBegin(void); + +/* Return -1 on error. */ +int TZR_DrawEnd(void); + +/* Return -1 on error. */ +#define TZR_DrawSetColor(...) _TZR_DrawSetColor(&(const TZR_Color){ \ + .r=-1.0f, .g=-1.0f, .b=-1.0f, .a=-1.0f, ._=0, __VA_ARGS__ }) +int _TZR_DrawSetColor(const TZR_Color *color); + +/* Return -1 on error. */ +int TZR_DrawClear(void); + +/* Return -1 on error. Draw point on `x`;`y` in the framebuffer. */ +int TZR_DrawPoint(int x, int y); + +/* Return -1 on error. Draw line between `x0`;`y0` and `x1`;`y1` in the + * framebuffer. */ +int TZR_DrawLine(int x0, int y0, int x1, int y1); + +/* Return -1 on error. Draw rectangle at `x`;`y` position of size `w`x`h` in the + * framebuffer. */ +int TZR_DrawRectangle(bool fill, int x, int y, int w, int h); + +/* Return -1 on error. Draw texture ressource `id` at `x`;`y` position of + * the framebuffer. */ +#define TZR_DrawImage(...) _TZR_DrawImage(&(const TZR_DrawImageArgs){ \ + .x=0, .y=0, .ix=0, .iy=0, .w=INT_MIN, .h=INT_MIN, .r=0.0f, .sx=1.0f, \ + .sy=1.0f, .center=false, ._=0, __VA_ARGS__ }) +int _TZR_DrawImage(const TZR_DrawImageArgs *args); +/* headers/TZR_keystate.h */ + +TZR_KeyState TZR_GetKeyState(int scancode); +bool TZR_IsKeyDown(int scancode); +bool TZR_IsKeyUp(int scancode); +bool TZR_IsKeyReleased(int scancode); +bool TZR_IsKeyPressed(int scancode); +/* headers/TZR.h */ + +/* TZR manages all loaded resources internally and tries to avoid duplicate. + * A resource can be loaded multiple times if asked, identification doesn't rely + * on filepath. In doubt, use TZR_LoadResource ONCE per asset and store the ID. + * Resources are exposed as ID instead of pointer, as a future proof measure in + * case TZR needs to rearrange memory at runtime in the future. */ + +#define TZR_Init(...) _TZR_Init(&(const TZR_Config){ \ + .width=256, \ + .height=224, \ + .target_fps=60, \ + .pixel_perfect=true, \ + .title="TZR", \ + ._=0, __VA_ARGS__ }) + +/* Should be called only once before usage of any other function unless + * otherwise specified. On error this calls TZR_Quit and returns -1. + * `config` will be duplicated internally and can be safely discarded. */ +int _TZR_Init(const TZR_Config *config); + +/* Destroy and free everything created by TZR. */ +void TZR_Quit(void); + +/* Return non-zero value when a quit event has been received. */ +int TZR_ShouldQuit(void); + +unsigned long TZR_GetTick(void); + +/* commit hash: 41400167398f1ab5f5e8ee67a76358189085f17f */ diff --git a/compile_flags.txt b/compile_flags.txt new file mode 100644 index 0000000..7077ba2 --- /dev/null +++ b/compile_flags.txt @@ -0,0 +1,5 @@ +-Wall +-Wextra +-Wno-initializer-overrides +-std=c99 +-Iheaders diff --git a/main.c b/main.c new file mode 100644 index 0000000..cea5f76 --- /dev/null +++ b/main.c @@ -0,0 +1,25 @@ +#include "TZR.h" + +int main(int argc, char **argv) +{ + (void)argc, (void)argv; + + if (TZR_Init(.target_fps=30, .pixel_perfect=false, .title="7DRL 2023")) + return 1; + if (atexit(TZR_Quit)) { + printf("atexit failed\n"); + TZR_Quit(); + return 1; + } + + while (!TZR_ShouldQuit()) { + TZR_CycleEvents(); + + TZR_DrawBegin(); + TZR_DrawSetColor(0, 0, 0, 1); + TZR_DrawClear(); + TZR_DrawEnd(); + } + + return 0; +} -- cgit v1.2.3