lzy/inc/lzy.h

1039 lines
21 KiB
C

/*
** 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 <stdint.h>
#ifdef FXCG50
#include <gint/keycodes.h>
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 <SDL2/SDL_mixer.h>
#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_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);
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, ...);
int LZY_LogError(int rv);
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);
#ifdef __cplusplus
}
#endif
#endif /* LZY_H_ */
/* implementation */
#ifdef LZY_IMPLEMENTATION
#undef LZY_IMPLEMENTATION
#ifndef LZY_SDL_INCLUDE
#define LZY_SDL_INCLUDE <SDL2/SDL.h>
#endif
#ifndef LZY_SDL_IMAGE_INCLUDE
#define LZY_SDL_IMAGE_INCLUDE <SDL2/SDL_image.h>
#endif
#ifndef LZY_SDL_MIXER_INCLUDE
#define LZY_SDL_MIXER_INCLUDE <SDL2/SDL_mixer.h>
#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 <stdio.h>
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);
}
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);
}
#ifdef FXCG50
#include <gint/cpu.h>
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/timer.h>
#include <stdint.h>
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) {
(void)title, (void)target_fps, (void)tset_path;
extern bopti_image_t LZY_GINT_TILESET;
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;
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_FillRect(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) {
(void)path;
return NULL;
}
int LZY_MusicDestroy(LZY_Music *music) {
(void)music;
return -1;
}
int LZY_MusicPlay(LZY_Music *music, int loops) {
(void)music, (void)loops;
return -1;
}
LZY_Sound *LZY_SoundLoad(const char *path) {
(void)path;
return NULL;
}
int LZY_SoundDestroy(LZY_Sound *sound) {
(void)sound;
return -1;
}
void LZY_SoundSetVolume(LZY_Sound *sound, float volume) {
(void)sound, (void)volume;
}
int LZY_SoundPlay(LZY_Sound *sound, int loops) {
(void)sound, (void)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, ...) {
(void)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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static const SDL_Scancode sc[LZYK_COUNT * 2] = {
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,
};
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);
if (scale > 1.0)
scale = (int)scale;
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_FillRect(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 * 2] ==
sdl_e.key.keysym.scancode ||
sc[i * 2 + 1] ==
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 * 2] == sdl_e.key.keysym.scancode ||
sc[i * 2 + 1] ==
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 */