commit 9ea7bf73bbe283c9fe97ee68740b8c0c8cffd155 Author: KikooDX Date: Fri Apr 1 17:37:59 2022 +0200 art 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 0000000..c6d3af0 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..3e64f5d --- /dev/null +++ b/res/fxconv-metadata.txt @@ -0,0 +1,7 @@ +tset.png: + type: bopti-image + name: bimg_tset +font.png: + type: bopti-image + name: bimg_font + profile: p4 diff --git a/res/icon-sel.png b/res/icon-sel.png new file mode 100644 index 0000000..3fefb8a 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..6381b23 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..f963f41 Binary files /dev/null and b/res/tset.png differ diff --git a/src/lzy.c b/src/lzy.c new file mode 100644 index 0000000..c4e903b --- /dev/null +++ b/src/lzy.c @@ -0,0 +1,10 @@ +#include "conf.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_HEIGHT +#define LZY_DISPLAY_WIDTH DISPLAY_WIDTH +#define LZY_DISPLAY_HEIGHT DISPLAY_HEIGHT +#define LZY_FIRST_CHR ' ' +#include "lzy.h" diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..acd2aba --- /dev/null +++ b/src/main.c @@ -0,0 +1,50 @@ +#include "conf.h" +#include "lzy.h" + +int main(int argc, const char **argv) +{ + int x = 0; + int y = 0; + + if (LZY_Init(argc, argv, "wehfou official goty", 30, "res/tset.png", + "res/font.png")) { + LZY_Log(LZY_GetError()); + LZY_Quit(); + return 1; + } + + while (!LZY_ShouldQuit()) { + /* update */ + LZY_CycleEvents(); + + if (LZY_KeyDown(LZYK_LEFT)) + x -= 2; + if (LZY_KeyDown(LZYK_RIGHT)) + x += 2; + if (LZY_KeyDown(LZYK_UP)) + y -= 2; + if (LZY_KeyDown(LZYK_DOWN)) + y += 2; + + /* draw */ + LZY_DrawBegin(); + { + /* draw background */ + LZY_DrawTileEx(0, 0, 0, 13, 7); + LZY_DrawTileEx(0, DISPLAY_WIDTH / 2, 0, 13, 7); + LZY_DrawTileEx(0, 0, DISPLAY_HEIGHT / 2, 13, 7); + LZY_DrawTileEx(0, DISPLAY_WIDTH / 2, DISPLAY_HEIGHT / 2, + 13, 7); + + /* draw player */ + if (LZY_DrawChar('s', x, y)) + LZY_Log(LZY_GetError()); + } + LZY_DrawEnd(); + } + + LZY_Log("cya"); + LZY_Quit(); + + return 0; +} diff --git a/src/player.c b/src/player.c new file mode 100644 index 0000000..85bf2a7 --- /dev/null +++ b/src/player.c @@ -0,0 +1,18 @@ +#include "player.h" +#include "lzy.h" + +static float x, y, spd_x, spd_y; + +void player_init(float nx, float ny) +{ + x = nx; + y = ny; + spd_x = 0.0f; + spd_y = 0.0f; +} + +void player_draw(void) +{ + LZY_DrawSetColor(255, 0, 255); + LZY_DrawFillRect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT); +}