changeset 79:8f95462ac5f8

core: create a debugging API, closes #2469 @2h
author David Demelier <markand@malikania.fr>
date Sun, 02 Feb 2020 15:48:36 +0100
parents 1bd1233b4cbc
children 05ffbcdee585
files Makefile src/adventure/main.c src/adventure/splashscreen_state.c src/core/debug.c src/core/debug.h src/core/font.c src/core/font.h src/core/map_state.c
diffstat 8 files changed, 274 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Fri Jan 31 13:57:57 2020 +0100
+++ b/Makefile	Sun Feb 02 15:48:36 2020 +0100
@@ -19,7 +19,7 @@
 .POSIX:
 
 CC=             gcc
-CFLAGS=         -MMD -O0 -std=c18 -Wall -Wextra -g
+CFLAGS=         -MMD -O0 -std=c18 -Wall -Wextra -g -Wall -Wextra
 # Use this instead to build a release.
 # CFLAGS=         -MMD -O3 -DNDEBUG -std=c18 -Wall -Wextra
 PROG=           molko
@@ -27,6 +27,7 @@
 
 CORE_SRCS=      src/core/animation.c \
                 src/core/clock.c \
+                src/core/debug.c \
                 src/core/error.c \
                 src/core/event.c \
                 src/core/font.c \
--- a/src/adventure/main.c	Fri Jan 31 13:57:57 2020 +0100
+++ b/src/adventure/main.c	Sun Feb 02 15:48:36 2020 +0100
@@ -23,6 +23,7 @@
 #include "clock.h"
 #include "error.h"
 #include "event.h"
+#include "debug.h"
 #include "font.h"
 #include "game.h"
 #include "image.h"
@@ -74,6 +75,8 @@
 
 	if (!(font = font_openf(sys_datapath("fonts/DejaVuSans.ttf"), 15)))
 		error_fatal();
+	if (!(debug_options.default_font = font_openf(sys_datapath("fonts/DejaVuSans.ttf"), 10)))
+		error_fatal();
 	if (!(frame = image_openf(sys_datapath("images/message.png"))))
 		error_fatal();
 
@@ -91,6 +94,8 @@
 		.flags = MESSAGE_QUESTION
 	};
 
+	debug_options.enable = true;
+
 	clock_start(&clock);
 	script_init(&sc);
 
--- a/src/adventure/splashscreen_state.c	Fri Jan 31 13:57:57 2020 +0100
+++ b/src/adventure/splashscreen_state.c	Sun Feb 02 15:48:36 2020 +0100
@@ -91,7 +91,6 @@
 	painter_set_color(0xffffffff);
 	painter_clear();
 	texture_draw(text, x, y);
