Mercurial > molko
changeset 346:323d13f49233
js: add state and game bindings
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 18 Oct 2021 21:52:46 +0200 |
parents | 56830e59f776 |
children | 0969931b98e4 |
files | src/libmlk-core-js/CMakeLists.txt src/libmlk-core-js/core/js-event.c src/libmlk-core-js/core/js-event.h src/libmlk-core-js/core/js-game.c src/libmlk-core-js/core/js-game.h src/libmlk-core-js/core/js-state.c src/libmlk-core-js/core/js-state.h src/mlk-run/main.c |
diffstat | 8 files changed, 460 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/src/libmlk-core-js/CMakeLists.txt Mon Oct 18 13:08:28 2021 +0200 +++ b/src/libmlk-core-js/CMakeLists.txt Mon Oct 18 21:52:46 2021 +0200 @@ -30,6 +30,8 @@ ${libmlk-core-js_SOURCE_DIR}/core/js-event.h ${libmlk-core-js_SOURCE_DIR}/core/js-font.c ${libmlk-core-js_SOURCE_DIR}/core/js-font.h + ${libmlk-core-js_SOURCE_DIR}/core/js-game.c + ${libmlk-core-js_SOURCE_DIR}/core/js-game.h ${libmlk-core-js_SOURCE_DIR}/core/js-music.c ${libmlk-core-js_SOURCE_DIR}/core/js-music.h ${libmlk-core-js_SOURCE_DIR}/core/js-painter.c @@ -38,6 +40,8 @@ ${libmlk-core-js_SOURCE_DIR}/core/js-sound.h ${libmlk-core-js_SOURCE_DIR}/core/js-sprite.c ${libmlk-core-js_SOURCE_DIR}/core/js-sprite.h + ${libmlk-core-js_SOURCE_DIR}/core/js-state.c + ${libmlk-core-js_SOURCE_DIR}/core/js-state.h ${libmlk-core-js_SOURCE_DIR}/core/js-texture.c ${libmlk-core-js_SOURCE_DIR}/core/js-texture.h ${libmlk-core-js_SOURCE_DIR}/core/js-window.c
--- a/src/libmlk-core-js/core/js-event.c Mon Oct 18 13:08:28 2021 +0200 +++ b/src/libmlk-core-js/core/js-event.c Mon Oct 18 21:52:46 2021 +0200 @@ -78,12 +78,8 @@ if (!event_poll(&ev)) duk_push_null(ctx); - else { - duk_push_object(ctx); - duk_push_int(ctx, ev.type); - duk_put_prop_string(ctx, -2, "type"); - push[ev.type](ctx, &ev); - } + else + js_event_push(ctx, &ev); return 1; } @@ -289,3 +285,12 @@ duk_put_prop_string(ctx, -2, "Event"); duk_pop(ctx); } + +void +js_event_push(duk_context *ctx, const union event *ev) +{ + duk_push_object(ctx); + duk_push_int(ctx, ev->type); + duk_put_prop_string(ctx, -2, "type"); + push[ev->type](ctx, ev); +}
--- a/src/libmlk-core-js/core/js-event.h Mon Oct 18 13:08:28 2021 +0200 +++ b/src/libmlk-core-js/core/js-event.h Mon Oct 18 21:52:46 2021 +0200 @@ -21,7 +21,12 @@ #include <duktape.h> +union event; + void js_event_bind(duk_context *); +void +js_event_push(duk_context *, const union event *); + #endif /* !MLK_CORE_JS_EVENT_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libmlk-core-js/core/js-game.c Mon Oct 18 21:52:46 2021 +0200 @@ -0,0 +1,107 @@ +/* + * js-game.c -- core gamej binding + * + * Copyright (c) 2020-2021 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include <core/game.h> + +#include "js-game.h" +#include "js-state.h" + +#define TABLE DUK_HIDDEN_SYMBOL("Mlk.Game.table") + +/* + * TODO: determine if it's worth it to add handle, update and draw functions. + */ + +static duk_ret_t +Game_push(duk_context *ctx) +{ + struct state *state = js_state_require(ctx, 0); + + if (game.state == &game.states[GAME_STATE_MAX]) + duk_error(ctx, DUK_ERR_RANGE_ERROR, "too many states"); + + game_push(state); + + /* Store the state to avoid destruction. */ + duk_push_global_stash(ctx); + duk_get_prop_string(ctx, -1, TABLE); + duk_dup(ctx, 0); + duk_put_prop_index(ctx, -2, duk_get_length(ctx, -2)); + duk_pop_n(ctx, 2); + + return 0; +} + +static duk_ret_t +Game_pop(duk_context *ctx) +{ + if (game.state == &game.states[0]) + return 0; + + /* Remove the stored reference. */ + duk_push_global_stash(ctx); + duk_get_prop_string(ctx, -1, TABLE); + duk_del_prop_index(ctx, -1, duk_get_length(ctx, -1) - 1); + duk_pop_n(ctx, 2); + + return 0; +} + +static duk_ret_t +Game_loop(duk_context *ctx) +{ + (void)ctx; + + game_loop(); + + return 0; +} + +static duk_ret_t +Game_quit(duk_context *ctx) +{ + (void)ctx; + + game_quit(); + + return 0; +} + +static const duk_function_list_entry functions[] = { + { "push", Game_push, 1 }, + { "pop", Game_pop, 0 }, + { "loop", Game_loop, 0 }, + { "quit", Game_quit, 0 }, + { NULL, NULL, 0 } +}; + +void +js_game_bind(duk_context *ctx) +{ + assert(ctx); + + duk_push_object(ctx); + duk_put_function_list(ctx, -1, functions); + duk_put_global_string(ctx, "Game"); + duk_push_global_stash(ctx); + duk_push_array(ctx); + duk_put_prop_string(ctx, -2, TABLE); + duk_pop(ctx); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libmlk-core-js/core/js-game.h Mon Oct 18 21:52:46 2021 +0200 @@ -0,0 +1,27 @@ +/* + * js-game.h -- core game binding + * + * Copyright (c) 2020-2021 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_CORE_JS_GAME_H +#define MLK_CORE_JS_GAME_H + +#include <duktape.h> + +void +js_game_bind(duk_context *); + +#endif /* !MLK_CORE_JS_GAME_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libmlk-core-js/core/js-state.c Mon Oct 18 21:52:46 2021 +0200 @@ -0,0 +1,271 @@ +/* + * js-state.c -- core state binding + * + * Copyright (c) 2020-2021 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> + +#include <core/alloc.h> +#include <core/state.h> + +#include "js-event.h" +#include "js-state.h" + +#define SIGNATURE DUK_HIDDEN_SYMBOL("Mlk.State") +#define FUNCTIONS DUK_HIDDEN_SYMBOL("Mlk.State.functions") + +#define INVOKE(state, function, block) \ +do { \ + struct statedata *data = state->data; \ + \ + duk_push_heapptr(data->ctx, data->heapptr); \ + duk_get_prop_index(data->ctx, -1, function); \ + duk_remove(data->ctx, -2); \ + \ + if (duk_is_callable(data->ctx, -1)) { \ + block \ + duk_pop(data->ctx); \ + } else { \ + duk_pop(data->ctx); \ + } \ +} while (0) + +#define SET(ctx, function) \ +do { \ + struct statedata *data = self(ctx); \ + \ + duk_push_heapptr(ctx, data->heapptr); \ + duk_dup(ctx, 0); \ + duk_put_prop_index(ctx, -2, function); \ + duk_pop(ctx); \ + \ + return 0; \ +} while (0) + +enum statefunc { + FUNC_START, + FUNC_HANDLE, + FUNC_UPDATE, + FUNC_DRAW, + FUNC_SUSPEND, + FUNC_RESUME, + FUNC_END +}; + +struct statedata { + duk_context *ctx; + void *heapptr; + struct state state; +}; + +static void +start(struct state *state) +{ + INVOKE(state, FUNC_START, { + duk_call(data->ctx, 0); + }); +} + +static void +handle(struct state *state, const union event *ev) +{ + INVOKE(state, FUNC_HANDLE, { + js_event_push(data->ctx, ev); + duk_call(data->ctx, 1); + }); +} + +static void +update(struct state *state, unsigned int ticks) +{ + INVOKE(state, FUNC_UPDATE, { + duk_push_uint(data->ctx, ticks); + duk_call(data->ctx, 1); + }); +} + +static void +draw(struct state *state) +{ + INVOKE(state, FUNC_DRAW, { + duk_call(data->ctx, 0); + }); +} + +static void +suspend(struct state *state) +{ + INVOKE(state, FUNC_SUSPEND, { + duk_call(data->ctx, 0); + }); +} + +static void +resume(struct state *state) +{ + INVOKE(state, FUNC_RESUME, { + duk_call(data->ctx, 0); + }); +} + +static void +end(struct state *state) +{ + INVOKE(state, FUNC_END, { + duk_call(data->ctx, 0); + }); +} + +static void +finish(struct state *state) +{ + free(state->data); +} + +static inline struct statedata * +self(duk_context *ctx) +{ + struct statedata *data = NULL; + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, SIGNATURE); + data = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!data) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a State object"); + + return data; +} + +static duk_ret_t +State_setStart(duk_context *ctx) +{ + SET(ctx, FUNC_START); +} + +static duk_ret_t +State_setHandle(duk_context *ctx) +{ + SET(ctx, FUNC_HANDLE); +} + +static duk_ret_t +State_setUpdate(duk_context *ctx) +{ + SET(ctx, FUNC_UPDATE); +} + +static duk_ret_t +State_setDraw(duk_context *ctx) +{ + SET(ctx, FUNC_DRAW); +} + +static duk_ret_t +State_setSuspend(duk_context *ctx) +{ + SET(ctx, FUNC_SUSPEND); +} + +static duk_ret_t +State_setResume(duk_context *ctx) +{ + SET(ctx, FUNC_RESUME); +} + +static duk_ret_t +State_setEnd(duk_context *ctx) +{ + SET(ctx, FUNC_END); +} + +static const struct { + const char *property; + duk_ret_t (*setter)(duk_context *ctx); +} properties[] = { + { "start", State_setStart }, + { "handle", State_setHandle }, + { "update", State_setUpdate }, + { "draw", State_setDraw }, + { "suspend", State_setSuspend }, + { "resume", State_setResume }, + { "end", State_setEnd }, + { NULL, NULL } +}; + +static duk_ret_t +State_constructor(duk_context *ctx) +{ + struct statedata *data; + + data = alloc_new0(sizeof (*data)); + data->ctx = ctx; + data->state.data = data; + data->state.start = start; + data->state.handle = handle; + data->state.update = update; + data->state.draw = draw; + data->state.suspend = suspend; + data->state.resume = resume; + data->state.end = end; + data->state.finish = finish; + + duk_push_this(ctx); + duk_push_pointer(ctx, data); + duk_put_prop_string(ctx, -2, SIGNATURE); + duk_push_array(ctx); + data->heapptr = duk_get_heapptr(ctx, -1); + duk_put_prop_string(ctx, -2, FUNCTIONS); + + /* Push every properties. */ + for (size_t i = 0; properties[i].property; ++i) { + duk_push_string(ctx, properties[i].property); + duk_push_c_function(ctx, properties[i].setter, 1); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_SETTER); + } + + duk_pop(ctx); + + return 0; +} + +void +js_state_bind(duk_context *ctx) +{ + assert(ctx); + + duk_push_c_function(ctx, State_constructor, 1); + duk_put_global_string(ctx, "State"); +} + +struct state * +js_state_require(duk_context *ctx, duk_idx_t idx) +{ + struct statedata *data = NULL; + + if (duk_is_object(ctx, idx)) { + duk_get_prop_string(ctx, idx, SIGNATURE); + data = duk_to_pointer(ctx, -1); + duk_pop(ctx); + } + + if (!data) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a State object"); + + return &data->state; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libmlk-core-js/core/js-state.h Mon Oct 18 21:52:46 2021 +0200 @@ -0,0 +1,30 @@ +/* + * js-state.h -- core state binding + * + * Copyright (c) 2020-2021 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_CORE_JS_STATE_H +#define MLK_CORE_JS_STATE_H + +#include <duktape.h> + +void +js_state_bind(duk_context *); + +struct state * +js_state_require(duk_context *, duk_idx_t); + +#endif /* !MLK_CORE_JS_STATE_H */
--- a/src/mlk-run/main.c Mon Oct 18 13:08:28 2021 +0200 +++ b/src/mlk-run/main.c Mon Oct 18 21:52:46 2021 +0200 @@ -31,10 +31,12 @@ #include <core/js-core.h> #include <core/js-event.h> #include <core/js-font.h> +#include <core/js-game.h> #include <core/js-music.h> #include <core/js-painter.h> #include <core/js-sound.h> #include <core/js-sprite.h> +#include <core/js-state.h> #include <core/js-texture.h> #include <core/js-window.h> @@ -58,12 +60,14 @@ js_animation_bind(ctx); js_clock_bind(ctx); js_core_bind(ctx, &vfs); + js_event_bind(ctx); js_font_bind(ctx); - js_event_bind(ctx); + js_game_bind(ctx); js_music_bind(ctx); js_painter_bind(ctx); js_sound_bind(ctx); js_sprite_bind(ctx); + js_state_bind(ctx); js_texture_bind(ctx); js_window_bind(ctx); }