#ifndef LZY_H_ #define LZY_H_ #ifdef __cplusplus extern "C" { #endif #include #define LZY_UNUSED(x) (void)(x) int LZY_Init(const char *title, int target_fps); 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); 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 FXCG50 #include enum LZY_ScanCode { LZYK_LEFT = KEY_LEFT, LZYK_RIGHT = KEY_RIGHT, LZYK_UP = KEY_UP, LZYK_DOWN = KEY_DOWN, }; #else /* end FXCG50, begin SDL2 */ #include enum LZY_ScanCode { LZYK_LEFT, LZYK_RIGHT, LZYK_UP, LZYK_DOWN, LZYK_COUNT, }; #endif /* SDL2 */ #ifdef __cplusplus } #endif #endif /* LZY_H_ */ /* implementation */ #ifdef LZY_IMPLEMENTATION #ifndef LZY_TILE_SIZE #define LZY_TILE_SIZE 16 #endif #ifndef LZY_DISPLAY_WIDTH #define LZY_DISPLAY_WIDTH 400 #endif #ifndef LZY_DISPLAY_HEIGHT #define LZY_DISPLAY_HEIGHT 224 #endif #ifdef FXCG50 #include #include #include #include #include static color_t draw_color = C_BLACK; static int should_quit = 0; static int timer = 0; static volatile int has_ticked = 0; static int timer_callback(volatile int *); int LZY_Init(const char *title, int target_fps) { LZY_UNUSED(title); 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; } 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 #include static const char *error = NULL; static SDL_Window *window = NULL; static SDL_Renderer *renderer = NULL; 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; int LZY_Init(const char *title, int target_fps) { if (SDL_Init(SDL_INIT_VIDEO) < 0) { error = SDL_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_SHOWN); if (window == NULL) { error = SDL_GetError(); return 2; } SDL_SetWindowMinimumSize(window, LZY_DISPLAY_WIDTH, LZY_DISPLAY_HEIGHT); renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); if (renderer == NULL) { error = SDL_GetError(); return 3; } fps_limiter = target_fps > 0; if (fps_limiter) { min_dt = 1000 / target_fps; next_time = SDL_GetTicks64(); } return 0; } void LZY_Quit(void) { if (renderer != NULL) { SDL_DestroyRenderer(renderer); renderer = NULL; } if (window != NULL) { SDL_DestroyWindow(window); window = NULL; } SDL_Quit(); } int LZY_DrawBegin(void) { if (fps_limiter) next_time += min_dt; return 0; } int LZY_DrawEnd(void) { 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; } void LZY_CycleEvents(void) { static const SDL_Scancode sc[LZYK_COUNT] = { SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, }; SDL_Event e; while (SDL_PollEvent(&e) != 0) { switch (e.type) { case SDL_QUIT: should_quit = 1; break; case SDL_KEYDOWN: { int i = LZYK_COUNT; while (i-- > 0) { if (sc[i] == e.key.keysym.scancode) { input[i] = 1; break; } } } break; case SDL_KEYUP: { int i = LZYK_COUNT; while (i-- > 0) { if (sc[i] == e.key.keysym.scancode) { input[i] = 0; break; } } } break; default: break; } } } 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(msg); } const char *LZY_GetError(void) { return error; } #endif /* SDL2 */ #endif /* LZY_IMPLEMENTATION */