diff options
Diffstat (limited to 'inc/lzy.h')
-rw-r--r-- | inc/lzy.h | 1119 |
1 files changed, 1119 insertions, 0 deletions
diff --git a/inc/lzy.h b/inc/lzy.h new file mode 100644 index 0000000..e8805bb --- /dev/null +++ b/inc/lzy.h @@ -0,0 +1,1119 @@ +/* +** Copyright (c) 2022 KikooDX +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to +** deal in the Software without restriction, including without limitation the +** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +** sell copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +** IN THE SOFTWARE. +*/ + +#ifndef LZY_H_ +#define LZY_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +#define LZY_UNUSED(x) (void)(x) + +#ifdef FXCG50 +#include <gint/keycodes.h> +typedef void LZY_Music; +typedef void LZY_Sound; +enum LZY_ScanCode { + LZYK_LEFT = KEY_LEFT, + LZYK_RIGHT = KEY_RIGHT, + LZYK_UP = KEY_UP, + LZYK_DOWN = KEY_DOWN, + LZYK_O = KEY_SHIFT, + LZYK_X = KEY_OPTN, +}; +#else /* end FXCG50, begin SDL2 */ +#ifndef LZY_SDL_MIXER_INCLUDE +#define LZY_SDL_MIXER_INCLUDE <SDL_mixer.h> +#endif +#include LZY_SDL_MIXER_INCLUDE +enum LZY_ScanCode { + LZYK_LEFT, + LZYK_RIGHT, + LZYK_UP, + LZYK_DOWN, + LZYK_O, + LZYK_X, + LZYK_COUNT, +}; +typedef Mix_Music LZY_Music; +typedef Mix_Chunk LZY_Sound; +#endif /* SDL2 */ + +enum LZY_EventType { + LZY_QUIT, + LZY_KEYDOWN, + LZY_KEYUP, +}; + +typedef struct LZY_KeyEvent { + unsigned int scancode; + int down; +} LZY_KeyEvent; + +typedef union LZY_EventUnion { + LZY_KeyEvent key; +} LZY_EventUnion; + +typedef struct LZY_Event { + int type; + LZY_EventUnion u; +} LZY_Event; + +int LZY_Init(int argc, const char **argv, const char *title, int target_fps, + const char *tset_path, const char *font_path); +void LZY_Quit(void); +int LZY_DrawBegin(void); +int LZY_DrawEnd(void); +void LZY_DrawSetColor(uint8_t r, uint8_t g, uint8_t b); +void LZY_DrawSetColorNone(void); +int LZY_DrawClear(void); +int LZY_DrawPoint(int x, int y); +int LZY_DrawLine(int x0, int y0, int x1, int y1); +int LZY_DrawRect(int x, int y, unsigned int w, unsigned int h); +int LZY_DrawFillRect(int x, int y, unsigned int w, unsigned int h); +int LZY_DrawTile(unsigned int id, int x, int y); +int LZY_DrawTileEx(unsigned int id, int x, int y, unsigned int w, + unsigned int h); +int LZY_DrawChar(unsigned char chr, int x, int y); +int LZY_DrawText(const char *text, int x, int y); +LZY_Music *LZY_MusicLoad(const char *path); +int LZY_MusicDestroy(LZY_Music *music); +int LZY_MusicPlay(LZY_Music *music, int loops); +LZY_Sound *LZY_SoundLoad(const char *path); +int LZY_SoundDestroy(LZY_Sound *sound); +void LZY_SoundSetVolume(LZY_Sound *sound, float volume); +int LZY_SoundPlay(LZY_Sound *sound, int loops); +int LZY_PollEvent(LZY_Event *); +void LZY_CycleEvents(void); +int LZY_KeyDown(unsigned int key); +int LZY_ShouldQuit(void); +void LZY_Log(const char *msg); +const char *LZY_GetError(void); + +#ifdef __cplusplus +} +#endif +#endif /* LZY_H_ */ + +/* implementation */ +#ifdef LZY_IMPLEMENTATION +#undef LZY_IMPLEMENTATION +#ifndef LZY_SDL_INCLUDE +#define LZY_SDL_INCLUDE <SDL.h> +#endif +#ifndef LZY_SDL_IMAGE_INCLUDE +#define LZY_SDL_IMAGE_INCLUDE <SDL_image.h> +#endif +#ifndef LZY_SDL_MIXER_INCLUDE +#define LZY_SDL_MIXER_INCLUDE <SDL_mixer.h> +#endif +#ifndef LZY_DISPLAY_WIDTH +#define LZY_DISPLAY_WIDTH 396 +#endif +#ifndef LZY_DISPLAY_HEIGHT +#define LZY_DISPLAY_HEIGHT 224 +#endif +#ifndef LZY_TILE_SIZE +#define LZY_TILE_SIZE 16 +#endif +#ifndef LZY_CHR_WIDTH +#define LZY_CHR_WIDTH LZY_TILE_SIZE +#endif +#ifndef LZY_CHR_HEIGHT +#define LZY_CHR_HEIGHT LZY_TILE_SIZE +#endif +#ifndef LZY_FIRST_CHR +#define LZY_FIRST_CHR ' ' +#endif + +int LZY_DrawLine(int x0, int y0, int x1, int y1) +{ + int dx, dy, sx, sy, err, e2; + int rc = 0; + + dx = x1 - x0; + dx = (dx < 0) ? (-dx) : (dx); + dy = y1 - y0; + dy = (dy < 0) ? (dy) : (-dy); + sx = (x0 < x1) ? (1) : (-1); + sy = (y0 < y1) ? (1) : (-1); + err = dx + dy; + + for (;;) { + if (LZY_DrawPoint(x0, y0)) + rc = -1; + + if (x0 == x1 && y0 == y1) + break; + + e2 = 2 * err; + if (e2 >= dy) { + err += dy; + x0 += sx; + } + if (e2 <= dx) { + err += dx; + y0 += sy; + } + } + + return rc; +} + +#ifdef FXCG50 +#include <gint/cpu.h> +#include <gint/display.h> +#include <gint/keyboard.h> +#include <gint/timer.h> +#include <stdint.h> + +static const int draw_off_x = (DWIDTH - LZY_DISPLAY_WIDTH) / 2; +static const int draw_off_y = (DHEIGHT - LZY_DISPLAY_HEIGHT) / 2; +static color_t draw_color = C_BLACK; +static int should_quit = 0; +static int timer = 0; +static volatile int has_ticked = 0; +#ifdef LZY_GINT_TILESET +static unsigned int tset_width, tset_height; +#endif +#ifdef LZY_GINT_FONT +static unsigned int font_width, font_height; +#endif +static int timer_callback(volatile int *); + +int LZY_Init(int argc, const char **argv, const char *title, int target_fps, + const char *tset_path, const char *font_path) +{ +#ifdef LZY_GINT_TILESET + extern bopti_image_t LZY_GINT_TILESET; + tset_width = LZY_GINT_TILESET.width / LZY_TILE_SIZE; + tset_height = LZY_GINT_TILESET.height / LZY_TILE_SIZE; +#endif +#ifdef LZY_GINT_FONT + extern bopti_image_t LZY_GINT_FONT; + font_width = LZY_GINT_FONT.width / LZY_CHR_WIDTH; + font_height = LZY_GINT_FONT.height / LZY_CHR_HEIGHT; +#endif + LZY_UNUSED(argc); + LZY_UNUSED(argv); + LZY_UNUSED(title); + LZY_UNUSED(tset_path); + LZY_UNUSED(font_path); + + if (target_fps > 0) { + timer = timer_configure(TIMER_ANY, 1000000 / target_fps, + GINT_CALL(timer_callback, &has_ticked)); + timer_start(timer); + } + return 0; +} + +static int timer_callback(volatile int *arg) +{ + *arg += 1; + return 0; +} + +void LZY_Quit(void) +{ + if (timer) { + timer_stop(timer); + timer = 0; + } +} + +int LZY_DrawBegin(void) +{ + return 0; +} + +int LZY_DrawEnd(void) +{ + dupdate(); + while (timer && !has_ticked) + sleep(); + has_ticked = 0; + return 0; +} + +void LZY_DrawSetColor(uint8_t r, uint8_t g, uint8_t b) +{ + draw_color = C_RGB(r / 8, g / 8, b / 8); +} + +void LZY_DrawSetColorNone(void) +{ + draw_color = C_NONE; +} + +int LZY_DrawClear(void) +{ + dclear(draw_color); + return 0; +} + +int LZY_DrawPoint(int x, int y) +{ + dpixel(x + draw_off_x, y + draw_off_y, draw_color); + return 0; +} + +int LZY_DrawRect(int x, int y, unsigned int w, unsigned int h) +{ + if (w < 1 || h < 1) + return -1; + x += draw_off_x; + y += draw_off_y; + + drect_border(x, y, x + w - 1, y + h - 1, C_NONE, 1, draw_color); + return 0; +} + +int LZY_DrawFillRect(int x, int y, unsigned int w, unsigned int h) +{ + if (w < 1 || h < 1) + return -1; + x += draw_off_x; + y += draw_off_y; + + drect(x, y, x + w - 1, y + h - 1, draw_color); + return 0; +} + +int LZY_DrawTile(unsigned int id, int x, int y) +{ +#ifndef LZY_GINT_TILESET + LZY_UNUSED(id); + LZY_UNUSED(x); + LZY_UNUSED(y); + return -1; +#else + extern bopti_image_t LZY_GINT_TILESET; + int ix, iy; + + if (id >= tset_width * tset_height) + return -1; + x += draw_off_x; + y += draw_off_y; + + ix = (id % tset_width) * LZY_TILE_SIZE; + iy = (id / tset_width) * LZY_TILE_SIZE; + dsubimage(x, y, &LZY_GINT_TILESET, ix, iy, LZY_TILE_SIZE, LZY_TILE_SIZE, + DIMAGE_NONE); + + return 0; +#endif +} + +int LZY_DrawTileEx(unsigned int id, int x, int y, unsigned int w, + unsigned int h) +{ +#ifndef LZY_GINT_TILESET + LZY_UNUSED(id); + LZY_UNUSED(x); + LZY_UNUSED(y); + LZY_UNUSED(w); + LZY_UNUSED(h); + return -1; +#else + extern bopti_image_t LZY_GINT_TILESET; + int ix, iy; + + if (w * h == 0) + return -1; + + x += draw_off_x; + y += draw_off_y; + + ix = id % tset_width; + iy = id / tset_width; + + if (ix >= (int)tset_width || ix + w - 1 >= tset_width || + iy >= (int)tset_height || iy + h - 1 >= tset_height) + return -1; + + ix *= LZY_TILE_SIZE; + iy *= LZY_TILE_SIZE; + dsubimage(x, y, &LZY_GINT_TILESET, ix, iy, w * LZY_TILE_SIZE, + h * LZY_TILE_SIZE, DIMAGE_NONE); + + return 0; +#endif +} + +int LZY_DrawChar(unsigned char chr, int x, int y) +{ +#ifndef LZY_GINT_FONT + LZY_UNUSED(chr); + LZY_UNUSED(x); + LZY_UNUSED(y); + return -1; +#else + extern bopti_image_t LZY_GINT_FONT; + const unsigned int id = (unsigned int)chr - LZY_FIRST_CHR; + int ix, iy; + + if (id >= font_width * font_height) + return -1; + x += draw_off_x; + y += draw_off_y; + + ix = (id % font_width) * LZY_CHR_WIDTH; + iy = (id / font_width) * LZY_CHR_HEIGHT; + dsubimage(x, y, &LZY_GINT_FONT, ix, iy, LZY_CHR_WIDTH, LZY_CHR_HEIGHT, + DIMAGE_NONE); + + return 0; +#endif +} + +int LZY_DrawText(const char *text, int x, int y) +{ +#ifndef LZY_GINT_FONT + LZY_UNUSED(text); + LZY_UNUSED(x); + LZY_UNUSED(y); + return -1; +#else + int err = 0; + + if (text == NULL) + return -1; + + for (; *text != '\0'; text++) { + const int rc = LZY_DrawChar(*text, x, y); + if (rc) + err = rc - 1; + x += LZY_CHR_WIDTH; + } + + return err; +#endif +} + +LZY_Music *LZY_MusicLoad(const char *path) +{ + LZY_UNUSED(path); + return NULL; +} + +int LZY_MusicDestroy(LZY_Music *music) +{ + LZY_UNUSED(music); + return -1; +} + +int LZY_MusicPlay(LZY_Music *music, int loops) +{ + LZY_UNUSED(music); + LZY_UNUSED(loops); + return -1; +} + +LZY_Sound *LZY_SoundLoad(const char *path) +{ + LZY_UNUSED(path); + return NULL; +} + +int LZY_SoundDestroy(LZY_Sound *sound) +{ + LZY_UNUSED(sound); + return -1; +} + +void LZY_SoundSetVolume(LZY_Sound *sound, float volume) +{ + LZY_UNUSED(sound); + LZY_UNUSED(volume); +} + +int LZY_SoundPlay(LZY_Sound *sound, int loops) +{ + LZY_UNUSED(sound); + LZY_UNUSED(loops); + return -1; +} + +int LZY_PollEvent(LZY_Event *e) +{ + for (;;) { + const key_event_t gk_e = pollevent(); + + switch (gk_e.type) { + case KEYEV_NONE: + return 0; + case KEYEV_DOWN: + e->type = LZY_KEYDOWN; + e->u.key.scancode = gk_e.key; + if (gk_e.key == KEY_EXIT) + should_quit = 1; + return 1; + case KEYEV_UP: + e->type = LZY_KEYUP; + e->u.key.scancode = gk_e.key; + return 1; + default: + break; + } + } +} + +void LZY_CycleEvents(void) +{ + clearevents(); + should_quit = should_quit || keydown(KEY_EXIT); +} + +int LZY_KeyDown(unsigned int key) +{ + return keydown(key); +} + +int LZY_ShouldQuit(void) +{ + return should_quit; +} + +void LZY_Log(const char *msg) +{ + LZY_UNUSED(msg); +} + +const char *LZY_GetError(void) +{ + return NULL; +} + +#else /* end FXCG50, begin SDL2 */ +#include LZY_SDL_INCLUDE +#include LZY_SDL_IMAGE_INCLUDE +#include LZY_SDL_MIXER_INCLUDE +#include <libgen.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +static const SDL_Scancode sc[LZYK_COUNT] = { + SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UP, + SDL_SCANCODE_DOWN, SDL_SCANCODE_Z, SDL_SCANCODE_X, +}; +static const SDL_Scancode fullscreen_sc = SDL_SCANCODE_F11; +static const char *error = NULL; +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; +static SDL_Texture *target = NULL; +static SDL_Texture *tset = NULL; +static SDL_Texture *font = NULL; +static int tset_width, tset_height, font_width, font_height; +static int should_quit = 0; +static int input[LZYK_COUNT] = {0}; +static int fps_limiter = 0; +static uint64_t min_dt; +static uint64_t next_time; +static char *datadir; + +static char *str_dup(const char *src) +{ + char *copy; + + if (src == NULL) { + error = "src is NULL"; + return NULL; + } + + copy = calloc(strlen(src) + 1, sizeof(char)); + if (copy == NULL) { + error = "calloc failed"; + return NULL; + } + + strcpy(copy, src); + return copy; +} + +static char *path_relative(const char *path) +{ + char *buf; + + if (datadir == NULL) { + error = "datadir is NULL"; + return NULL; + } + + if (path == NULL) { + error = "path is NULL"; + return NULL; + } + + buf = calloc(strlen(datadir) + strlen(path) + 2, sizeof(char)); + if (buf == NULL) { + error = "calloc failed"; + return NULL; + } + + strcpy(buf, datadir); + strcat(buf, "/"); + strcat(buf, path); + + return buf; +} + +int LZY_Init(int argc, const char **argv, const char *title, int target_fps, + const char *tset_path, const char *font_path) +{ + const int img_flags = IMG_INIT_PNG; + char *buf; + + datadir = str_dup((argc < 1) ? ("./rl") : (argv[0])); + if (datadir == NULL) + return -1; + dirname(datadir); + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { + error = SDL_GetError(); + return -1; + } + + if ((IMG_Init(img_flags) & img_flags) != img_flags) { + error = IMG_GetError(); + return -1; + } + + if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) { + error = Mix_GetError(); + return -1; + } + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, 0); + + window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, LZY_DISPLAY_WIDTH, + LZY_DISPLAY_HEIGHT, SDL_WINDOW_RESIZABLE); + if (window == NULL) { + error = SDL_GetError(); + return -1; + } + + SDL_SetWindowMinimumSize(window, LZY_DISPLAY_WIDTH, LZY_DISPLAY_HEIGHT); + + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + if (renderer == NULL) { + error = SDL_GetError(); + return -1; + } + + target = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB888, + SDL_TEXTUREACCESS_TARGET, LZY_DISPLAY_WIDTH, + LZY_DISPLAY_HEIGHT); + if (target == NULL) { + error = SDL_GetError(); + return -1; + } + + buf = path_relative(tset_path); + if (buf == NULL) + return -1; + tset = IMG_LoadTexture(renderer, buf); + if (tset == NULL) { + error = IMG_GetError(); + return -1; + } + free(buf); + + if (SDL_QueryTexture(tset, NULL, NULL, &tset_width, &tset_height) < 0) { + error = SDL_GetError(); + return -1; + } + tset_width /= LZY_TILE_SIZE; + tset_height /= LZY_TILE_SIZE; + + buf = path_relative(font_path); + if (buf == NULL) + return -1; + font = IMG_LoadTexture(renderer, buf); + if (font == NULL) { + error = IMG_GetError(); + return -1; + } + free(buf); + + if (SDL_QueryTexture(font, NULL, NULL, &font_width, &font_height) < 0) { + error = SDL_GetError(); + return -1; + } + font_width /= LZY_CHR_WIDTH; + font_height /= LZY_CHR_HEIGHT; + + fps_limiter = target_fps > 0; + if (fps_limiter) { + min_dt = 1000 / target_fps; + next_time = SDL_GetTicks64(); + } + + return 0; +} + +void LZY_Quit(void) +{ + if (datadir != NULL) { + free(datadir); + datadir = NULL; + } + + if (tset != NULL) { + SDL_DestroyTexture(tset); + tset = NULL; + } + + if (target != NULL) { + SDL_DestroyTexture(target); + target = NULL; + } + + if (renderer != NULL) { + SDL_DestroyRenderer(renderer); + renderer = NULL; + } + + if (window != NULL) { + SDL_DestroyWindow(window); + window = NULL; + } + + Mix_Quit(); + IMG_Quit(); + SDL_Quit(); +} + +int LZY_DrawBegin(void) +{ + if (fps_limiter) + next_time += min_dt; + + if (SDL_SetRenderTarget(renderer, target) < 0) { + error = SDL_GetError(); + return -1; + } + return 0; +} + +int LZY_DrawEnd(void) +{ + int win_w, win_h, off_x, off_y; + float ratio_w, ratio_h, scale; + SDL_Rect src, dst; + + if (SDL_SetRenderTarget(renderer, NULL)) { + error = SDL_GetError(); + return -1; + } + + LZY_DrawSetColor(0x00, 0x00, 0x00); + if (LZY_DrawClear()) + return -2; + + SDL_GetWindowSize(window, &win_w, &win_h); + ratio_w = (float)win_w / LZY_DISPLAY_WIDTH; + ratio_h = (float)win_h / LZY_DISPLAY_HEIGHT; + scale = (ratio_w < ratio_h) ? (ratio_w) : (ratio_h); + off_x = (win_w - LZY_DISPLAY_WIDTH * scale) / 2; + off_y = (win_h - LZY_DISPLAY_HEIGHT * scale) / 2; + + src.x = 0; + src.y = 0; + src.w = LZY_DISPLAY_WIDTH; + src.h = LZY_DISPLAY_HEIGHT; + + dst.x = off_x; + dst.y = off_y; + dst.w = LZY_DISPLAY_WIDTH * scale; + dst.h = LZY_DISPLAY_HEIGHT * scale; + + if (SDL_RenderCopy(renderer, target, &src, &dst) < 0) { + error = SDL_GetError(); + return -3; + } + + SDL_RenderPresent(renderer); + + if (fps_limiter) { + const uint64_t cur_time = SDL_GetTicks64(); + if (next_time <= cur_time) + next_time = cur_time; + else + SDL_Delay(next_time - cur_time); + } + return 0; +} + +void LZY_DrawSetColor(uint8_t r, uint8_t g, uint8_t b) +{ + SDL_SetRenderDrawColor(renderer, r, g, b, 0xff); +} + +void LZY_DrawSetColorNone(void) +{ + SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00); +} + +int LZY_DrawClear(void) +{ + if (SDL_RenderClear(renderer) < 0) { + error = SDL_GetError(); + return -1; + } + return 0; +} + +int LZY_DrawPoint(int x, int y) +{ + if (SDL_RenderDrawPoint(renderer, x, y) < 0) { + error = SDL_GetError(); + return -1; + } + return 0; +} + +int LZY_DrawRect(int x, int y, unsigned int w, unsigned int h) +{ + const SDL_Rect rect = {x, y, w, h}; + + if (w == 0 || h == 0) { + error = "rectangle dimensions cannot be 0"; + return -1; + } + + if (SDL_RenderDrawRect(renderer, &rect) < 0) { + error = SDL_GetError(); + return -2; + } + return 0; +} + +int LZY_DrawFillRect(int x, int y, unsigned int w, unsigned int h) +{ + const SDL_Rect rect = {x, y, w, h}; + + if (w == 0 || h == 0) { + error = "rectangle dimensions cannot be 0"; + return -1; + } + + if (SDL_RenderFillRect(renderer, &rect) < 0) { + error = SDL_GetError(); + return -2; + } + return 0; +} + +int LZY_DrawTile(unsigned int id, int x, int y) +{ + SDL_Rect src, dst; + + if (id >= (unsigned int)(tset_width * tset_height)) { + error = "id exceeds boundaries"; + return -1; + } + + src.x = (id % tset_width) * LZY_TILE_SIZE; + src.y = (id / tset_width) * LZY_TILE_SIZE; + src.w = LZY_TILE_SIZE; + src.h = LZY_TILE_SIZE; + + dst.x = x; + dst.y = y; + dst.w = LZY_TILE_SIZE; + dst.h = LZY_TILE_SIZE; + + if (SDL_RenderCopy(renderer, tset, &src, &dst) < 0) { + error = SDL_GetError(); + return -2; + } + + return 0; +} + +int LZY_DrawTileEx(unsigned int id, int x, int y, unsigned int w, + unsigned int h) +{ + SDL_Rect src, dst; + + if (w * h == 0) { + error = "tile size can't be 0"; + return -1; + } + + if (id >= (unsigned int)(tset_width * tset_height)) { + error = "id exceeds boundaries"; + return -1; + } + + src.x = id % tset_width; + src.y = id / tset_width; + + if (src.x >= tset_width || src.x + w - 1 >= (unsigned int)tset_width || + src.y >= tset_height || + src.y + h - 1 >= (unsigned int)tset_height) { + error = "tile is not in tileset"; + return -1; + } + + src.x *= LZY_TILE_SIZE; + src.y *= LZY_TILE_SIZE; + src.w = w * LZY_TILE_SIZE; + src.h = h * LZY_TILE_SIZE; + + dst.x = x; + dst.y = y; + dst.w = w * LZY_TILE_SIZE; + dst.h = h * LZY_TILE_SIZE; + + if (SDL_RenderCopy(renderer, tset, &src, &dst) < 0) { + error = SDL_GetError(); + return -1; + } + + return 0; +} + +int LZY_DrawChar(unsigned char chr, int x, int y) +{ + const unsigned int id = (unsigned int)chr - LZY_FIRST_CHR; + SDL_Rect src, dst; + + if (id >= (unsigned int)(font_width * font_height)) { + error = "chr exceeds boundaries"; + return -1; + } + + src.x = (id % font_width) * LZY_CHR_WIDTH; + src.y = (id / font_width) * LZY_CHR_HEIGHT; + src.w = LZY_CHR_WIDTH; + src.h = LZY_CHR_HEIGHT; + + dst.x = x; + dst.y = y; + dst.w = LZY_CHR_WIDTH; + dst.h = LZY_CHR_HEIGHT; + + if (SDL_RenderCopy(renderer, font, &src, &dst) < 0) { + error = SDL_GetError(); + return -2; + } + + return 0; +} + +int LZY_DrawText(const char *text, int x, int y) +{ + int err = 0; + + if (text == NULL) { + error = "text is NULL"; + return -1; + } + + for (; *text != '\0'; text++) { + const int rc = LZY_DrawChar(*text, x, y); + if (rc) + err = rc - 1; + x += LZY_CHR_WIDTH; + } + + return err; +} + +LZY_Music *LZY_MusicLoad(const char *path) +{ + char *buf; + LZY_Music *music; + + buf = path_relative(path); + if (buf == NULL) + return NULL; + music = Mix_LoadMUS(buf); + if (music == NULL) + error = Mix_GetError(); + free(buf); + + return music; +} + +int LZY_MusicDestroy(LZY_Music *music) +{ + if (music == NULL) { + error = "music is NULL"; + return -1; + } + + Mix_FreeMusic(music); + return 0; +} + +int LZY_MusicPlay(LZY_Music *music, int loops) +{ + if (music == NULL) { + error = "music is NULL"; + return -1; + } + + if (Mix_PlayMusic(music, loops) < 0) { + error = Mix_GetError(); + return -2; + } + return 0; +} + +LZY_Sound *LZY_SoundLoad(const char *path) +{ + char *buf; + LZY_Sound *sound; + + buf = path_relative(path); + if (buf == NULL) + return NULL; + sound = Mix_LoadWAV(buf); + if (sound == NULL) + error = Mix_GetError(); + free(buf); + + return sound; +} + +int LZY_SoundDestroy(LZY_Sound *sound) +{ + if (sound == NULL) { + error = "sound is NULL"; + return -1; + } + + Mix_FreeChunk(sound); + return 0; +} + +void LZY_SoundSetVolume(LZY_Sound *sound, float volume) +{ + if (sound != NULL) + Mix_VolumeChunk(sound, MIX_MAX_VOLUME * volume); +} + +int LZY_SoundPlay(LZY_Sound *sound, int loops) +{ + if (sound == NULL) { + error = "sound is NULL"; + return -1; + } + + if (Mix_PlayChannel(-1, sound, loops) < 0) { + error = Mix_GetError(); + return -2; + } + + return 0; +} + +int LZY_PollEvent(LZY_Event *e) +{ + SDL_Event sdl_e; + + while (SDL_PollEvent(&sdl_e) != 0) { + switch (sdl_e.type) { + case SDL_QUIT: + e->type = LZY_QUIT; + should_quit = 1; + return 1; + case SDL_KEYDOWN: { + if (!sdl_e.key.repeat) { + int i = LZYK_COUNT; + while (i-- > 0) { + if (sc[i] == + sdl_e.key.keysym.scancode) { + e->type = LZY_KEYDOWN; + e->u.key.scancode = i; + input[i] = 1; + return 1; + } + } + if (sdl_e.key.keysym.scancode == + fullscreen_sc) { + const unsigned int flag = + SDL_WINDOW_FULLSCREEN; + const unsigned int fullscreen = + SDL_GetWindowFlags(window) & flag; + SDL_SetWindowFullscreen(window, + !fullscreen); + } + } + } break; + case SDL_KEYUP: { + int i = LZYK_COUNT; + while (i-- > 0) { + if (sc[i] == sdl_e.key.keysym.scancode) { + e->type = LZY_KEYUP; + e->u.key.scancode = i; + input[i] = 0; + return 1; + } + } + } break; + default: + break; + } + } + + return 0; +} + +void LZY_CycleEvents(void) +{ + LZY_Event e; + + while (LZY_PollEvent(&e) != 0) + ; +} + +int LZY_KeyDown(unsigned int key) +{ + if (key >= LZYK_COUNT) + return 0; + return input[key]; +} + +int LZY_ShouldQuit(void) +{ + return should_quit; +} + +void LZY_Log(const char *msg) +{ + SDL_Log("%s", msg); +} + +const char *LZY_GetError(void) +{ + return error; +} +#endif /* SDL2 */ +#endif /* LZY_IMPLEMENTATION */ |