-	painter_present();
 }
 
 struct state splashscreen_state = {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/debug.c	Sun Feb 02 15:48:36 2020 +0100
@@ -0,0 +1,71 @@
+/*
+ * debug.c -- debugging interfaces
+ *
+ * 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 "debug.h"
+#include "font.h"
+#include "texture.h"
+
+#define PADDING_X 5
+#define PADDING_Y 5
+
+struct debug_options debug_options = {
+	.default_color = 0x0000ffff,
+	.default_style = FONT_STYLE_ANTIALIASED
+};
+
+void
+debug_printf(struct debug_report *report, const char *fmt, ...)
+{
+	assert(report);
+	assert(fmt);
+
+	va_list ap;
+
+	va_start(ap, fmt);
+	debug_vprintf(report, fmt, ap);
+	va_end(ap);
+}
+
+void
+debug_vprintf(struct debug_report *report, const char *fmt, va_list ap)
+{
+	assert(report);
+	assert(fmt);
+
+	char line[DEBUG_LINE_MAX];
+	struct texture *tex;
+	struct font *font;
+	unsigned int gapy;
+
+	vsnprintf(line, sizeof (line), fmt, ap);
+	font = report->font ? report->font : debug_options.default_font;
+	tex = font_render_ex(font, line, report->color, report->style);
+
+	if (!tex)
+		return;
+
+	gapy = (PADDING_Y * (report->count)) +
+	    (font_height(font) * (report->count));
+	report->count++;
+
+	texture_draw(tex, PADDING_X, gapy);
+	texture_close(tex);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/debug.h	Sun Feb 02 15:48:36 2020 +0100
@@ -0,0 +1,133 @@
+/*
+ * debug.h -- debugging interfaces
+ *
+ * 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_DEBUG_H
+#define MOLKO_DEBUG_H
+
+/**
+ * \file debug.h
+ * \brief Debugging interfaces.
+ *
+ * This module provides functions to draw debugging information within the game
+ * window. It is mostly used for information only when state of the game is
+ * better inspected via direct window information rather than writing in the
+ * console.
+ *
+ * Predefined core states may print debugging information if
+ * debug_options.enabled variable is set to true. However, you need to specify
+ * the font to use in order to work.
+ *
+ * Each call to \ref debug_printf or \ref debug_vprintf automatically adjust
+ * next coordinate for rendering the text. As such, user may simply print
+ * several lines of text without having to deal with that manually.
+ *
+ * Example, activate global debugging.
+ *
+ * \code
+ * struct font *f = font_openf("foo.ttf", 10);
+ *
+ * if (!f)
+ * 	error_fatal();
+ *
+ * debug_options.default_font = f;
+ * debug_options.enabled = true;
+ * \endcode
+ *
+ * Example, print debugging information manually.
+ *
+ * \code
+ * struct debug_report report = {
+ * 	.color = 0x00ff00ff,
+ * 	.font = myfont          // Optional if debug_options.default_font is set.
+ * };
+ *
+ * debug_printf("current position: %d, %d\n", x, y);
+ * \endcode
+ */
+
+#include <stdbool.h>
+#include <stdarg.h>
+
+#include "font.h"
+
+/**
+ * Maximum content length per report.
+ */
+#define DEBUG_LINE_MAX 1024
+
+/**
+ * \brief Debugging options.
+ *
+ * Fill this structure with appropriate values to change debugging behavior
+ * in core API.
+ */
+struct debug_options {
+	struct font *default_font;      /*!< (RW) Default font for reports. */
+	enum font_style default_style;  /*!< (RW) Default font style. */
+	unsigned long default_color;    /*!< (RW) Default font color. */
+	bool enable;                    /*!< (RW) Enable core API debugging. */
+};
+
+/**
+ * \brief Debug context.
+ *
+ * Use this structure each time you need to print one or more messages.
+ */
+struct debug_report {
+	struct font *font;              /*!< (RW) Font to use. */
+	enum font_style style;          /*!< (RW) Font style to use. */
+	unsigned long color;            /*!< (RW) Font foreground color to use. */
+	unsigned int count;             /*!< (PV) Number of messages already printed. */
+};
+
+/**
+ * Global debugging options.
+ */
+extern struct debug_options debug_options;
+
+/**
+ * Convenient macro to initialize \ref debug_report with default values.
+ */
+#define DEBUG_INIT_DEFAULTS {                   \
+        .font = debug_options.default_font,     \
+        .color = debug_options.default_color,   \
+        .style = debug_options.default_style    \
+}
+
+/**
+ * Print debugging information into the screen.
+ *
+ * \pre report != NULL
+ * \pre fmt != NULL
+ * \param report the reporting context
+ * \param fmt the printf(3) format string
+ * \note The message length must not exceed DEBUG_LINE_MAX, otherwise its
+ *       result is truncated.
+ */
+void
+debug_printf(struct debug_report *report, const char *fmt, ...);
+
+/**
+ * Similar to \ref debug_printf but with a va_list object.
+ *
+ * \see \ref debug_printf
+ */
+void
+debug_vprintf(struct debug_report *report, const char *fmt, va_list ap);
+
+#endif /* !MOLKO_DEBUG_H */
--- a/src/core/font.c	Fri Jan 31 13:57:57 2020 +0100
+++ b/src/core/font.c	Sun Feb 02 15:48:36 2020 +0100
@@ -74,6 +74,15 @@
 struct texture *
 font_render(struct font *font, const char *text, unsigned long color)
 {
+	return font_render_ex(font, text, color, FONT_STYLE_ANTIALIASED);
+}
+
+struct texture *
+font_render_ex(struct font *font,
+               const char *text,
+               unsigned long color,
+               enum font_style style)
+{
 	assert(font);
 	assert(text);
 
@@ -83,10 +92,19 @@
 		.b = COLOR_B(color),
 		.a = COLOR_A(color)
 	};
