changeset 141:4eeeccf2b732

core: add trace/vtrace functions, closes #2493
author David Demelier <markand@malikania.fr>
date Wed, 14 Oct 2020 10:29:53 +0200
parents 453651d76f7c
children fea0cc899931
files examples/CMakeLists.txt examples/example-action.c examples/example-trace.c libadventure/CMakeLists.txt libadventure/adventure/trace_hud.c libadventure/adventure/trace_hud.h libcore/CMakeLists.txt libcore/core/message.c libcore/core/message.h libcore/core/trace.c libcore/core/trace.h
diffstat 11 files changed, 451 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/examples/CMakeLists.txt	Tue Oct 13 18:39:35 2020 +0200
+++ b/examples/CMakeLists.txt	Wed Oct 14 10:29:53 2020 +0200
@@ -63,3 +63,10 @@
 	ASSETS
 		${examples_SOURCE_DIR}/assets/sprites/explosion.png
 )
+
+molko_define_executable(
+	TARGET example-trace
+	SOURCES example-trace.c
+	FOLDER examples
+	LIBRARIES libcore libadventure
+)
--- a/examples/example-action.c	Tue Oct 13 18:39:35 2020 +0200
+++ b/examples/example-action.c	Wed Oct 14 10:29:53 2020 +0200
@@ -120,7 +120,7 @@
 				.w = MW,
 				.h = MH,
 				.delay = MESSAGE_DELAY_DEFAULT,
-				.flags = MESSAGE_FLAGS_FADEIN | MESSAGE_FLAGS_AUTOMATIC,
+				.flags = MESSAGE_FLAGS_FADEIN,
 				.text = {
 					"Bienvenue dans ce monde Molko."
 				}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/example-trace.c	Wed Oct 14 10:29:53 2020 +0200
