changeset 363:c74ab1bbedec

js: add drawable bindings
author David Demelier <markand@malikania.fr>
date Sun, 24 Oct 2021 09:55:12 +0200
parents 12367bfc2df6
children 570ab19bf268
files src/libmlk-core-js/CMakeLists.txt src/libmlk-core-js/core/js-drawable-stack.c src/libmlk-core-js/core/js-drawable-stack.h src/libmlk-core-js/core/js-drawable.c src/libmlk-core-js/core/js-drawable.h src/libmlk-core-js/core/js-state.c src/mlk-run/main.c
diffstat 7 files changed, 434 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/src/libmlk-core-js/CMakeLists.txt	Fri Oct 22 14:40:03 2021 +0200
+++ b/src/libmlk-core-js/CMakeLists.txt	Sun Oct 24 09:55:12 2021 +0200
@@ -28,6 +28,10 @@
 	${libmlk-core-js_SOURCE_DIR}/core/js-color.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-core.c
 	${libmlk-core-js_SOURCE_DIR}/core/js-core.h
+	${libmlk-core-js_SOURCE_DIR}/core/js-drawable.c
+	${libmlk-core-js_SOURCE_DIR}/core/js-drawable.h
+	${libmlk-core-js_SOURCE_DIR}/core/js-drawable-stack.c
+	${libmlk-core-js_SOURCE_DIR}/core/js-drawable-stack.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-event.c
 	${libmlk-core-js_SOURCE_DIR}/core/js-event.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-font.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libmlk-core-js/core/js-drawable-stack.c	Sun Oct 24 09:55:12 2021 +0200
