changeset 129:9301c7c84471

core: implement basic drawables, closes #2491 @1h
author David Demelier <markand@malikania.fr>
date Tue, 06 Oct 2020 13:55:20 +0200
parents 365e40e92800
children 09978921e281
files examples/CMakeLists.txt examples/assets/sprites/explosion.png examples/example-drawable.c libcore/CMakeLists.txt libcore/core/drawable.c libcore/core/drawable.h
diffstat 6 files changed, 510 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/examples/CMakeLists.txt	Tue Oct 06 13:53:19 2020 +0200
+++ b/examples/CMakeLists.txt	Tue Oct 06 13:55:20 2020 +0200
@@ -44,3 +44,12 @@
 		${examples_SOURCE_DIR}/assets/sounds/vabsounds-romance.ogg 
 	LIBRARIES libcore
 )
+
+molko_define_executable(
+	TARGET example-drawable
+	SOURCES example-drawable.c
+	FOLDER examples
+	LIBRARIES libcore
+	ASSETS
+		${examples_SOURCE_DIR}/assets/sprites/explosion.png
+)
Binary file examples/assets/sprites/explosion.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/example-drawable.c	Tue Oct 06 13:55:20 2020 +0200
@@ -0,0 +1,163 @@
+/*
+ * example-drawable.c -- example on how to use automatic drawables
+ *
+ * Copyright (c) 2020 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 <core/animation.h>
+#include <core/clock.h>
+#include <core/event.h>
+#include <core/drawable.h>
+#include <core/key.h>
+#include <core/label.h>
+#include <core/painter.h>
+#include <core/panic.h>
+#include <core/sys.h>
+#include <core/image.h>
+#include <core/sprite.h>
+#include <core/texture.h>
+#include <core/theme.h>
+#include <core/util.h>
+#include <core/window.h>
+
+#include <assets/sprites/explosion.h>
+
+#define W 1280
+#define H 720
+
+static struct label help = {
+	.text = "Keys: <Esc> to reset. Click anywhere to spawn a drawable.",
+	.x = 10,
+	.y = 10,
+	.w = W,
+	.h = 32,
+	.flags = LABEL_NO_HCENTER,
+	.color = 0x4f8fbaff
+};
+
+#if 0
+// TODO: for the moment only animations are supported.
+static unsigned int which_selection;
+static char which_text[128];
+static struct label which = {
+	.text = buf,
+	.x = 10,
+	.y = 40,
+	.w = W,
+	.h = 32,
+	.flags = LABEL_NO_HCENTER,
+	.color = 0x4f8fbaff
+};
+#endif
+
+static struct drawable_stack stack;
+
+/*
+ * List of drawables for this example.
+ * -----------------------------------------------------------------------------
+ */
+
+/* 0: Explosion animation. */
+static struct texture explosion_tex;
+static struct sprite explosion_sprite;
+static struct animation explosion_animation;
+
+static void
+init(void)
+{
+	if (!sys_init() ||
+	    !window_init("Example - Drawable", W, H) ||
+	    !theme_init())
+		panic();
+
+	/* 0: Explosion animation. */
+	if (!image_openmem(&explosion_tex, explosion, sizeof (explosion)))
+		panic();
+
+	sprite_init(&explosion_sprite, &explosion_tex, 256, 256);
+	animation_init(&explosion_animation, &explosion_sprite, 100);
+}
+
+static void
+spawn(int x, int y)
+{
+	struct drawable dw;
+
+	drawable_from_animation(&dw, &explosion_animation, x, y);
+	drawable_stack_add(&stack, &dw);
+}
+
+static void
+run(void)
+{
+	struct clock clock = {0};
+
+	clock_start(&clock);
+
+	for (;;) {
+		union event ev;
+		unsigned int elapsed = clock_elapsed(&clock);
+
+		clock_start(&clock);
+
+		while (event_poll(&ev)) {
+			switch (ev.type) {
+			case EVENT_KEYDOWN:
+				switch (ev.key.key) {
+				case KEY_ESCAPE:
+					drawable_stack_finish(&stack);
+					break;
+				default:
+					break;
+				}
+				break;
+			case EVENT_CLICKDOWN:
+				spawn(ev.click.x, ev.click.y);
+				break;
+			case EVENT_QUIT:
+				return;
+			default:
+				break;
+			}
+		}
+
+		drawable_stack_update(&stack, elapsed);
+		painter_set_color(0xebede9ff);
+		painter_clear();
+		label_draw(&help);
+		drawable_stack_draw(&stack);
+		painter_present();
+
+		if ((elapsed = clock_elapsed(&clock)) < 20)
+			delay(20 - elapsed);
+	}
+}
+
+static void
+quit(void)
+{
+	
+}
+
+int
+main(int argc, char **argv)
+{
+	(void)argc;
+	(void)argv;
+
+	init();
+	run();
+	quit();
+}
--- a/libcore/CMakeLists.txt	Tue Oct 06 13:53:19 2020 +0200
+++ b/libcore/CMakeLists.txt	Tue Oct 06 13:55:20 2020 +0200
@@ -47,6 +47,8 @@
 	${libcore_SOURCE_DIR}/core/color.h
 	${libcore_SOURCE_DIR}/core/debug.c
 	${libcore_SOURCE_DIR}/core/debug.h
