# HG changeset patch # User David Demelier # Date 1602664193 -7200 # Node ID 4eeeccf2b732579d80fe2d49138172ac974bffd4 # Parent 453651d76f7c8d2f3f83ed9fa69968ee252d6f6f core: add trace/vtrace functions, closes #2493 diff -r 453651d76f7c -r 4eeeccf2b732 examples/CMakeLists.txt --- 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 +) diff -r 453651d76f7c -r 4eeeccf2b732 examples/example-action.c --- 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." } diff -r 453651d76f7c -r 4eeeccf2b732 examples/example-trace.c --- /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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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(); +} + diff -r 453651d76f7c -r 4eeeccf2b732 libadventure/CMakeLists.txt --- 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( diff -r 453651d76f7c -r 4eeeccf2b732 libadventure/adventure/trace_hud.c --- /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 + * + * 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 +#include +#include + +#include +#include +#include +#include + +#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)); +} diff -r 453651d76f7c -r 4eeeccf2b732 libadventure/adventure/trace_hud.h --- /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 + * + * 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 */ diff -r 453651d76f7c -r 4eeeccf2b732 libcore/CMakeLists.txt --- 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 diff -r 453651d76f7c -r 4eeeccf2b732 libcore/core/message.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 diff -r 453651d76f7c -r 4eeeccf2b732 libcore/core/message.h --- 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 diff -r 453651d76f7c -r 4eeeccf2b732 libcore/core/trace.c --- /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 + * + * 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 +#include + +#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); +} diff -r 453651d76f7c -r 4eeeccf2b732 libcore/core/trace.h --- /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 + * + * 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 + +#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 */