From bda2e4aeb64de349758d00f0c0b4f8c1d2acf562 Mon Sep 17 00:00:00 2001 From: kdx Date: Fri, 17 Mar 2023 09:50:44 +0100 Subject: [PATCH] initial commit --- .gitignore | 14 + CMakeLists.txt | 29 ++ build.sh | 2 + compile_flags.txt | 3 + res/font.png | Bin 0 -> 3702 bytes res/fxconv-metadata.txt | 6 + res/icon-sel.png | Bin 0 -> 8388 bytes res/icon-uns.png | Bin 0 -> 4629 bytes res/tset.png | Bin 0 -> 500 bytes src/cfg.h | 6 + src/lzy.c | 11 + src/lzy.h | 1022 +++++++++++++++++++++++++++++++++++++++ src/main.c | 6 + 13 files changed, 1099 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100755 build.sh create mode 100644 compile_flags.txt create mode 100644 res/font.png create mode 100644 res/fxconv-metadata.txt create mode 100644 res/icon-sel.png create mode 100644 res/icon-uns.png create mode 100644 res/tset.png create mode 100644 src/cfg.h create mode 100644 src/lzy.c create mode 100644 src/lzy.h create mode 100644 src/main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c9e5cd --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Build files +/build-fx +/build-cg +/*.g1a +/*.g3a +/hyperultra + +# Python bytecode +__pycache__/ + +# Common IDE files +*.sublime-project +*.sublime-workspace +.vscode diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..74aa891 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,29 @@ +# Configure with [fxsdk build-cg], which provide the toolchain file +# and module path of the fxSDK + +cmake_minimum_required(VERSION 3.15) +project(MyAddin) + +include(GenerateG1A) +include(GenerateG3A) +include(Fxconv) +find_package(Gint 2.9 REQUIRED) + +set(SOURCES + src/main.c + src/lzy.c +) + +set(ASSETS + res/font.png + res/tset.png +) + +fxconv_declare_assets(${ASSETS} WITH_METADATA) + +add_executable(myaddin ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}}) +target_compile_options(myaddin PRIVATE -Wall -Wextra -Os) +target_link_libraries(myaddin Gint::Gint) + +generate_g3a(TARGET myaddin OUTPUT "hyperultra.g3a" NAME "" + ICONS res/icon-uns.png res/icon-sel.png) diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..3501041 --- /dev/null +++ b/build.sh @@ -0,0 +1,2 @@ +#!/bin/sh +gcc -std=c99 -Wall -Wextra -o hyperultra src/*.c -lSDL2 -lSDL2_image -lSDL2_mixer diff --git a/compile_flags.txt b/compile_flags.txt new file mode 100644 index 0000000..c376403 --- /dev/null +++ b/compile_flags.txt @@ -0,0 +1,3 @@ +-Wall +-Wextra +-std=c99 diff --git a/res/font.png b/res/font.png new file mode 100644 index 0000000000000000000000000000000000000000..6c06089b4f84a70fc5fcff79aa789298dbd01f32 GIT binary patch literal 3702 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 ag#Q8hHNm}t`+-sb0000 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 LNkvXXu0mjfMjhGA literal 0 HcmV?d00001 diff --git a/res/tset.png b/res/tset.png new file mode 100644 index 0000000000000000000000000000000000000000..5b920e1993944425adcf275a349f26f2dd1e829a GIT binary patch literal 500 zcmVb;8}^V-7AHJpqXU zI?3BBGgFP>?bPRC0X zF*olIMmu|ipe6w2;PKo?yVU;k)qV8w6i7TX@yxlItu_lKw*fRz_ZcYSNH)Uh>nt!H zI7OIh?sC$J5Z|Eg0OjDR%{~?m9p}O`kae1;wwWygN5=lmHPL1rZLi`t4a9l%m_#nHGsaB(%t(Sf?S$fKw_E?3$j3 zAgBpI(O9R~z52S(AY-Ci2A&8QfCuvT#o0Y7A~vFx{>HO&rAYmJae06_2)fLHtlLE4 qS=ac>eo-d=6fOuQ0tEMg4(Jall?IOY?2X9)0000 + +#define LZY_UNUSED(x) (void)(x) + +#ifdef FXCG50 +#include +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 +#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(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, int w, int h); +int LZY_DrawFillRect(int x, int y, int w, 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(int x, int y, const char *text); +int LZY_DrawTextF(int x, int y, const char *fmt, ...); +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 *fmt, ...); +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 +#endif +#ifndef LZY_SDL_IMAGE_INCLUDE +#define LZY_SDL_IMAGE_INCLUDE +#endif +#ifndef LZY_SDL_MIXER_INCLUDE +#define LZY_SDL_MIXER_INCLUDE +#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 +#include + +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; +} + +int LZY_DrawTextF(int x, int y, const char *fmt, ...) { + char buf[256] = {0}; + + va_list args; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf) - 1, fmt, args); + va_end(args); + + return LZY_DrawText(x, y, buf); +} + +#ifdef FXCG50 +#include +#include +#include +#include +#include + +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; +static unsigned int tset_width, tset_height; +static unsigned int font_width, font_height; +static int timer_callback(volatile int *); + +static int _LZY_Sign(int n) { + return (n > 0) - (n < 0); +} + +int LZY_Init(const char *title, int target_fps, const char *tset_path, + const char *font_path) { + extern bopti_image_t LZY_GINT_TILESET; + extern bopti_image_t LZY_GINT_FONT; + + LZY_UNUSED(title); + LZY_UNUSED(tset_path); + LZY_UNUSED(font_path); + + tset_width = LZY_GINT_TILESET.width / LZY_TILE_SIZE; + tset_height = LZY_GINT_TILESET.height / LZY_TILE_SIZE; + + font_width = LZY_GINT_FONT.width / LZY_CHR_WIDTH; + font_height = LZY_GINT_FONT.height / LZY_CHR_HEIGHT; + + 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, int w, int h) { + w += w == 0; + h += h == 0; + x += draw_off_x; + y += draw_off_y; + + drect_border(x, y, x + w - _LZY_Sign(w), y + h - _LZY_Sign(h), C_NONE, + 1, draw_color); + return 0; +} + +int LZY_DrawFillRect(int x, int y, int w, int h) { + w += w == 0; + h += h == 0; + x += draw_off_x; + y += draw_off_y; + + drect(x, y, x + w - _LZY_Sign(w), y + h - _LZY_Sign(h), draw_color); + return 0; +} + +int LZY_DrawTile(unsigned int id, int x, int y) { + 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; +} + +int LZY_DrawTileEx(unsigned int id, int x, int y, unsigned int w, + unsigned int h) { + 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; +} + +int LZY_DrawChar(unsigned char chr, int x, int y) { + 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; +} + +int LZY_DrawText(int x, int y, const char *text) { + 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; +} + +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 *fmt, ...) { + LZY_UNUSED(fmt); +} + +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 +#include +#include +#include + +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 *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) + 1, sizeof(char)); + if (buf == NULL) { + error = "calloc failed"; + return NULL; + } + + strcpy(buf, datadir); + strcat(buf, path); + + return buf; +} + +int LZY_Init(const char *title, int target_fps, const char *tset_path, + const char *font_path) { + const int img_flags = IMG_INIT_PNG; + char *buf; + + datadir = SDL_GetBasePath(); + if (datadir == NULL) { + error = SDL_GetError(); + return -1; + } + + 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) { + SDL_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, int w, int h) { + const SDL_Rect rect = {x, y, w + (w == 0), h + (h == 0)}; + + if (SDL_RenderDrawRect(renderer, &rect) < 0) { + error = SDL_GetError(); + return -2; + } + return 0; +} + +int LZY_DrawFillRect(int x, int y, int w, int h) { + const SDL_Rect rect = {x, y, w + (w == 0), h + (h == 0)}; + + 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(int x, int y, const char *text) { + 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 *fmt, ...) { + char buf[2048] = {0}; + va_list args; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf) - 1, fmt, args); + va_end(args); + + SDL_Log("%s", buf); +} + +const char *LZY_GetError(void) { + return error; +} +#endif /* SDL2 */ +#endif /* LZY_IMPLEMENTATION */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..288afda --- /dev/null +++ b/src/main.c @@ -0,0 +1,6 @@ +#include "lzy.h" + +int main(void) +{ + return 1; +}