+	SDL_Surface *surface;
+	SDL_Surface *(*func)(TTF_Font *, const char *, SDL_Color);
 
-	SDL_Surface *surface;
+	switch (style) {
+	case FONT_STYLE_ANTIALIASED:
+		func = TTF_RenderUTF8_Blended;
+		break;
+	default:
+		func = TTF_RenderUTF8_Solid;
+		break;
+	}
 
-	if (!(surface = TTF_RenderUTF8_Blended(font->handle, text, fg))) {
+	if (!(surface = func(font->handle, text, fg))) {
 		error_sdl();
 		return NULL;
 	}
@@ -94,6 +112,12 @@
 	return texture_from_surface(surface);
 }
 
+unsigned int
+font_height(const struct font *font)
+{
+	return TTF_FontHeight(font->handle);
+}
+
 void
 font_close(struct font *font)
 {
--- a/src/core/font.h	Fri Jan 31 13:57:57 2020 +0100
+++ b/src/core/font.h	Sun Feb 02 15:48:36 2020 +0100
@@ -37,6 +37,14 @@
 struct texture;
 
 /**
+ * \brief Font style for rendering.
+ */
+enum font_style {
+	FONT_STYLE_NONE,                /*!< No antialiasing. */
+	FONT_STYLE_ANTIALIASED          /*!< Pretty antialiasing looking. */
+};
+
+/**
  * Open font from path file.
  *
  * \pre path != NULL
@@ -61,6 +69,12 @@
 font_openb(const void *buffer, size_t buflen, unsigned int size);
 
 /**
+ * Similar to \ref font_render_ex with predefined convenient values.
+ */
+struct texture *
+font_render(struct font *font, const char *text, unsigned long color);
+
+/**
  * Render a text.
  *
  * \pre font != NULL
@@ -68,9 +82,23 @@
  * \param font the font handle
  * \param text the text in UTF-8
  * \param color the color
+ * \param style the font style
  */
 struct texture *
-font_render(struct font *font, const char *text, unsigned long color);
+font_render_ex(struct font *font,
+               const char *text,
+               unsigned long color,
+               enum font_style style);
+
+/**
+ * Get the maximum height for all glyphs.
+ *
+ * \pre font != NULL
+ * \param font the font handle
+ * \return the height in pixels
+ */
+unsigned int
+font_height(const struct font *font);
 
 /**
  * Close the font.
--- a/src/core/map_state.c	Fri Jan 31 13:57:57 2020 +0100
+++ b/src/core/map_state.c	Sun Feb 02 15:48:36 2020 +0100
@@ -18,6 +18,7 @@
 
 #include <stdio.h>
 
+#include "debug.h"
 #include "event.h"
 #include "game.h"
 #include "map.h"
@@ -319,12 +320,19 @@
 static void
 draw(void)
 {
+	struct debug_report report = DEBUG_INIT_DEFAULTS;
+
 	map_draw(&map_state_data.map.map, map_state_data.view.x, map_state_data.view.y);
 	walksprite_draw(
 		&cache.player.ws,
 		map_state_data.player.angle,
 		map_state_data.player.x - map_state_data.view.x,
 		map_state_data.player.y - map_state_data.view.y);
+
+	debug_printf(&report, "position: %d, %d", map_state_data.player.x,
+	    map_state_data.player.y);
+	debug_printf(&report, "view: %d, %d", map_state_data.view.x,
+	    map_state_data.view.y);
 }
 
 struct map_state_data map_state_data;