lzy/inc/lzy.h

1039 lines
21 KiB
C
Raw Normal View History

2022-03-01 00:36:35 +01:00
/*
** 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.
*/
2022-02-28 15:38:08 +01:00
#ifndef LZY_H_
#define LZY_H_
#ifdef __cplusplus
extern "C" {
#endif
2022-03-01 01:54:20 +01:00
2022-02-28 15:38:08 +01:00
#include <stdint.h>
2022-03-02 00:04:31 +01:00
#ifdef FXCG50
2022-03-06 02:58:07 +01:00
#include <gint/keycodes.h>
2022-03-02 00:04:31 +01:00
typedef void LZY_Music;
2022-03-02 00:16:38 +01:00
typedef void LZY_Sound;
2022-03-06 02:58:07 +01:00
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 */
2022-03-02 00:04:31 +01:00
#ifndef LZY_SDL_MIXER_INCLUDE
2023-03-21 16:56:06 +01:00
#define LZY_SDL_MIXER_INCLUDE <SDL2/SDL_mixer.h>
2022-03-02 00:04:31 +01:00
#endif
#include LZY_SDL_MIXER_INCLUDE
2022-03-06 02:58:07 +01:00
enum LZY_ScanCode {
LZYK_LEFT,
LZYK_RIGHT,
LZYK_UP,
LZYK_DOWN,
LZYK_O,
LZYK_X,
LZYK_COUNT,
};
2022-03-02 00:04:31 +01:00
typedef Mix_Music LZY_Music;
2022-03-02 00:16:38 +01:00
typedef Mix_Chunk LZY_Sound;
2022-03-06 02:58:07 +01:00
#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;
2022-03-02 00:04:31 +01:00
int LZY_Init(const char *title, int target_fps,
2023-03-25 21:33:02 +01:00
const char *tset_path, const char *font_path);
2022-02-28 16:26:59 +01:00
void LZY_Quit(void);
int LZY_DrawBegin(void);
int LZY_DrawEnd(void);
2022-02-28 15:38:08 +01:00
void LZY_DrawSetColor(uint8_t r, uint8_t g, uint8_t b);
2022-02-28 15:49:33 +01:00
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_FillRect(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);
2022-03-06 19:19:51 +01:00
void LZY_SoundSetVolume(LZY_Sound *sound, float volume);
int LZY_SoundPlay(LZY_Sound *sound, int loops);
2022-03-06 02:58:07 +01:00
int LZY_PollEvent(LZY_Event *);
2022-02-28 15:38:08 +01:00
void LZY_CycleEvents(void);
2022-02-28 16:43:45 +01:00
int LZY_KeyDown(unsigned int key);
2022-02-28 16:26:59 +01:00
int LZY_ShouldQuit(void);
2022-04-12 11:48:42 +02:00
void LZY_Log(const char *fmt, ...);
2023-03-25 21:33:02 +01:00
int LZY_LogError(int rv);
2022-02-28 15:38:08 +01:00
const char *LZY_GetError(void);
#ifdef __has_cpp_attribute
[[deprecated("renamed to LZY_FillRect")]]
#endif
int LZY_DrawFillRect(int x, int y, int w, int h);
2023-03-25 21:33:02 +01:00
2022-02-28 15:38:08 +01:00
#ifdef __cplusplus
}
#endif
#endif /* LZY_H_ */
/* implementation */
#ifdef LZY_IMPLEMENTATION
2022-02-28 23:13:20 +01:00
#undef LZY_IMPLEMENTATION
2022-03-01 15:13:35 +01:00
#ifndef LZY_SDL_INCLUDE
2023-03-21 16:56:06 +01:00
#define LZY_SDL_INCLUDE <SDL2/SDL.h>
2022-03-01 15:13:35 +01:00
#endif
#ifndef LZY_SDL_IMAGE_INCLUDE
2023-03-21 16:56:06 +01:00
#define LZY_SDL_IMAGE_INCLUDE <SDL2/SDL_image.h>
2022-02-28 15:38:08 +01:00
#endif
2022-03-02 00:04:31 +01:00
#ifndef LZY_SDL_MIXER_INCLUDE
2023-03-21 16:56:06 +01:00
#define LZY_SDL_MIXER_INCLUDE <SDL2/SDL_mixer.h>
2022-03-02 00:04:31 +01:00
#endif
2022-02-28 16:26:59 +01:00
#ifndef LZY_DISPLAY_WIDTH
2022-02-28 21:47:26 +01:00
#define LZY_DISPLAY_WIDTH 396
2022-02-28 16:26:59 +01:00
#endif
#ifndef LZY_DISPLAY_HEIGHT
#define LZY_DISPLAY_HEIGHT 224
#endif
2022-03-01 15:13:35 +01:00
#ifndef LZY_TILE_SIZE
#define LZY_TILE_SIZE 16
2022-03-01 01:54:20 +01:00
#endif
2022-03-01 15:13:35 +01:00
#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 ' '
2022-03-01 01:54:20 +01:00
#endif
2022-04-12 11:58:12 +02:00
#include <stdio.h>
2022-02-28 16:26:59 +01:00
2022-03-02 23:32:07 +01:00
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;
}
2022-04-12 11:58:12 +02:00
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);
}
2023-03-25 21:33:02 +01:00
int LZY_LogError(int rv) {
LZY_Log("%s", LZY_GetError());
return rv;
}
int LZY_DrawFillRect(int x, int y, int w, int h) {
return LZY_FillRect(x, y, w, h);
}
2022-02-28 15:38:08 +01:00
#ifdef FXCG50
2022-02-28 18:01:06 +01:00
#include <gint/cpu.h>
2022-02-28 15:38:08 +01:00
#include <gint/display.h>
2022-02-28 15:49:33 +01:00
#include <gint/keyboard.h>
2022-02-28 18:01:06 +01:00
#include <gint/timer.h>
2022-02-28 15:38:08 +01:00
#include <stdint.h>
2022-03-15 00:15:14 +01:00
static const int draw_off_x = (DWIDTH - LZY_DISPLAY_WIDTH) / 2;
static const int draw_off_y = (DHEIGHT - LZY_DISPLAY_HEIGHT) / 2;
2022-02-28 16:26:59 +01:00
static color_t draw_color = C_BLACK;
static int should_quit = 0;
2022-02-28 18:01:06 +01:00
static int timer = 0;
static volatile int has_ticked = 0;
2022-03-01 01:54:20 +01:00
static unsigned int tset_width, tset_height;
2022-03-01 15:13:35 +01:00
static unsigned int font_width, font_height;
2022-02-28 18:01:06 +01:00
static int timer_callback(volatile int *);
2022-08-13 19:41:55 +02:00
static int _LZY_Sign(int n) {
return (n > 0) - (n < 0);
}
2023-04-13 09:04:54 +02:00
int LZY_Init(const char *title, int target_fps, const char *tset_path,
const char *font_path) {
(void)title, (void)target_fps, (void)tset_path;
2022-03-01 01:54:20 +01:00
extern bopti_image_t LZY_GINT_TILESET;
2022-03-01 15:13:35 +01:00
extern bopti_image_t LZY_GINT_FONT;
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;
2022-02-28 18:01:06 +01:00
if (target_fps > 0) {
timer = timer_configure(TIMER_ANY, 1000000 / target_fps,
GINT_CALL(timer_callback, &has_ticked));
timer_start(timer);
}
2022-02-28 18:01:06 +01:00
return 0;
}
static int timer_callback(volatile int *arg) {
*arg += 1;
2022-02-28 15:38:08 +01:00
return 0;
}
2022-02-28 18:01:06 +01:00
void LZY_Quit(void) {
if (timer) {
timer_stop(timer);
timer = 0;
}
}
2022-02-28 15:38:08 +01:00
int LZY_DrawBegin(void) {
return 0;
}
int LZY_DrawEnd(void) {
2022-02-28 15:49:33 +01:00
dupdate();
2022-02-28 18:01:06 +01:00
while (timer && !has_ticked)
sleep();
has_ticked = 0;
2022-02-28 15:38:08 +01:00
return 0;
}
void LZY_DrawSetColor(uint8_t r, uint8_t g, uint8_t b) {
2022-02-28 18:01:06 +01:00
draw_color = C_RGB(r / 8, g / 8, b / 8);
2022-02-28 15:38:08 +01:00
}
2022-02-28 15:49:33 +01:00
void LZY_DrawSetColorNone(void) {
draw_color = C_NONE;
}
2022-02-28 15:38:08 +01:00
int LZY_DrawClear(void) {
2022-02-28 15:49:33 +01:00
dclear(draw_color);
2022-02-28 15:38:08 +01:00
return 0;
}
2022-03-02 23:04:20 +01:00
int LZY_DrawPoint(int x, int y) {
2022-03-15 00:15:14 +01:00
dpixel(x + draw_off_x, y + draw_off_y, draw_color);
2022-03-02 23:04:20 +01:00
return 0;
}
2022-08-13 19:41:55 +02:00
int LZY_DrawRect(int x, int y, int w, int h) {
w += w == 0;
h += h == 0;
2022-03-15 00:15:14 +01:00
x += draw_off_x;
y += draw_off_y;
2022-08-13 19:41:55 +02:00
drect_border(x, y, x + w - _LZY_Sign(w), y + h - _LZY_Sign(h), C_NONE,
1, draw_color);
2022-02-28 21:47:26 +01:00
return 0;
}
2023-03-25 21:33:02 +01:00
int LZY_FillRect(int x, int y, int w, int h) {
2022-08-13 19:41:55 +02:00
w += w == 0;
h += h == 0;
2022-03-15 00:15:14 +01:00
x += draw_off_x;
y += draw_off_y;
2022-08-13 19:41:55 +02:00
drect(x, y, x + w - _LZY_Sign(w), y + h - _LZY_Sign(h), draw_color);
2022-02-28 21:47:26 +01:00
return 0;
}
2022-03-01 01:54:20 +01:00
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;
2022-03-15 00:15:14 +01:00
x += draw_off_x;
y += draw_off_y;
2022-03-01 01:54:20 +01:00
2022-03-15 22:11:49 +01:00
ix = (id % tset_width) * LZY_TILE_SIZE;
iy = (id / tset_width) * LZY_TILE_SIZE;
2022-03-01 01:54:20 +01:00
dsubimage(x, y, &LZY_GINT_TILESET, ix, iy, LZY_TILE_SIZE, LZY_TILE_SIZE,
DIMAGE_NONE);
return 0;
}
2022-03-27 14:56:31 +02:00
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;
}
2022-03-01 15:13:35 +01:00
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;
2022-03-15 00:15:14 +01:00
x += draw_off_x;
y += draw_off_y;
2022-03-01 15:13:35 +01:00
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;
}
2022-04-12 11:58:12 +02:00
int LZY_DrawText(int x, int y, const char *text) {
2022-03-01 15:29:34 +01:00
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;
}
2023-04-13 09:04:54 +02:00
LZY_Music *LZY_MusicLoad(const char *path) {
(void)path;
2022-03-02 00:04:31 +01:00
return NULL;
}
2022-03-02 00:16:38 +01:00
2023-04-13 09:04:54 +02:00
int LZY_MusicDestroy(LZY_Music *music) {
(void)music;
2022-03-02 00:04:31 +01:00
return -1;
}
2022-03-02 00:16:38 +01:00
2023-04-13 09:04:54 +02:00
int LZY_MusicPlay(LZY_Music *music, int loops) {
(void)music, (void)loops;
2022-03-02 00:04:31 +01:00
return -1;
}
2023-04-13 09:04:54 +02:00
LZY_Sound *LZY_SoundLoad(const char *path) {
(void)path;
2022-03-02 00:16:38 +01:00
return NULL;
}
2023-04-13 09:04:54 +02:00
int LZY_SoundDestroy(LZY_Sound *sound) {
(void)sound;
2022-03-02 00:16:38 +01:00
return -1;
}
2023-04-13 09:04:54 +02:00
void LZY_SoundSetVolume(LZY_Sound *sound, float volume) {
(void)sound, (void)volume;
}
2022-03-06 19:19:51 +01:00
2023-04-13 09:04:54 +02:00
int LZY_SoundPlay(LZY_Sound *sound, int loops) {
(void)sound, (void)loops;
2022-03-02 00:16:38 +01:00
return -1;
}
2022-03-06 02:58:07 +01:00
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;
2022-03-06 14:47:16 +01:00
default:
2022-03-12 22:11:00 +01:00
break;
2022-03-06 02:58:07 +01:00
}
}
}
2022-02-28 15:49:33 +01:00
void LZY_CycleEvents(void) {
clearevents();
2022-02-28 16:43:45 +01:00
should_quit = should_quit || keydown(KEY_EXIT);
2022-02-28 15:49:33 +01:00
}
2022-02-28 15:38:08 +01:00
2022-02-28 16:43:45 +01:00
int LZY_KeyDown(unsigned int key) {
return keydown(key);
2022-02-28 15:38:08 +01:00
}
2022-02-28 16:26:59 +01:00
int LZY_ShouldQuit(void) {
return should_quit;
}
2023-04-13 09:04:54 +02:00
void LZY_Log(const char *fmt, ...) {
(void)fmt;
}
2022-02-28 16:26:59 +01:00
2022-02-28 15:38:08 +01:00
const char *LZY_GetError(void) {
return NULL;
}
#else /* end FXCG50, begin SDL2 */
2022-03-01 01:54:20 +01:00
#include LZY_SDL_INCLUDE
#include LZY_SDL_IMAGE_INCLUDE
2022-03-02 00:04:31 +01:00
#include LZY_SDL_MIXER_INCLUDE
2022-02-28 15:38:08 +01:00
#include <stdint.h>
2022-04-12 11:58:12 +02:00
#include <stdio.h>
2022-03-07 14:56:34 +01:00
#include <stdlib.h>
#include <string.h>
2022-02-28 15:38:08 +01:00
2023-03-21 16:56:06 +01:00
static const SDL_Scancode sc[LZYK_COUNT * 2] = {
2023-03-25 21:33:02 +01:00
SDL_SCANCODE_LEFT, SDL_SCANCODE_A, SDL_SCANCODE_RIGHT, SDL_SCANCODE_D,
SDL_SCANCODE_UP, SDL_SCANCODE_W, SDL_SCANCODE_DOWN, SDL_SCANCODE_S,
SDL_SCANCODE_Z, SDL_SCANCODE_J, SDL_SCANCODE_X, SDL_SCANCODE_K,
2022-03-06 02:58:07 +01:00
};
2022-03-11 12:35:04 +01:00
static const SDL_Scancode fullscreen_sc = SDL_SCANCODE_F11;
2022-02-28 16:26:59 +01:00
static const char *error = NULL;
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
2022-02-28 22:15:00 +01:00
static SDL_Texture *target = NULL;
2022-03-01 01:54:20 +01:00
static SDL_Texture *tset = NULL;
2022-03-01 15:13:35 +01:00
static SDL_Texture *font = NULL;
static int tset_width, tset_height, font_width, font_height;
2022-02-28 16:26:59 +01:00
static int should_quit = 0;
2022-02-28 16:43:45 +01:00
static int input[LZYK_COUNT] = {0};
2022-02-28 18:01:06 +01:00
static int fps_limiter = 0;
static uint64_t min_dt;
static uint64_t next_time;
2022-03-07 14:56:34 +01:00
static char *datadir;
2022-02-28 16:26:59 +01:00
2022-03-07 14:56:34 +01:00
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;
}
2022-04-12 17:02:17 +02:00
buf = calloc(strlen(datadir) + strlen(path) + 1, sizeof(char));
2022-03-07 14:56:34 +01:00
if (buf == NULL) {
error = "calloc failed";
return NULL;
}
strcpy(buf, datadir);
strcat(buf, path);
return buf;
}
2022-04-12 17:02:17 +02:00
int LZY_Init(const char *title, int target_fps, const char *tset_path,
const char *font_path) {
2022-03-02 00:04:31 +01:00
const int img_flags = IMG_INIT_PNG;
2022-03-07 14:56:34 +01:00
char *buf;
2022-04-12 17:02:17 +02:00
datadir = SDL_GetBasePath();
if (datadir == NULL) {
error = SDL_GetError();
2022-03-07 14:56:34 +01:00
return -1;
2022-04-12 17:02:17 +02:00
}
2022-03-02 00:04:31 +01:00
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
2022-02-28 16:26:59 +01:00
error = SDL_GetError();
2022-02-28 21:47:26 +01:00
return -1;
2022-02-28 16:26:59 +01:00
}
2022-03-02 00:04:31 +01:00
if ((IMG_Init(img_flags) & img_flags) != img_flags) {
error = IMG_GetError();
2022-03-07 14:56:34 +01:00
return -1;
2022-03-02 00:04:31 +01:00
}
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) {
error = Mix_GetError();
2022-03-07 14:56:34 +01:00
return -1;
2022-03-02 00:04:31 +01:00
}
2022-02-28 16:26:59 +01:00
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, 0);
window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, LZY_DISPLAY_WIDTH,
2022-02-28 22:15:00 +01:00
LZY_DISPLAY_HEIGHT, SDL_WINDOW_RESIZABLE);
2022-02-28 16:26:59 +01:00
if (window == NULL) {
error = SDL_GetError();
2022-03-07 14:56:34 +01:00
return -1;
2022-02-28 16:26:59 +01:00
}
SDL_SetWindowMinimumSize(window, LZY_DISPLAY_WIDTH, LZY_DISPLAY_HEIGHT);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (renderer == NULL) {
error = SDL_GetError();
2022-03-07 14:56:34 +01:00
return -1;
2022-02-28 16:26:59 +01:00
}
2022-02-28 22:15:00 +01:00
target = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB888,
SDL_TEXTUREACCESS_TARGET, LZY_DISPLAY_WIDTH,
LZY_DISPLAY_HEIGHT);
if (target == NULL) {
error = SDL_GetError();
2022-03-07 14:56:34 +01:00
return -1;
2022-02-28 22:15:00 +01:00
}
2022-03-07 14:56:34 +01:00
buf = path_relative(tset_path);
if (buf == NULL)
return -1;
tset = IMG_LoadTexture(renderer, buf);
2022-03-01 01:54:20 +01:00
if (tset == NULL) {
error = IMG_GetError();
2022-03-07 14:56:34 +01:00
return -1;
2022-03-01 01:54:20 +01:00
}
2022-03-07 14:56:34 +01:00
free(buf);
2022-03-01 01:54:20 +01:00
if (SDL_QueryTexture(tset, NULL, NULL, &tset_width, &tset_height) < 0) {
error = SDL_GetError();
2022-03-07 14:56:34 +01:00
return -1;
2022-03-01 01:54:20 +01:00
}
tset_width /= LZY_TILE_SIZE;
tset_height /= LZY_TILE_SIZE;
2022-03-07 14:56:34 +01:00
buf = path_relative(font_path);
if (buf == NULL)
return -1;
font = IMG_LoadTexture(renderer, buf);
2022-03-01 15:13:35 +01:00
if (font == NULL) {
error = IMG_GetError();
2022-03-07 14:56:34 +01:00
return -1;
2022-03-01 15:13:35 +01:00
}
2022-03-07 14:56:34 +01:00
free(buf);
2022-03-01 15:13:35 +01:00
if (SDL_QueryTexture(font, NULL, NULL, &font_width, &font_height) < 0) {
error = SDL_GetError();
2022-03-07 14:56:34 +01:00
return -1;
2022-03-01 15:13:35 +01:00
}
font_width /= LZY_CHR_WIDTH;
font_height /= LZY_CHR_HEIGHT;
2022-02-28 18:01:06 +01:00
fps_limiter = target_fps > 0;
if (fps_limiter) {
min_dt = 1000 / target_fps;
next_time = SDL_GetTicks64();
}
2022-02-28 15:38:08 +01:00
return 0;
}
2022-02-28 16:26:59 +01:00
void LZY_Quit(void) {
2022-03-07 14:56:34 +01:00
if (datadir != NULL) {
2022-04-12 17:02:17 +02:00
SDL_free(datadir);
2022-03-07 14:56:34 +01:00
datadir = NULL;
}
2022-03-01 01:54:20 +01:00
if (tset != NULL) {
SDL_DestroyTexture(tset);
tset = NULL;
}
2022-02-28 22:15:00 +01:00
if (target != NULL) {
SDL_DestroyTexture(target);
target = NULL;
}
2022-02-28 16:26:59 +01:00
if (renderer != NULL) {
SDL_DestroyRenderer(renderer);
renderer = NULL;
}
if (window != NULL) {
SDL_DestroyWindow(window);
window = NULL;
}
2022-03-02 00:04:31 +01:00
Mix_Quit();
IMG_Quit();
2022-02-28 16:26:59 +01:00
SDL_Quit();
2022-02-28 15:38:08 +01:00
}
int LZY_DrawBegin(void) {
2022-02-28 18:01:06 +01:00
if (fps_limiter)
next_time += min_dt;
2022-02-28 22:15:00 +01:00
if (SDL_SetRenderTarget(renderer, target) < 0) {
error = SDL_GetError();
return -1;
}
2022-02-28 15:38:08 +01:00
return 0;
}
int LZY_DrawEnd(void) {
2022-02-28 22:15:00 +01:00
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);
2023-03-21 16:56:06 +01:00
if (scale > 1.0)
scale = (int)scale;
2022-02-28 22:15:00 +01:00
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;
}
2022-02-28 16:26:59 +01:00
SDL_RenderPresent(renderer);
2022-02-28 18:01:06 +01:00
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);
}
2022-02-28 15:38:08 +01:00
return 0;
}
2022-02-28 16:26:59 +01:00
void LZY_DrawSetColor(uint8_t r, uint8_t g, uint8_t b) {
SDL_SetRenderDrawColor(renderer, r, g, b, 0xff);
}
2022-02-28 15:38:08 +01:00
2022-02-28 16:26:59 +01:00
void LZY_DrawSetColorNone(void) {
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
}
2022-02-28 15:49:33 +01:00
2022-02-28 15:38:08 +01:00
int LZY_DrawClear(void) {
2022-02-28 16:26:59 +01:00
if (SDL_RenderClear(renderer) < 0) {
error = SDL_GetError();
2022-02-28 21:47:26 +01:00
return -1;
}
return 0;
}
2022-03-02 23:04:20 +01:00
int LZY_DrawPoint(int x, int y) {
if (SDL_RenderDrawPoint(renderer, x, y) < 0) {
error = SDL_GetError();
return -1;
}
return 0;
}
2022-08-13 19:41:55 +02:00
int LZY_DrawRect(int x, int y, int w, int h) {
const SDL_Rect rect = {x, y, w + (w == 0), h + (h == 0)};
2022-02-28 22:15:00 +01:00
2022-02-28 21:47:26 +01:00
if (SDL_RenderDrawRect(renderer, &rect) < 0) {
error = SDL_GetError();
2022-02-28 22:15:00 +01:00
return -2;
2022-02-28 21:47:26 +01:00
}
return 0;
}
2023-03-25 21:33:02 +01:00
int LZY_FillRect(int x, int y, int w, int h) {
2022-08-13 19:41:55 +02:00
const SDL_Rect rect = {x, y, w + (w == 0), h + (h == 0)};
2022-02-28 22:15:00 +01:00
2022-02-28 21:47:26 +01:00
if (SDL_RenderFillRect(renderer, &rect) < 0) {
error = SDL_GetError();
2022-02-28 22:15:00 +01:00
return -2;
2022-02-28 16:26:59 +01:00
}
2022-02-28 15:38:08 +01:00
return 0;
}
2022-03-01 01:54:20 +01:00
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) {
2022-03-01 15:13:35 +01:00
error = SDL_GetError();
return -2;
}
return 0;
}
2022-03-27 14:56:31 +02:00
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;
}
2022-03-01 15:13:35 +01:00
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) {
2022-03-01 01:54:20 +01:00
error = SDL_GetError();
return -2;
}
return 0;
}
2022-04-12 11:58:12 +02:00
int LZY_DrawText(int x, int y, const char *text) {
2022-03-01 15:29:34 +01:00
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;
}
2022-03-02 00:04:31 +01:00
LZY_Music *LZY_MusicLoad(const char *path) {
2022-03-07 14:56:34 +01:00
char *buf;
LZY_Music *music;
buf = path_relative(path);
if (buf == NULL)
return NULL;
music = Mix_LoadMUS(buf);
2022-03-02 00:04:31 +01:00
if (music == NULL)
error = Mix_GetError();
2022-03-07 14:56:34 +01:00
free(buf);
2022-03-02 00:04:31 +01:00
return music;
}
2022-03-06 19:19:51 +01:00
int LZY_MusicDestroy(LZY_Music *music) {
2022-03-02 00:16:38 +01:00
if (music == NULL) {
error = "music is NULL";
return -1;
}
2022-03-06 19:19:51 +01:00
Mix_FreeMusic(music);
2022-03-02 00:04:31 +01:00
return 0;
}
2022-03-06 19:19:51 +01:00
int LZY_MusicPlay(LZY_Music *music, int loops) {
2022-03-02 00:04:31 +01:00
if (music == NULL) {
error = "music is NULL";
return -1;
}
2022-03-06 19:19:51 +01:00
if (Mix_PlayMusic(music, loops) < 0) {
error = Mix_GetError();
return -2;
}
2022-03-02 00:04:31 +01:00
return 0;
}
2022-03-02 00:16:38 +01:00
LZY_Sound *LZY_SoundLoad(const char *path) {
2022-03-07 14:56:34 +01:00
char *buf;
LZY_Sound *sound;
buf = path_relative(path);
if (buf == NULL)
return NULL;
sound = Mix_LoadWAV(buf);
2022-03-02 00:16:38 +01:00
if (sound == NULL)
error = Mix_GetError();
2022-03-07 14:56:34 +01:00
free(buf);
2022-03-02 00:16:38 +01:00
return sound;
}
2022-03-06 19:19:51 +01:00
int LZY_SoundDestroy(LZY_Sound *sound) {
2022-03-02 00:16:38 +01:00
if (sound == NULL) {
error = "sound is NULL";
return -1;
}
2022-03-06 19:19:51 +01:00
Mix_FreeChunk(sound);
2022-03-02 00:16:38 +01:00
return 0;
}
2022-03-06 19:19:51 +01:00
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) {
2022-03-02 00:16:38 +01:00
if (sound == NULL) {
error = "sound is NULL";
return -1;
}
2022-03-06 19:19:51 +01:00
if (Mix_PlayChannel(-1, sound, loops) < 0) {
error = Mix_GetError();
return -2;
}
2022-03-02 00:16:38 +01:00
return 0;
}
2022-03-06 02:58:07 +01:00
int LZY_PollEvent(LZY_Event *e) {
SDL_Event sdl_e;
2022-03-12 22:11:00 +01:00
while (SDL_PollEvent(&sdl_e) != 0) {
2022-03-06 02:58:07 +01:00
switch (sdl_e.type) {
2022-02-28 16:26:59 +01:00
case SDL_QUIT:
2022-03-06 02:58:07 +01:00
e->type = LZY_QUIT;
2022-02-28 16:26:59 +01:00
should_quit = 1;
2022-03-06 02:58:07 +01:00
return 1;
2022-02-28 16:43:45 +01:00
case SDL_KEYDOWN: {
2022-03-06 02:58:07 +01:00
if (!sdl_e.key.repeat) {
int i = LZYK_COUNT;
while (i-- > 0) {
2023-03-25 21:33:02 +01:00
if (sc[i * 2] ==
sdl_e.key.keysym.scancode ||
sc[i * 2 + 1] ==
sdl_e.key.keysym.scancode) {
2022-03-06 02:58:07 +01:00
e->type = LZY_KEYDOWN;
e->u.key.scancode = i;
input[i] = 1;
return 1;
}
2022-02-28 16:43:45 +01:00
}
2022-03-11 12:35:04 +01:00
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);
}
2022-02-28 16:43:45 +01:00
}
2022-03-12 22:11:00 +01:00
} break;
2022-02-28 16:43:45 +01:00
case SDL_KEYUP: {
int i = LZYK_COUNT;
while (i-- > 0) {
2023-03-25 21:33:02 +01:00
if (sc[i * 2] == sdl_e.key.keysym.scancode ||
sc[i * 2 + 1] ==
sdl_e.key.keysym.scancode) {
2022-03-06 02:58:07 +01:00
e->type = LZY_KEYUP;
e->u.key.scancode = i;
2022-02-28 16:43:45 +01:00
input[i] = 0;
2022-03-06 02:58:07 +01:00
return 1;
2022-02-28 16:43:45 +01:00
}
}
2022-03-12 22:11:00 +01:00
} break;
2022-03-06 14:47:16 +01:00
default:
2022-03-12 22:11:00 +01:00
break;
2022-02-28 16:26:59 +01:00
}
}
2022-03-06 02:58:07 +01:00
return 0;
}
void LZY_CycleEvents(void) {
LZY_Event e;
while (LZY_PollEvent(&e) != 0)
;
2022-02-28 16:26:59 +01:00
}
2022-02-28 15:38:08 +01:00
2022-02-28 16:43:45 +01:00
int LZY_KeyDown(unsigned int key) {
if (key >= LZYK_COUNT)
return 0;
return input[key];
2022-02-28 15:38:08 +01:00
}
2022-02-28 16:26:59 +01:00
int LZY_ShouldQuit(void) {
return should_quit;
}
2022-04-12 11:48:42 +02:00
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);
2022-02-28 16:26:59 +01:00
}
2022-02-28 15:38:08 +01:00
const char *LZY_GetError(void) {
2022-02-28 16:26:59 +01:00
return error;
2022-02-28 15:38:08 +01:00
}
#endif /* SDL2 */
#endif /* LZY_IMPLEMENTATION */