@@ -0,0 +1,124 @@
+/*
+ * js-drawable-stack.h -- core drawable_stack 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/alloc.h>
+#include <core/drawable.h>
+
+#include "js-drawable-stack.h"
+#include "js-drawable.h"
+
+#define SIGNATURE DUK_HIDDEN_SYMBOL("Mlk.DrawableStack")
+
+static inline struct drawable_stack *
+self(duk_context *ctx)
+{
+	struct drawable_stack *sf = NULL;
+
+	duk_push_this(ctx);
+	duk_get_prop_string(ctx, -1, SIGNATURE);
+	sf = duk_to_pointer(ctx, -1);
+	duk_pop_2(ctx);
+
+	if (!sf)
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a DrawableStack object");
+
+	return sf;
+}
+
+static duk_ret_t
+DrawableStack_constructor(duk_context *ctx)
+{
+	duk_push_this(ctx);
+	duk_push_pointer(ctx, alloc_new0(sizeof (struct drawable_stack)));
+	duk_put_prop_string(ctx, -2, SIGNATURE);
+	duk_pop(ctx);
+
+	return 0;
+}
+
+static duk_ret_t
+DrawableStack_destructor(duk_context *ctx)
+{
+	struct drawable_stack *st;
+
+	duk_get_prop_string(ctx, 0, SIGNATURE);
+	
+	if ((st = duk_to_pointer(ctx, -1))) {
+		drawable_stack_finish(st);
+		free(st);
+	}
+		
+	duk_pop(ctx);
+	duk_del_prop_string(ctx, 0, SIGNATURE);
+
+	return 0;
+}
+
+static duk_ret_t
+DrawableStack_add(duk_context *ctx)
+{
+	struct drawable_stack *st = self(ctx);
+	struct drawable *dw = js_drawable_require(ctx, 0);
+
+	if (drawable_stack_add(st, dw) < 0)
+		drawable_finish(dw);
+
+	return 0;
+}
+
+static duk_ret_t
+DrawableStack_update(duk_context *ctx)
+{
+	struct drawable_stack *st = self(ctx);
+	const unsigned int ticks = duk_require_uint(ctx, 0);
+
+	duk_push_uint(ctx, drawable_stack_update(st, ticks));
+
+	return 1;
+}
+
+static duk_ret_t
+DrawableStack_draw(duk_context *ctx)
+{
+	drawable_stack_draw(self(ctx));
+
+	return 0;
+}
+
+static duk_function_list_entry methods[] = {
+	{ "add",        DrawableStack_add,      1       },
+	{ "update",     DrawableStack_update,   1       },
+	{ "draw",       DrawableStack_draw,     0       },
+	{ NULL,         NULL,                   0       }
+};
+
+void
+js_drawable_stack_bind(duk_context *ctx)
+{
+	assert(ctx);
+
+	duk_push_c_function(ctx, DrawableStack_constructor, 0);
+	duk_push_object(ctx);
+	duk_put_function_list(ctx, -1, methods);
+	duk_push_c_function(ctx, DrawableStack_destructor, 1);
+	duk_set_finalizer(ctx, -2);
+	duk_put_prop_string(ctx, -2, "prototype");
+	duk_put_global_string(ctx, "DrawableStack");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libmlk-core-js/core/js-drawable-stack.h	Sun Oct 24 09:55:12 2021 +0200
@@ -0,0 +1,27 @@
+/*
+ * js-drawable-stack.h -- core drawable_stack 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_DRAWABLE_STACK_H
+#define MLK_CORE_JS_DRAWABLE_STACK_H
+
+#include <duktape.h>
+
+void
+js_drawable_stack_bind(duk_context *);
+
+#endif /* !MLK_CORE_JS_DRAWABLE_STACK_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libmlk-core-js/core/js-drawable.c	Sun Oct 24 09:55:12 2021 +0200
@@ -0,0 +1,233 @@
+/*
+ * js-drawable.c -- core drawable 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/alloc.h>
+#include <core/drawable.h>
+
+#include "js-drawable.h"
+
+#define SIGNATURE DUK_HIDDEN_SYMBOL("Mlk.Drawable")
+
+struct self {
+	duk_context *ctx;
+	void *ptr;
+	struct drawable dw;
+	unsigned int refc;
+};
+
+static inline struct self *
+self(duk_context *ctx)
+{
+	struct self *sf = NULL;
+
+	duk_push_this(ctx);
+	duk_get_prop_string(ctx, -1, SIGNATURE);
+	sf = duk_to_pointer(ctx, -1);
+	duk_pop_2(ctx);
+
+	if (!sf)
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Drawable object");
+
+	return sf;
+}
+
+static inline int
+callable(struct self *s, const char *prop, duk_context **ctx)
+{
+	int callable;
+
+	if (!s->ptr)
+		return 0;
+
+	duk_push_heapptr(s->ctx, s->ptr);
+	duk_get_prop_string(s->ctx, -1, prop);
+	duk_remove(s->ctx, -2);
+
+	if (duk_is_callable(s->ctx, -1)) {
+		*ctx = s->ctx;
+		callable = 1;
+	} else {
+		*ctx = NULL;
+		callable = 0;
+		duk_pop(s->ctx);
+	}
+
+	return callable;
+}
+
+static int
+update(struct drawable *dw, unsigned int ticks)
+{
+	duk_context *ctx;
+	int ret = 0;
+
+	if (callable(dw->data, "update", &ctx)) {
+		duk_push_uint(ctx, ticks);
+		duk_call(ctx, 1);
+		ret = duk_to_int(ctx, -1);
+	}
+
+	return ret;
+}
+
+static void
+draw(struct drawable *dw)
+{
+	duk_context *ctx;
+
+	if (callable(dw->data, "draw", &ctx))
+		duk_call(ctx, 0);
+}
+
+static void
+end(struct drawable *dw)
+{
+	duk_context *ctx;
+
+	if (callable(dw->data, "end", &ctx))
+		duk_call(ctx, 0);
+}
+
+static void
+finish(struct drawable *dw)
+{
+	struct self *sf = dw->data;
+
+	if (!--sf->refc)
+		free(sf);
+}
+
+static duk_ret_t
+Drawable_getX(duk_context *ctx)
+{
+	duk_push_uint(ctx, self(ctx)->dw.x);
+
+	return 1;
+}
+
+static duk_ret_t
+Drawable_setX(duk_context *ctx)
+{
+	self(ctx)->dw.x = duk_require_uint(ctx, 0);
+
+	return 0;
+}
+
+static duk_ret_t
+Drawable_getY(duk_context *ctx)
+{
+	duk_push_uint(ctx, self(ctx)->dw.y);
+
+	return 1;
+}
+
+static duk_ret_t
+Drawable_setY(duk_context *ctx)
+{
+	self(ctx)->dw.y = duk_require_uint(ctx, 0);
+
+	return 0;
+}
+
+static duk_ret_t
+Drawable_constructor(duk_context *ctx)
+{
+	struct self *self;
+	const int x = duk_require_int(ctx, 0);
+	const int y = duk_require_int(ctx, 1);
+
+	self = alloc_new0(sizeof (*self));
+	self->refc = 1;
+	self->ctx = ctx;
+	self->dw.x = x;
+	self->dw.y = y;
+	self->dw.data = self;
+	self->dw.update = update;
+	self->dw.finish = finish;
+	self->dw.draw = draw;
+	self->dw.end = end;
+
+	duk_push_this(ctx);
+	self->ptr = duk_get_heapptr(ctx, -1);
+	duk_push_pointer(ctx, self);
+	duk_put_prop_string(ctx, -2, SIGNATURE);
+	duk_push_string(ctx, "x");
+	duk_push_c_function(ctx, Drawable_getX, 0);
+	duk_push_c_function(ctx, Drawable_setX, 1);
+	duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
+	duk_push_string(ctx, "y");
+	duk_push_c_function(ctx, Drawable_getY, 0);
+	duk_push_c_function(ctx, Drawable_setY, 1);
+	duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
+	duk_pop(ctx);
+
+	return 0;
+}
+
+static duk_ret_t
+Drawable_destructor(duk_context *ctx)
+{
+	struct self *sf;
+
+	duk_get_prop_string(ctx, 0, SIGNATURE);
+
+	if ((sf = duk_to_pointer(ctx, -1))) {
+		sf->ptr = NULL;
+		drawable_finish(&sf->dw);
+	}
+
+	duk_del_prop_string(ctx, 0, SIGNATURE);
+	duk_pop(ctx);
+
+	return 0;
+}
+
+
+void
+js_drawable_bind(duk_context *ctx)
+{
+	assert(ctx);
+
+	duk_push_c_function(ctx, Drawable_constructor, 2);
+	duk_push_object(ctx);
+	duk_push_c_function(ctx, Drawable_destructor, 1);
+	duk_set_finalizer(ctx, -2);
+	duk_put_prop_string(ctx, -2, "prototype");
+	duk_put_global_string(ctx, "Drawable");
+}
+
+struct drawable *
+js_drawable_require(duk_context *ctx, duk_idx_t idx)
+{
+	struct self *sf = NULL;
+
+	if (duk_is_object(ctx, idx)) {
+		duk_get_prop_string(ctx, idx, SIGNATURE);
+		sf = duk_to_pointer(ctx, -1);
+		duk_pop(ctx);
+	}
+
+	if (!sf)
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Drawable object");
+
+	sf->refc++;
+
+	return &sf->dw;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libmlk-core-js/core/js-drawable.h	Sun Oct 24 09:55:12 2021 +0200
@@ -0,0 +1,32 @@
+/*
+ * js-drawable.h -- core drawable 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_DRAWABLE_H
+#define MLK_CORE_JS_DRAWABLE_H
+
+#include <duktape.h>
+
+struct drawable;
+
+void
+js_drawable_bind(duk_context *);
+
+struct drawable *
+js_drawable_require(duk_context *, duk_idx_t);
+
+#endif /* !MLK_CORE_JS_DRAWABLE_H */
--- a/src/libmlk-core-js/core/js-state.c	Fri Oct 22 14:40:03 2021 +0200
+++ b/src/libmlk-core-js/core/js-state.c	Sun Oct 24 09:55:12 2021 +0200
@@ -26,11 +26,10 @@
 #include "js-state.h"
 
 #define SIGNATURE DUK_HIDDEN_SYMBOL("Mlk.State")
