From 9ea7bf73bbe283c9fe97ee68740b8c0c8cffd155 Mon Sep 17 00:00:00 2001 From: KikooDX Date: Fri, 1 Apr 2022 17:37:59 +0200 Subject: [PATCH] art --- .clang-format | 9 + CMakeLists.txt | 27 + Makefile | 34 ++ inc/conf.h | 6 + inc/lzy.h | 1119 +++++++++++++++++++++++++++++++++++++++ inc/player.h | 7 + res/font.png | Bin 0 -> 1836 bytes res/fxconv-metadata.txt | 7 + res/icon-sel.png | Bin 0 -> 2783 bytes res/icon-uns.png | Bin 0 -> 1010 bytes res/tset.png | Bin 0 -> 2560 bytes src/lzy.c | 10 + src/main.c | 50 ++ src/player.c | 18 + 14 files changed, 1287 insertions(+) create mode 100644 .clang-format create mode 100644 CMakeLists.txt create mode 100644 Makefile create mode 100644 inc/conf.h create mode 100644 inc/lzy.h create mode 100644 inc/player.h 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/lzy.c create mode 100644 src/main.c create mode 100644 src/player.c diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..edb6674 --- /dev/null +++ b/.clang-format @@ -0,0 +1,9 @@ +BasedOnStyle: LLVM +IndentWidth: 8 +UseTab: AlignWithSpaces +BreakBeforeBraces: Linux +AllowShortIfStatementsOnASingleLine: Never +AllowShortFunctionsOnASingleLine: Empty +IndentCaseLabels: false +ColumnLimit: 80 +AlignConsecutiveMacros: true diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..fce70ab --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.22) +project(wehfou) + +include(GenerateG3A) +include(Fxconv) +find_package(Gint 2.7.0 REQUIRED) + +include_directories(inc) + +set(SOURCES + src/main.c + src/lzy.c +) + +set(ASSETS + res/tset.png + res/font.png +) + +fxconv_declare_assets(${ASSETS} WITH_METADATA) + +add_executable(thyaddin ${SOURCES} ${ASSETS}) +target_compile_options(thyaddin PRIVATE -Wall -Wextra -Os) +target_link_libraries(thyaddin Gint::Gint) + +generate_g3a(TARGET thyaddin OUTPUT "wehfou.g3a" + NAME "wehfou" ICONS res/icon-uns.png res/icon-sel.png) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e371044 --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +CC ?= gcc +CFLAGS = -std=c99 -Wall -Wextra -O3 -I./inc -MMD $(shell sdl2-config --cflags) +LDFLAGS = -lSDL2 -lSDL2_image -lSDL2_mixer $(shell sdl2-config --libs) + +OBJ_NAME = wehfou +OBJS := $(patsubst %.c,%.o,$(wildcard src/*.c)) + +all: $(OBJ_NAME) + +$(OBJ_NAME): $(OBJS) + $(CC) $(LDFLAGS) $(LIBRARIES) -o $(OBJ_NAME) $(OBJS) + strip $(OBJ_NAME) + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +cg: + fxsdk build-cg + +run: $(OBJ_NAME) + ./$(OBJ_NAME) + +format: + @clang-format -style=file -verbose -i src/*.c + @clang-format -style=file -verbose -i inc/*.h + +clean: + rm -f $(OBJ_NAME).g3a $(OBJ_NAME) + rm -f $(OBJS) src/*.d + rm -Rf build-cg + +.PHONY: cg run run-txt format clean + +-include src/*.d diff --git a/inc/conf.h b/inc/conf.h new file mode 100644 index 0000000..30fceb0 --- /dev/null +++ b/inc/conf.h @@ -0,0 +1,6 @@ +#pragma once + +#define CHR_WIDTH 8 +#define CHR_HEIGHT 16 +#define DISPLAY_WIDTH 400 +#define DISPLAY_HEIGHT 224 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 + +#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(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 +#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 + +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 +#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; +#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 +#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 *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 */ diff --git a/inc/player.h b/inc/player.h new file mode 100644 index 0000000..c1d6d7a --- /dev/null +++ b/inc/player.h @@ -0,0 +1,7 @@ +#pragma once + +void player_init(float x, float y); +void player_draw(void); + +#define PLAYER_WIDTH 12 +#define PLAYER_HEIGHT 12 diff --git a/res/font.png b/res/font.png new file mode 100644 index 0000000000000000000000000000000000000000..c6d3af0b9c60c05cb3603b6bd82d08e730cff055 GIT binary patch literal 1836 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 literal 0 HcmV?d00001 diff --git a/res/icon-uns.png b/res/icon-uns.png new file mode 100644 index 0000000000000000000000000000000000000000..6381b23a98e4b09d72760bd6a29e0b2805a8ffd7 GIT binary patch literal 1010 zcmVBp3uQ%&dk7B+s>s0QO z-xwT>pvJXiGNJ2^TMs za-sY*&BN33ai#L^%Yl!l?3YTlI<-8t&7YqUVV53a;m^;AuuBiI@aJbl*ku@Ep|<_Q zB=3)oe4v!SRS6B0y<8xiOAx(?T!QFDxIjct@zsmNQ+)N}@RTt0 zBDo|7^pvJ9>!FdRE-PIlVL=J#DWX_{c#0^NP(4LHl%}5IEfcq=c+14?DV+|bsi%0$ zKdP`aZ}kqo74`jj?#%DL-P+TkhCr*v(ff~E8+gc61(J9QT!w79y)7LGOF zp_b*?6k}m|Mf8*>4<8_e=9XTz4T^Jg@M2{xs%gPx;?T?6LIEK(mdUV%xVCItRTPBK z$oM!`)t$}FR-ZhYPIH;e&P-=>c|97P&*#`(>2xR|Pai*$1Eme~6h`Fs?d#249IJ|sFJDupMG7-N|X zyTy`-&ud20>D^+{ojVAj-C}V*pPO5H>F8*g#fWr9#wR)@eZ2M3DskL3s8uQ%Ci(bg zhjZbAlEp%D`n2j(+*L-bL5xV#4B`$VZpL+OG@Z`o@+?iHvj{7F92(i)c;!eLu?8`X z>}_qa+~G+i=1bE8w7sz*dW!s^41NVSI7=6g?X4i^qMS3=LeVmQUH-uhHgGeaL5YfDoz?vb?@tC=|cCPP4efvZ<C;$Zlpa2wr g0#E=7K>45X3jyZ|-3|n`uK)l507*qoM6N<$g4EpN_5c6? literal 0 HcmV?d00001 diff --git a/res/tset.png b/res/tset.png new file mode 100644 index 0000000000000000000000000000000000000000..f963f4145dfae13c8043a23b48aeb14e9c30b68a GIT binary patch literal 2560 zcmV+b3jg(qP)93=RywfMHTclRDVg!K52)I^YW!HZa(RWms_J&{r^f z1Sg9(*li=rQmZ6YNmZpPcrf!``@Qa#KK)hIC24bfcJVT;*!IERRAc}A^#DG$_P1QS zIz3wb{ONFiGQ+W*oBKEaKe@af=Gtd%7nB0W4Bws(_uoM@ifxSo&&$sr*3%o=87=|J?T%ghjl8P9}9rX;JvcNy~J_IOe{G$=1 zd8AJB^7F^E`S|s<(K%(}-1C8SNI!6gUQ2GUzZ{=)ulzx5x#uoOS|Ab+kOcLCcG{fI z?H?QaTesuKj(PdMH*L-zz<}qv&&zu*NLnD8wZ%WuplPXWA#g(fepL<+s#?`{Jpe5b z&DPaW`+?+$rg1vMmgdHaH5fFTgpqa9=)&bf0UgxTxp0_^ zd~k8=a-hJh0n_ZljW&&2Z44yY9v^RBMHTbaC zNcjBa7tnEcx6cNURA^Fgl$If_{apwy3>U6c*?hOS6eK7xkiRR1$^dErPVX}R(3%9T zp$Q$I3sNaCxlrZ6q;6R&H*MX*$BxDr4ClsROsB?Ftu>JRwxfin1|~9qTFgcb`QYw* zRO@7~DUPj6R|ZlHqL$#S!4v~YoC4KAf#LT{QXFXz`D%1^dNh6h`%f0<7XxY50*wy_ zMHPX;(_W3fefTu}#ss1TBp0GtGCXT)5&{an0T3SO`N^-0vubiIodi zGxfj>C&tsDHnlDvsRH>G1{!9qvg_D^Oqo4vqJt;&8&E}>Yv5VlGl*#6ao;zP;_>og z7&VX!s40-PYT$uyc6e~h-}adV+rUb$dVDBfHP4}}tGj(_~lADe2B+Go@(ZrD}$ zF_-S{_L(LNSE5K%mD5sOvsApJZD%(OgY5rGtwdYa4D@Q4)A8409E*ScgJyYgFq@Iu z$z>~b%|?UBO|{3M>A9hER|S%gy~EyMH}sw<3*Y#sJ3xQ@{_E?jN2isN&}a#gqnM8a1psc>ee1E#9H|2NkgUNqf(zFp?g}nxB_NyU-*+xa z16D}{X{%J0EPAMQb)J^S6`rU9Q3dyF=|`^ao5Y8@F0>L|I7sG=gZl3#1GjdK zE$_V~aJnc^DMYN!f~XXnIlDmS}Duh}{^JszbHxRP1|u>{1BY@O@I)n;I7I*kty^t+b7 zi*1ferAks%Cw5P;2EY)My<;I!0AWJZI+!kjD5f~dC+j(vteFD&S-9E}iL(-=M&mU#k_=Aj+OcC<4lZ321)^C0z*i!! z>FAImWvx;w_~EgC?%0Wim>RWIBs2vIsZR_X%#kS6C|o<;yX1wtyp%F{dMi;YMIuw6 z7VyNrZ&4&E4@uvxUdkXfO&t?q_kmvV5xN4k0w-rA;?x;aP;0ICYqd;O>r5RgKp}W~ zJds|LbPgRf29fq+St^K9u@$8ohf>NDlgVD?9Lw)=eHyN1l3wfUUfMHf!XGI$juJ)T01dhe#|<0_@QkWFAr~&Et+*`# zJ(na9Lh9p=CLG~07fG&hUN`+s7A_|Pm&&jA0?CKRz~QYz?zT1(HW)wy2ntebprq8u z89Xw9L63n>F0bE|@x&gax*fa4Lo|cOOjHtKF?Um~6iie#aR!f>Sb#z>K~#xL0>aFU z4M09fONlXC z>N6}r7(kivS07FAum-5s-7_;YfJ~h%_A!9WARTLjsodJ!w`mf%u%eC129E(`@TdoB z1b9>e#JwYqraanB1wj4?$F%`d=cQsdaPJy4tB<*G9XnR6ibC{`d7j&*9UfHxaaN(+ zbCCv-q*Y)IAYl-Nlm}A7CuUjVzXa#!$W@)tB7@lHjD4-6!h-@(YF|_i?%Wzk zB^?vuTGh-|imlYyLybmF4h*kAy*dfjBtQ3iT$oxy1idd;r$^?(X*FMcVjZ(3Jh{K? zD-v}~2aV-yLgQcx