@@ -0,0 +1,109 @@
+/*
+ * example-trace.c -- example on how to use custom trace handlers
+ *
+ * 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/clock.h>
+#include <core/event.h>
+#include <core/sys.h>
+#include <core/window.h>
+#include <core/theme.h>
+#include <core/painter.h>
+#include <core/panic.h>
+#include <core/trace.h>
+#include <core/util.h>
+
+#include <adventure/trace_hud.h>
+
+#define W 1280
+#define H 720
+
+static void
+init(void)
+{
+	if (!sys_init() ||
+	    !window_init("Example - Trace", W, H) ||
+	    !theme_init())
+		panic();
+
+	trace_handler = trace_hud_handler;
+}
+
+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:
+					trace_hud_clear();
+					break;
+				default:
+					trace("keydown pressed: %d", ev.key.key);
+					break;
+				}
+				break;
+			case EVENT_CLICKDOWN:
+				trace("click at %d,%d", ev.click.x, ev.click.y);
+				break;
+			case EVENT_QUIT:
+				return;
+			default:
+				break;
+			}
+		}
+
+		painter_set_color(0xffffffff);
+		painter_clear();
+		trace_hud_update(elapsed);
+		trace_hud_draw();
+		painter_present();
+
+		if ((elapsed = clock_elapsed(&clock)) < 20)
+			delay(20 - elapsed);
+	}
+}
+
+static void
+quit(void)
+{
+	theme_finish();
+	window_finish();
+	sys_finish();
+}
+
+int
+main(int argc, char **argv)
+{
+	(void)argc;
+	(void)argv;
+
+	init();
+	run();
+	quit();
+}
+
--- a/libadventure/CMakeLists.txt	Tue Oct 13 18:39:35 2020 +0200
+++ b/libadventure/CMakeLists.txt	Wed Oct 14 10:29:53 2020 +0200
@@ -26,6 +26,8 @@
 	${libadventure_SOURCE_DIR}/adventure/panic_state.h
 	${libadventure_SOURCE_DIR}/adventure/splashscreen_state.c
 	${libadventure_SOURCE_DIR}/adventure/splashscreen_state.h
+	${libadventure_SOURCE_DIR}/adventure/trace_hud.c
+	${libadventure_SOURCE_DIR}/adventure/trace_hud.h
 )
 
 set(
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libadventure/adventure/trace_hud.c	Wed Oct 14 10:29:53 2020 +0200
@@ -0,0 +1,113 @@
+/*
+ * trace_hud.c -- on screen hud
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include <core/label.h>
+#include <core/font.h>
+#include <core/theme.h>
+#include <core/trace.h>
+
+#include "trace_hud.h"
+
+#define LINES_MAX       (4)
+#define THEME(t)        ((t) ? (t) : theme_default())
+
+static struct {
+	char lines[LINES_MAX + 1][TRACE_LINE_MAX];
+	unsigned int elapsed;
+} data;
+
+struct trace_hud trace_hud = {
+	.timeout = TRACE_HUD_TIMEOUT_DEFAULT
+};
+
+void
+trace_hud_handler(const char *str)
+{
+	assert(str);
+
+	/* 1.Try to find an empty line. */
+	for (size_t i = 0; i < LINES_MAX; ++i) {
+		if (data.lines[i][0] == '\0') {
+			snprintf(data.lines[i], sizeof (data.lines[i]), "%s", str);
+			return;
+		}
+	}
+
+	/* 2. All lines are full, put in last one and move other. */
+	memmove(&data.lines[0], &data.lines[1], sizeof (data.lines[0]) * LINES_MAX - 1);
+	snprintf(data.lines[LINES_MAX - 1], sizeof (data.lines[0]), "%s", str);
+
+	/* 3. Reset elapsed time now. */
+	data.elapsed = 0;
+}
+
+void
+trace_hud_update(unsigned int ticks)
+{
+	data.elapsed += ticks;
+
+	/*
+	 * We have an empty line in the data.lines at LINES_MAX, so we simply so
+	 * to move the whole array.
+	 *
+	 * [0] = "abc"
+	 * [1] = "def"
+	 * [2] = "xyz"
+	 * [3] = "zef"
+	 * [n] = "ldkf"
+	 * [LINES_MAX + 1] = "\0"
+	 */
+	if (data.elapsed >= trace_hud.timeout) {
+		data.elapsed = 0;
+		memmove(&data.lines[0], &data.lines[1], sizeof (data.lines[0]) * LINES_MAX);
+	}
+}
+
+void
+trace_hud_draw(void)
+{
+	struct theme *th;
+	int x, y;
+
+	th = THEME(trace_hud.theme);
+	x = th->padding;
+	y = th->padding;
+
+	for (int i = 0; i < LINES_MAX && data.lines[i][0]; ++i) {
+		label_draw(&(struct label) {
+			.x = x,
+			.y = y,
+			.text = data.lines[i],
+			.theme = th,
+			.flags = LABEL_NO_HCENTER
+		});
+
+		y += font_height(th->fonts[THEME_FONT_INTERFACE]);
+		y += th->padding;
+	}
+}
+
+void
+trace_hud_clear(void)
+{
+	memset(&data, 0, sizeof (data));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libadventure/adventure/trace_hud.h	Wed Oct 14 10:29:53 2020 +0200
@@ -0,0 +1,76 @@
+/*
+ * trace_hud.h -- on screen hud
+ *
+ * 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_TRACE_HUD_H
+#define MOLKO_TRACE_HUD_H
+
+/**
+ * \file trace_hud.h
+ * \brief On screen hud
+ */
+
+struct theme;
+
+/**
+ * \brief Default time to remove messages.
+ */
+#define TRACE_HUD_TIMEOUT_DEFAULT (3000)
+
+/**
+ * \brief Trace HUD options.
+ */
+struct trace_hud {
+	struct theme *theme;	/*!< (RW, ref, optional) Theme to use. */
+	unsigned int timeout;   /*!< (RW) Timeout to remove messages. */
+};
+
+/**
+ * Global trace HUD options.
+ */
+extern struct trace_hud trace_hud;
+
+/**
+ * Handler to use as \ref trace_handler.
+ *
+ * \pre str != NULL
+ * \param str the line to store
+ */
+void
+trace_hud_handler(const char *str);
+
+/**
+ * Update the HUD.
+ *
+ * \param ticks elapsed milliseconds since last frame.
+ */
+void
+trace_hud_update(unsigned int ticks);
+
+/**
+ * Draw the HUD.
+ */
+void
+trace_hud_draw(void);
+
+/**
+ * Clear the hud.
+ */
+void
+trace_hud_clear(void);
+
+#endif /* !MOLKO_TRACE_HUD_H */
--- a/libcore/CMakeLists.txt	Tue Oct 13 18:39:35 2020 +0200
+++ b/libcore/CMakeLists.txt	Wed Oct 14 10:29:53 2020 +0200
@@ -97,6 +97,8 @@
 	${libcore_SOURCE_DIR}/core/texture_p.h
 	${libcore_SOURCE_DIR}/core/theme.c
 	${libcore_SOURCE_DIR}/core/theme.h
+	${libcore_SOURCE_DIR}/core/trace.c
+	${libcore_SOURCE_DIR}/core/trace.h
 	${libcore_SOURCE_DIR}/core/util.c
 	${libcore_SOURCE_DIR}/core/util.h
 	${libcore_SOURCE_DIR}/core/wait.c
--- a/libcore/core/message.c	Tue Oct 13 18:39:35 2020 +0200
+++ b/libcore/core/message.c	Wed Oct 14 10:29:53 2020 +0200
@@ -32,6 +32,7 @@
 #include "sprite.h"
 #include "texture.h"
 #include "theme.h"
+#include "trace.h"
 #include "util.h"
 
 #define THEME(msg)      (msg->theme ? msg->theme : theme_default())
@@ -115,11 +116,17 @@
 {
 	assert(msg);
 
+	if (msg->flags & (MESSAGE_FLAGS_FADEIN|MESSAGE_FLAGS_FADEOUT))
+		assert(msg->delay > 0);
+
 	msg->elapsed = 0;
 	msg->scale = msg->flags & MESSAGE_FLAGS_FADEIN ? 0.0 : 1.0;
 	msg->state = msg->flags & MESSAGE_FLAGS_FADEIN
 	    ? MESSAGE_STATE_OPENING
 	    : MESSAGE_STATE_SHOWING;
+
+	if (msg->flags & MESSAGE_FLAGS_AUTOMATIC && msg->timeout == 0)
+		trace("message is automatic but has zero timeout");
 }
 
 void
--- a/libcore/core/message.h	Tue Oct 13 18:39:35 2020 +0200
+++ b/libcore/core/message.h	Wed Oct 14 10:29:53 2020 +0200
@@ -131,6 +131,8 @@
  * elapsed time.
  *
  * \pre msg != NULL
+ * \pre msg->delay > 0 if msg->flags contains MESSAGE_FLAGS_FADEIN or
+ *      MESSAGE_FLAGS_FADEOUT
  * \param msg the message
  */
 void
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/trace.c	Wed Oct 14 10:29:53 2020 +0200
@@ -0,0 +1,61 @@
+/*
+ * trace.h -- non-fatal message logs
+ *
+ * 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 <stdio.h>
+
+#include "trace.h"
+
+static void
+default_handler(const char *line)
+{
+	assert(line);
+
+	puts(line);
+}
+
+void (*trace_handler)(const char *) = default_handler;
+
+void
+trace(const char *fmt, ...)
+{
+	assert(fmt);
+
+	va_list ap;
+
+	if (!trace_handler)
+		return;
+
+	va_start(ap, fmt);
+	vtrace(fmt, ap);
+	va_end(ap);
+}
+
+void
+vtrace(const char *fmt, va_list ap)
+{
+	assert(fmt);
+
+	char buf[TRACE_LINE_MAX];
+
+	if (!trace_handler)
+		return;
+
+	vsnprintf(buf, sizeof (buf), fmt, ap);
+	trace_handler(buf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/trace.h	Wed Oct 14 10:29:53 2020 +0200
@@ -0,0 +1,71 @@
+/*
+ * trace.h -- non-fatal message logs
+ *
+ * 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_TRACE_H
+#define MOLKO_TRACE_H
+
+/**
+ * \file trace.h
+ * \brief Non-fatal message logs.
+ *
+ * The purpose of this module is to provide a feedback from the code when there
+ * are non-fatal programming error or unexpected results. In contrast to the
+ * \ref debug.h module this one is always activated no manner if the build
+ * is in Debug or Release.
+ *
+ * For example, having an animation with a delay of 0 is not a technical issue
+ * but is probably not what the use wants. Thus, a trace warning may be
+ * generated in that way.
+ */
+
+#include <stdarg.h>
+
+#include "plat.h"
+
+/**
+ * \brief Maximum length for a trace log.
+ */
+#define TRACE_LINE_MAX (1024)
+
+/**
+ * \brief Global trace handler.
+ *
+ * The default one use a simple printf on the standard output.
+ */
+extern void (*trace_handler)(const char *);
+
+/**
+ * Log some information.
+ *
+ * \pre fmt != NULL
+ * \param fmt the printf(3) format string
+ */
+void
+trace(const char *fmt, ...) PLAT_PRINTF(1, 2);
+
+/**
+ * Similar to \ref trace with a va_list arguments pointer.
+ *
+ * \pre fmt != NULL
+ * \param fmt the printf(3) format string
+ * \param ap the argument list
+ */
+void
+vtrace(const char *fmt, va_list ap) PLAT_PRINTF(1, 0);
+
+#endif /* !MOLKO_TRACE_H */