-#define SELF DUK_HIDDEN_SYMBOL("Mlk.State.self")
 
 struct self {
 	duk_context *ctx;
-	void *selfptr;
+	void *ptr;
 	struct state state;
 	unsigned int refc;
 };
@@ -40,7 +39,10 @@
 {
 	int callable;
 
-	duk_push_heapptr(s->ctx, s->selfptr);
+	if (!s->ptr)
+		return 0;
+
+	duk_push_heapptr(s->ctx, s->ptr);
 	duk_get_prop_string(s->ctx, -1, prop);
 	duk_remove(s->ctx, -2);
 
@@ -140,28 +142,8 @@
 {
 	struct self *self = state->data;
 
-	if (!--self->refc) {
-		duk_push_heapptr(self->ctx, self->selfptr);
-		duk_del_prop_string(self->ctx, -1, SIGNATURE);
-		duk_pop(self->ctx);
+	if (!--self->refc)
 		free(self);
-	}
-}
-
-static inline struct self *
-self(duk_context *ctx)
-{
-	struct self *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)
-		return (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a State object"), NULL;
-
-	return data;
 }
 
 static duk_ret_t
@@ -183,9 +165,7 @@
 	self->state.finish = finish;
 
 	duk_push_this(ctx);
-	self->selfptr = duk_get_heapptr(ctx, -1);
-	duk_dup(ctx, -1);
-	duk_put_prop_string(ctx, -2, SELF);
+	self->ptr = duk_get_heapptr(ctx, -1);
 	duk_push_pointer(ctx, self);
 	duk_put_prop_string(ctx, -2, SIGNATURE);
 	duk_pop(ctx);
@@ -200,8 +180,10 @@
 
 	duk_get_prop_string(ctx, 0, SIGNATURE);
 
-	if ((self = duk_to_pointer(ctx, -1)))
+	if ((self = duk_to_pointer(ctx, -1))) {
+		self->ptr = NULL;
 		state_finish(&self->state);
+	}
 
 	duk_pop(ctx);
 
--- a/src/mlk-run/main.c	Fri Oct 22 14:40:03 2021 +0200
+++ b/src/mlk-run/main.c	Sun Oct 24 09:55:12 2021 +0200
@@ -30,6 +30,8 @@
 #include <core/js-clock.h>
 #include <core/js-color.h>
 #include <core/js-core.h>
+#include <core/js-drawable.h>
+#include <core/js-drawable-stack.h>
 #include <core/js-event.h>
 #include <core/js-font.h>
 #include <core/js-game.h>
@@ -66,6 +68,8 @@
 	js_animation_bind(ctx);
 	js_clock_bind(ctx);
 	js_color_bind(ctx);
+	js_drawable_bind(ctx);
+	js_drawable_stack_bind(ctx);
 	js_event_bind(ctx);
 	js_font_bind(ctx);
 	js_game_bind(ctx);