commit bda2e4aeb64de349758d00f0c0b4f8c1d2acf562 Author: kdx Date: Fri Mar 17 09:50:44 2023 +0100 initial commit 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 0000000..6c06089 Binary files /dev/null and b/res/font.png differ diff --git a/res/fxconv-metadata.txt b/res/fxconv-metadata.txt new file mode 100644 index 0000000..2ecf9ba --- /dev/null +++ b/res/fxconv-metadata.txt @@ -0,0 +1,6 @@ +font.png: + type: bopti-image + name: bimg_font +tset.png: + type: bopti-image + name: bimg_tset diff --git a/res/icon-sel.png b/res/icon-sel.png new file mode 100644 index 0000000..7137b50 Binary files /dev/null and b/res/icon-sel.png differ diff --git a/res/icon-uns.png b/res/icon-uns.png new file mode 100644 index 0000000..3c99f62 Binary files /dev/null and b/res/icon-uns.png differ diff --git a/res/tset.png b/res/tset.png new file mode 100644 index 0000000..5b920e1 Binary files /dev/null and b/res/tset.png differ diff --git a/src/cfg.h b/src/cfg.h new file mode 100644 index 0000000..fc23d86 --- /dev/null +++ b/src/cfg.h @@ -0,0 +1,6 @@ +#pragma once +#define CHR_WIDTH 8 +#define CHR_HEIGHT 16 +#define DISPLAY_WIDTH 400 +#define DISPLAY_HEIGHT 224 +#define TSIZE 16 diff --git a/src/lzy.c b/src/lzy.c new file mode 100644 index 0000000..9b9542c --- /dev/null +++ b/src/lzy.c @@ -0,0 +1,11 @@ +#include "cfg.h" +#define LZY_IMPLEMENTATION +#define LZY_GINT_TILESET bimg_tset +#define LZY_GINT_FONT bimg_font +#define LZY_CHR_WIDTH CHR_WIDTH +#define LZY_CHR_HEIGHT CHR_WIDTH +#define LZY_DISPLAY_WIDTH DISPLAY_WIDTH +#define LZY_DISPLAY_HEIGHT DISPLAY_HEIGHT +#define LZY_FIRST_CHR ' ' +#define LZY_TILE_SIZE TSIZE +#include "lzy.h" diff --git a/src/lzy.h b/src/lzy.h new file mode 100644 index 0000000..67c654a --- /dev/null +++ b/src/lzy.h @@ -0,0 +1,1022 @@ +/* +** 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 + +#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; +}