From 8d45b2b70143972f6b7862835b8ae9876f49e214 Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Sat, 12 Jan 2019 15:34:56 -0500 Subject: functioning sdl --- meson.build | 5 +- src/sdl/action.c | 63 ++++++++++++ src/sdl/action.h | 27 +++++ src/sdl/main.c | 301 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 394 insertions(+), 2 deletions(-) create mode 100644 src/sdl/action.c create mode 100644 src/sdl/action.h diff --git a/meson.build b/meson.build index 1d5f2e3..d8c3b35 100644 --- a/meson.build +++ b/meson.build @@ -18,9 +18,12 @@ executable('sok-text', sources + [ # sdl exe executable('sok-sdl', sources + [ + 'src/text/levels.c', + 'src/sdl/action.c', 'src/sdl/main.c', ], dependencies: [ - # 'sdl2', + dependency('SDL2'), + dependency('SDL2_image'), ]) # test executable diff --git a/src/sdl/action.c b/src/sdl/action.c new file mode 100644 index 0000000..a4dcb79 --- /dev/null +++ b/src/sdl/action.c @@ -0,0 +1,63 @@ +#include "../libsok/sok.h" +#include "action.h" + +#define CASE_DIGIT \ + case SDLK_0: \ + case SDLK_1: \ + case SDLK_2: \ + case SDLK_3: \ + case SDLK_4: \ + case SDLK_5: \ + case SDLK_6: \ + case SDLK_7: \ + case SDLK_8: \ + case SDLK_9: + +static const sok_dir_t +keycode_to_dir(const SDL_Keycode code) { + switch (code) { + case SDLK_UP: return SOK_DIR_UP; + case SDLK_LEFT: return SOK_DIR_LEFT; + case SDLK_DOWN: return SOK_DIR_DOWN; + case SDLK_RIGHT: return SOK_DIR_RIGHT; + default: return SOK_DIR_LAST; + } +} + +action_t +get_action( + const SDL_Keycode code +) { + switch (code) { + case SDLK_ESCAPE: + case SDLK_q: + return (action_t) { .type = ACTION_QUIT }; + case SDLK_UP: + case SDLK_DOWN: + case SDLK_LEFT: + case SDLK_RIGHT: + return (action_t) { + .type = ACTION_MOVE, + .data = keycode_to_dir(code) + }; + case SDLK_u: + return (action_t) { .type = ACTION_UNDO }; + case SDLK_n: + return (action_t) { .type = ACTION_NEXT }; + CASE_DIGIT + return (action_t) { + .type = ACTION_WARP_BUF_PUSH, + .data = (code - SDLK_0), + }; + case SDLK_DELETE: + return (action_t) { .type = ACTION_WARP_BUF_POP }; + case SDLK_RETURN: + return (action_t) { .type = ACTION_WARP }; + case 'r': + return (action_t) { .type = ACTION_RESET }; + case 's': + return (action_t) { .type = ACTION_SOLVE }; + default: + return (action_t) { .type = ACTION_NONE }; + } +} diff --git a/src/sdl/action.h b/src/sdl/action.h new file mode 100644 index 0000000..d6d9870 --- /dev/null +++ b/src/sdl/action.h @@ -0,0 +1,27 @@ +#ifndef ACTION_H +#define ACTION_H + +#include + +typedef enum { + ACTION_NONE, + ACTION_QUIT, + ACTION_MOVE, + ACTION_WARP, + ACTION_WARP_BUF_PUSH, + ACTION_WARP_BUF_POP, + ACTION_UNDO, + ACTION_NEXT, + ACTION_SOLVE, + ACTION_RESET, + ACTION_LAST, +} action_type_t; + +typedef struct { + action_type_t type; + uint64_t data; +} action_t; + +action_t get_action(const SDL_Keycode); + +#endif /* ACTION_H */ diff --git a/src/sdl/main.c b/src/sdl/main.c index 0fb4389..831d3f7 100644 --- a/src/sdl/main.c +++ b/src/sdl/main.c @@ -1,3 +1,302 @@ +#include // bool +#include // EXIT_{FAILURE,SUCCESS} +#include // strerror +#include // errno +#include +#include +#include "../text/levels.h" +#include "../libsok/sok.h" +#include "action.h" + +#define warn(...) do { \ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__); \ +} while (0) + +#define die(...) do { \ + SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__); \ + exit(EXIT_FAILURE); \ +} while (0) + +static void +solve_on_error( + const char * const err +) { + die("Error solving level: %s", err); +} + +static void +draw_moves( + const sok_ctx_t * const ctx, + const size_t skip_moves +) { + printf("Solution (%zu moves): ", ctx->num_moves - skip_moves); + for (size_t i = skip_moves; i < ctx->num_moves; i++) { + if (ctx->moves[i].dir >= SOK_DIR_LAST) { + die("invalid move: %u", ctx->moves[i].dir); + } + + fputs(SOK_DIR_TO_STR(ctx->moves[i].dir), stdout); + } + printf("\n"); +} + +static const SDL_Color +RED = { .r = 0x00, .g = 0xFF, .b = 0x00, .a = 0xFF }, +BLACK = { .r = 0x00, .g = 0x00, .b = 0x00, .a = 0xFF }; + +static SDL_Color +get_bg( + const sok_ctx_t * const ctx +) { + return (sok_ctx_is_done(ctx)) ? RED : BLACK; +} + +bool draw_on_wall( + const sok_ctx_t * const ctx, + const sok_pos_t pos, + void * const data +) { + SDL_Renderer *renderer = data; + SDL_Rect rect = { 32 * pos.x, 32 * pos.y, 32, 32 }; + + SDL_SetRenderDrawColor(renderer, 0x66, 0x66, 0x66, 0xFF); + + if (SDL_RenderFillRect(renderer, &rect)) { + die("SDL_RenderFillRect(): %s", SDL_GetError()); + } + + return true; +} + +bool draw_on_goal( + const sok_ctx_t * const ctx, + const sok_pos_t pos, + const bool has_player, + const bool has_box, + void * const data +) { + SDL_Renderer *renderer = data; + SDL_Rect rect = { 32 * pos.x, 32 * pos.y, 32, 32 }; + + SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0xFF); + + if (SDL_RenderFillRect(renderer, &rect)) { + die("SDL_RenderFillRect(): %s", SDL_GetError()); + } + + return true; +} + +bool draw_on_home( + const sok_ctx_t * const ctx, + const sok_pos_t pos, + const bool has_goal, + void * const data +) { + SDL_Renderer *renderer = data; + SDL_Rect rect = { 32 * pos.x, 32 * pos.y, 32, 32 }; + + SDL_SetRenderDrawColor(renderer, 0xFF, has_goal ? 0xFF : 0x00, 0x00, 0xFF); + + if (SDL_RenderFillRect(renderer, &rect)) { + die("SDL_RenderFillRect(): %s", SDL_GetError()); + } + + return true; +} + +bool draw_on_box( + const sok_ctx_t * const ctx, + const sok_pos_t pos, + const bool has_goal, + void * const data +) { + SDL_Renderer *renderer = data; + SDL_Rect rect = { 32 * pos.x, 32 * pos.y, 32, 32 }; + + SDL_SetRenderDrawColor(renderer, 0x00, has_goal ? 0xFF : 0x00, 0xFF, 0xFF); + + if (SDL_RenderFillRect(renderer, &rect)) { + die("SDL_RenderFillRect(): %s", SDL_GetError()); + } + + return true; +} + +static sok_ctx_walk_cbs_t +DRAW_CBS = { + .on_wall = draw_on_wall, + .on_goal = draw_on_goal, + .on_home = draw_on_home, + .on_box = draw_on_box, +}; +/* + * typedef struct { + * sok_ctx_walk_pos_cb_t on_size, + * on_wall; + * sok_ctx_walk_tile_cb_t on_home, + * on_box; + * sok_ctx_walk_goal_cb_t on_goal; + * sok_ctx_walk_move_cb_t on_move; + * } sok_ctx_walk_cbs_t; + * + * _Bool sok_ctx_walk( + * const sok_ctx_t * const, + * const sok_ctx_walk_cbs_t * const, + * void * const + * ); + */ + +static void +draw( + SDL_Renderer * const renderer, + const sok_ctx_t * const ctx, + const size_t level_num, + const level_t * const level +) { + // clear + const SDL_Color c = get_bg(ctx); + SDL_SetRenderDrawColor(renderer, c.r, c.g, c.b, c.a); + SDL_RenderClear(renderer); + + sok_ctx_walk(ctx, &DRAW_CBS, renderer); + + // flip + SDL_RenderPresent(renderer); +} + int main(int argc, char *argv[]) { - return 0; + size_t warp_buf = 0; + size_t level_num = (argc > 1) ? atoi(argv[1]) : 0; + const level_t *level = levels_get_level(level_num); + + // init context + sok_ctx_t ctx; + sok_ctx_init(&ctx, NULL); + + if (!sok_ctx_set_level(&ctx, level->data)) { + die("Couldn't load level %zu", level_num); + } + + // init sdl + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) { + die("SDL_Init(): %s", SDL_GetError()); + } + + if (atexit(SDL_Quit)) { + die("atexit(): %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + // create window and renderer + SDL_Window *win; + SDL_Renderer *renderer; + if (SDL_CreateWindowAndRenderer(800, 600, SDL_WINDOW_RESIZABLE, &win, &renderer)) { + die("SDL_CreateWindowAndRenderer(): %s", SDL_GetError()); + } + + bool done = false; + SDL_Event ev; + while (!done) { + while (SDL_PollEvent(&ev)) { + switch (ev.type) { + case SDL_QUIT: + done = true; + break; + case SDL_KEYUP: + { + const action_t action = get_action(ev.key.keysym.sym); + + switch (action.type) { + case ACTION_QUIT: + done = true; + break; + case ACTION_MOVE: + if (!sok_ctx_move(&ctx, (sok_dir_t) action.data)) { + warn("move %s failed", SOK_DIR_TO_STR((sok_dir_t) action.data)); + } + + break; + case ACTION_UNDO: + if (!sok_ctx_undo(&ctx)) { + warn("undo failed"); + } + + break; + case ACTION_NEXT: + if (sok_ctx_is_done(&ctx)) { + // advance level + level_num++; + level = levels_get_level(level_num); + + // load next level + if (!sok_ctx_set_level(&ctx, level->data)) { + die("Couldn't load level %zu", level_num); + } + } else { + warn("cannot advance to next level"); + } + + break; + case ACTION_RESET: + // reset level + if (!sok_ctx_set_level(&ctx, level->data)) { + die("Couldn't load level %zu", level_num); + } + + break; + case ACTION_WARP: + level_num = warp_buf; + level = levels_get_level(level_num); + + // load level + if (!sok_ctx_set_level(&ctx, level->data)) { + die("Couldn't load level %zu", level_num); + } + + warp_buf = 0; + + break; + case ACTION_WARP_BUF_PUSH: + warp_buf = 10 * warp_buf + action.data; + + break; + case ACTION_WARP_BUF_POP: + warp_buf /= 10; + + break; + case ACTION_SOLVE: + { + // get current number of moves + const size_t old_num_moves = ctx.num_moves; + + if (sok_solve(&ctx, solve_on_error)) { + // found solution, print it + draw_moves(&ctx, old_num_moves); + } else { + warn("Couldn't solve level"); + } + } + default: + // ignore + break; + } + } + + break; + default: + // ignore + break; + } + } + + draw(renderer, &ctx, level_num, level); + } + + // fini renderer, window + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(win); + + // return success + return EXIT_SUCCESS; } -- cgit v1.2.3