+	${libcore_SOURCE_DIR}/core/drawable.c
+	${libcore_SOURCE_DIR}/core/drawable.h
 	${libcore_SOURCE_DIR}/core/error.c
 	${libcore_SOURCE_DIR}/core/error.h
 	${libcore_SOURCE_DIR}/core/error_p.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/drawable.c	Tue Oct 06 13:55:20 2020 +0200
@@ -0,0 +1,159 @@
+/*
+ * drawable.c -- automatic drawable objects
+ *
+ * Copyright (c) 2020 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 <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "animation.h"
+#include "drawable.h"
+#include "util.h"
+#include "sprite.h"
+
+bool
+drawable_update(struct drawable *dw, unsigned int ticks)
+{
+	assert(dw);
+
+	return dw->update(dw, ticks);
+}
+
+void
+drawable_draw(struct drawable *dw)
+{
+	assert(dw);
+
+	dw->draw(dw);
+}
+
+void
+drawable_finish(struct drawable *dw)
+{
+	if (dw->finish)
+		dw->finish(dw);
+}
+
+static bool
+drawable_animation_update(struct drawable *dw, unsigned int ticks)
+{
+	return animation_update(dw->data, ticks);
+}
+
+static void
+drawable_animation_draw(struct drawable *dw)
+{
+	return animation_draw(dw->data, dw->x, dw->y);
+}
+
+static void
+drawable_animation_finish(struct drawable *dw)
+{
+	free(dw->data);
+}
+
+void
+drawable_from_animation(struct drawable *dw,
+			const struct animation *an,
+			int x,
+			int y)
+{
+	assert(dw);
+	assert(an);
+
+	memset(dw, 0, sizeof (*dw));
+	
+	dw->data = ememdup(an, sizeof (*an));
+	dw->x = x - (an->sprite->cellw / 2);
+	dw->y = y - (an->sprite->cellh / 2);
+	dw->update = drawable_animation_update;
+	dw->draw = drawable_animation_draw;
+	dw->finish = drawable_animation_finish;
+}
+
+void
+drawable_stack_init(struct drawable_stack *st)
+{
+	assert(st);
+
+	memset(st, 0, sizeof (*st));
+}
+
+bool
+drawable_stack_add(struct drawable_stack *st, const struct drawable *dw)
+{
+	/* Find an empty slot. */
+	struct drawable *slot = NULL;
+
+	for (size_t i = 0; i < DRAWABLE_STACK_MAX; ++i) {
+		struct drawable *dtmp = &st->objects[i];
+
+		dtmp = &st->objects[i];
+
+		if (!dtmp->update && !dtmp->draw) {
+			slot = dtmp;
+			break;
+		}
+	}
+
+	if (slot) {
+		memcpy(slot, dw, sizeof (*dw));
+		return true;
+	}
+	
+	return false;
+}
+
+void
+drawable_stack_update(struct drawable_stack *st, unsigned int ticks)
+{
+	assert(st);
+
+	for (size_t i = 0; i < DRAWABLE_STACK_MAX; ++i) {
+		struct drawable *dw = &st->objects[i];
+
+		if (dw->update && dw->update(dw, ticks))
+			memset(dw, 0, sizeof (*dw));
+	}
+}
+
+void
+drawable_stack_draw(struct drawable_stack *st)
+{
+	assert(st);
+
+	for (size_t i = 0; i < DRAWABLE_STACK_MAX; ++i) {
+		struct drawable *dw = &st->objects[i];
+
+		if (dw->draw)
+			dw->draw(dw);
+	}
+}
+
+void
+drawable_stack_finish(struct drawable_stack *st)
+{
+	for (size_t i = 0; i < DRAWABLE_STACK_MAX; ++i) {
+		struct drawable *dw = &st->objects[i];
+
+		if (dw->finish)
+			dw->finish(dw);
+	}
+
+	memset(st, 0, sizeof (*st));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/drawable.h	Tue Oct 06 13:55:20 2020 +0200
@@ -0,0 +1,177 @@
+/*
+ * drawable.h -- automatic drawable objects
+ *
+ * Copyright (c) 2020 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 MOLKO_DRAWABLE_H
+#define MOLKO_DRAWABLE_H
+
+#include <stdbool.h>
+
+/**
+ * \brief Maximum number of drawable object into a stack.
+ */
+#define DRAWABLE_STACK_MAX      128
+
+struct animation;
+
+/**
+ * \brief Abstract drawable object.
+ *
+ * This structure is used to
+ */
+struct drawable {
+	void *data;     /*!< (RW) Drawable data. */
+	int x;          /*!< (RW) X coordinate if necessary. */
+	int y;          /*!< (RW) Y coordinate if necessary. */
+
+	/**
+	 * Update this drawable.
+	 *
+	 * \param dw the drawable object
+	 * \param ticks the number of ticks since last frame
+	 * \return true if object has ended
+	 */
+	bool (*update)(struct drawable *dw, unsigned int ticks);
+
+	/**
+	 * Draw this drawable.
+	 *
+	 * \param dw the drawable object
+	 */
+	void (*draw)(struct drawable *dw);
+	
+	/**
+	 * Destroy the drawable if necessary.
+	 *
+	 * \note This function is optional and can be NULL.
+	 * \param dw the drawable object
+	 */
+	void (*finish)(struct drawable *dw);
+};
+
+/**
+ * Update the object
+ *
+ * \pre dw != NULL
+ * \param dw the drawable object
+ * \param ticks elapsed milliseconds since last frame
+ * \return true if the drawable ended
+ */
+bool
+drawable_update(struct drawable *dw, unsigned int ticks);
+
+/**
+ * Draw the drawable.
+ *
+ * \pre dw != NULL
+ * \param dw the drawable object
+ */
+void
+drawable_draw(struct drawable *dw);
+
+/**
+ * Dispose internal resources if necessary.
+ *
+ * \pre dw != NULL
+ * \param dw the drawable object
+ */
+void
+drawable_finish(struct drawable *dw);
+
+/**
+ * Create a drawable from an animation.
+ *
+ * The animation is copied verbatim (as such internal resources must be kept
+ * valid).
+ *
+ * \pre dw != NULL
+ * \pre an the animation
+ * \param dw the drawable
+ * \param an the animation
+ * \param x x position on screen
+ * \param y y position on screen
+ */
+void
+drawable_from_animation(struct drawable *dw,
+                        const struct animation *an,
+                        int x,
+                        int y);
+
+/**
+ * \brief Stack of drawable objects.
+ *
+ * This stack of drawable object can be used to store drawable objects within
+ * a specific transition (state, battle, menu, etc).
+ *
+ * You can add, clear, and update and draw them.
+ */
+struct drawable_stack {
+	struct drawable objects[DRAWABLE_STACK_MAX];    /*!< (RW) Drawables. */
+};
+
+/**
+ * Initialize the stack.
+ *
+ * \pre st != NULL
+ * \param st the drawable stack
+ */
+void
+drawable_stack_init(struct drawable_stack *st);
+
+/**
+ * Add a drawable object into the stack.
+ *
+ * The drawable object internals are copied verbatim into the stack.
+ *
+ * \pre st != NULL
+ * \pre dw != NULL
+ * \param st the stack
+ * \param dw the drawable to copy from
+ * \return true if the drawable was placed correctly and false if there wasn't
+ *         enough room.
+ */
+bool
+drawable_stack_add(struct drawable_stack *st, const struct drawable *dw);
+
+/**
+ * Update all drawable objects.
+ *
+ * Also remove drawable objects if they were finished.
+ *
+ * \pre st != NULL
+ * \param st the drawable stack
+ * \param ticks the number of ticks since last frame
+ */
+void
+drawable_stack_update(struct drawable_stack *st, unsigned int ticks);
+
+/**
+ * Draw all drawable objects.
+ *
+ * \pre st != NULL
+ * \param st the drawable stack
+ */
+void
+drawable_stack_draw(struct drawable_stack *st);
+
+/**
+ * Clear all drawable objects into the stack.
+ */
+void
+drawable_stack_finish(struct drawable_stack *st);
+
+#endif /* !MOLKO_DRAWABLE_H */