Mercurial > molko
changeset 148:c577c15df07f
misc: split libraries, closes #2496
line wrap: on
line diff
--- a/CMakeLists.txt Thu Oct 15 09:21:04 2020 +0200 +++ b/CMakeLists.txt Thu Oct 15 10:32:18 2020 +0200 @@ -53,6 +53,8 @@ add_subdirectory(tools/map) add_subdirectory(libcore) +add_subdirectory(libui) +add_subdirectory(librpg) add_subdirectory(libadventure) add_subdirectory(molko)
--- a/doxygen/CMakeLists.txt Thu Oct 15 09:21:04 2020 +0200 +++ b/doxygen/CMakeLists.txt Thu Oct 15 10:32:18 2020 +0200 @@ -30,12 +30,16 @@ doxygen/page-examples.c libadventure libcore + libui + librpg ) set( DOXYGEN_STRIP_FROM_PATH ${CMAKE_SOURCE_DIR}/libadventure ${CMAKE_SOURCE_DIR}/libcore + ${CMAKE_SOURCE_DIR}/libui + ${CMAKE_SOURCE_DIR}/librpg ) set(DOXYGEN_ALLOW_UNICODE_NAMES YES)
--- a/examples/CMakeLists.txt Thu Oct 15 09:21:04 2020 +0200 +++ b/examples/CMakeLists.txt Thu Oct 15 10:32:18 2020 +0200 @@ -25,37 +25,37 @@ ASSETS ${examples_SOURCE_DIR}/assets/sprites/chest.png ${examples_SOURCE_DIR}/assets/sprites/people.png - LIBRARIES libcore + LIBRARIES librpg ) molko_define_executable( TARGET example-font SOURCES example-font.c - LIBRARIES libcore + LIBRARIES libui ) molko_define_executable( TARGET example-inventory - SOURCES example-inventory + SOURCES example-inventory.c ASSETS ${examples_SOURCE_DIR}/assets/images/fish.png ${examples_SOURCE_DIR}/assets/images/potion.png ${examples_SOURCE_DIR}/assets/images/sword.png FOLDER examples - LIBRARIES libcore + LIBRARIES librpg ) molko_define_executable( TARGET example-label SOURCES example-label.c - LIBRARIES libcore + LIBRARIES libui ) molko_define_executable( TARGET example-message SOURCES example-message.c FOLDER examples - LIBRARIES libcore + LIBRARIES librpg ) molko_define_executable( @@ -63,15 +63,15 @@ SOURCES example-sound.c FOLDER examples ASSETS - ${examples_SOURCE_DIR}/assets/sounds/vabsounds-romance.ogg - LIBRARIES libcore + ${examples_SOURCE_DIR}/assets/sounds/vabsounds-romance.ogg + LIBRARIES libui ) molko_define_executable( TARGET example-drawable SOURCES example-drawable.c FOLDER examples - LIBRARIES libcore + LIBRARIES libui ASSETS ${examples_SOURCE_DIR}/assets/sprites/explosion.png ) @@ -80,5 +80,5 @@ TARGET example-trace SOURCES example-trace.c FOLDER examples - LIBRARIES libcore libadventure + LIBRARIES libui libadventure )
--- a/examples/example-action.c Thu Oct 15 09:21:04 2020 +0200 +++ b/examples/example-action.c Thu Oct 15 10:32:18 2020 +0200 @@ -23,17 +23,19 @@ #include <core/event.h> #include <core/image.h> #include <core/maths.h> -#include <core/message.h> #include <core/painter.h> #include <core/panic.h> #include <core/script.h> #include <core/sprite.h> #include <core/sys.h> #include <core/texture.h> -#include <core/theme.h> #include <core/util.h> #include <core/window.h> +#include <ui/theme.h> + +#include <rpg/message.h> + #include <assets/sprites/chest.h> #include <assets/sprites/people.h>
--- a/examples/example-drawable.c Thu Oct 15 09:21:04 2020 +0200 +++ b/examples/example-drawable.c Thu Oct 15 10:32:18 2020 +0200 @@ -23,17 +23,18 @@ #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 <ui/label.h> +#include <ui/theme.h> + #include <assets/sprites/explosion.h> #define W 1280
--- a/examples/example-font.c Thu Oct 15 09:21:04 2020 +0200 +++ b/examples/example-font.c Thu Oct 15 10:32:18 2020 +0200 @@ -23,10 +23,11 @@ #include <core/panic.h> #include <core/sys.h> #include <core/texture.h> -#include <core/theme.h> #include <core/util.h> #include <core/window.h> +#include <ui/theme.h> + #define W (1280) #define H (720)
--- a/examples/example-inventory.c Thu Oct 15 09:21:04 2020 +0200 +++ b/examples/example-inventory.c Thu Oct 15 10:32:18 2020 +0200 @@ -19,17 +19,19 @@ #include <core/clock.h> #include <core/event.h> #include <core/image.h> -#include <core/inventory.h> -#include <core/inventory_dialog.h> -#include <core/item.h> #include <core/painter.h> #include <core/panic.h> #include <core/sys.h> #include <core/texture.h> -#include <core/theme.h> #include <core/util.h> #include <core/window.h> +#include <ui/theme.h> + +#include <rpg/item.h> +#include <rpg/inventory.h> +#include <rpg/inventory_dialog.h> + /* https://shikashiassets.itch.io/shikashis-fantasy-icons-pack */ #include <assets/images/fish.h> #include <assets/images/potion.h>
--- a/examples/example-label.c Thu Oct 15 09:21:04 2020 +0200 +++ b/examples/example-label.c Thu Oct 15 10:32:18 2020 +0200 @@ -18,14 +18,15 @@ #include <core/clock.h> #include <core/event.h> -#include <core/label.h> #include <core/painter.h> #include <core/panic.h> #include <core/sys.h> -#include <core/theme.h> #include <core/util.h> #include <core/window.h> +#include <ui/label.h> +#include <ui/theme.h> + #define W (1280) #define H (720)
--- a/examples/example-message.c Thu Oct 15 09:21:04 2020 +0200 +++ b/examples/example-message.c Thu Oct 15 10:32:18 2020 +0200 @@ -20,15 +20,17 @@ #include <core/clock.h> #include <core/event.h> -#include <core/frame.h> -#include <core/message.h> #include <core/painter.h> #include <core/panic.h> #include <core/sys.h> #include <core/util.h> -#include <core/theme.h> #include <core/window.h> +#include <ui/frame.h> +#include <ui/theme.h> + +#include <rpg/message.h> + #define W (1280) #define H (720)
--- a/examples/example-sound.c Thu Oct 15 09:21:04 2020 +0200 +++ b/examples/example-sound.c Thu Oct 15 10:32:18 2020 +0200 @@ -18,15 +18,16 @@ #include <core/clock.h> #include <core/event.h> -#include <core/label.h> #include <core/painter.h> #include <core/panic.h> #include <core/sound.h> #include <core/sys.h> -#include <core/theme.h> #include <core/util.h> #include <core/window.h> +#include <ui/label.h> +#include <ui/theme.h> + /* https://freesound.org/people/VABsounds/sounds/423658 */ #include <assets/sounds/vabsounds-romance.h>
--- a/examples/example-trace.c Thu Oct 15 09:21:04 2020 +0200 +++ b/examples/example-trace.c Thu Oct 15 10:32:18 2020 +0200 @@ -20,12 +20,13 @@ #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 <ui/theme.h> + #include <adventure/trace_hud.h> #define W 1280
--- a/libadventure/CMakeLists.txt Thu Oct 15 09:21:04 2020 +0200 +++ b/libadventure/CMakeLists.txt Thu Oct 15 10:32:18 2020 +0200 @@ -44,7 +44,7 @@ TARGET libadventure SOURCES ${SOURCES} ASSETS ${ASSETS} - LIBRARIES libcore + LIBRARIES libcore libui librpg PUBLIC_INCLUDES $<BUILD_INTERFACE:${libadventure_SOURCE_DIR}> )
--- a/libadventure/adventure/mainmenu_state.c Thu Oct 15 09:21:04 2020 +0200 +++ b/libadventure/adventure/mainmenu_state.c Thu Oct 15 10:32:18 2020 +0200 @@ -24,7 +24,6 @@ #include <core/font.h> #include <core/game.h> #include <core/image.h> -#include <core/map_state.h> #include <core/painter.h> #include <core/panic.h> #include <core/state.h> @@ -37,6 +36,8 @@ #include <adventure/assets/tilesets/world.h> #include <adventure/assets/sprites/john.h> +#include <rpg/map_state.h> + #include "mainmenu_state.h" #include "splashscreen_state.h"
--- a/libadventure/adventure/panic_state.c Thu Oct 15 09:21:04 2020 +0200 +++ b/libadventure/adventure/panic_state.c Thu Oct 15 10:32:18 2020 +0200 @@ -29,7 +29,8 @@ #include <core/texture.h> #include <core/util.h> #include <core/window.h> -#include <core/map_state.h> + +#include <rpg/map_state.h> #include <adventure/assets/fonts/lato.h>
--- a/libadventure/adventure/splashscreen_state.c Thu Oct 15 09:21:04 2020 +0200 +++ b/libadventure/adventure/splashscreen_state.c Thu Oct 15 10:32:18 2020 +0200 @@ -19,8 +19,6 @@ #include <core/font.h> #include <core/game.h> #include <core/image.h> -#include <core/map.h> -#include <core/map_state.h> #include <core/painter.h> #include <core/panic.h> #include <core/state.h> @@ -28,6 +26,9 @@ #include <core/texture.h> #include <core/window.h> +#include <rpg/map.h> +#include <rpg/map_state.h> + #include <adventure/assets/fonts/teutonic.h> #include "splashscreen_state.h"
--- a/libadventure/adventure/trace_hud.c Thu Oct 15 09:21:04 2020 +0200 +++ b/libadventure/adventure/trace_hud.c Thu Oct 15 10:32:18 2020 +0200 @@ -20,10 +20,12 @@ #include <stdio.h> #include <string.h> -#include <core/label.h> #include <core/font.h> -#include <core/theme.h> #include <core/trace.h> +#include <core/window.h> + +#include <ui/label.h> +#include <ui/theme.h> #include "trace_hud.h" @@ -98,7 +100,7 @@ .y = y, .text = data.lines[i], .theme = th, - .flags = LABEL_ALIGN_LEFT + .align = LABEL_ALIGN_TOP_LEFT }); y += font_height(th->fonts[THEME_FONT_INTERFACE]);
--- a/libcore/CMakeLists.txt Thu Oct 15 09:21:04 2020 +0200 +++ b/libcore/CMakeLists.txt Thu Oct 15 10:32:18 2020 +0200 @@ -31,15 +31,9 @@ ${libcore_SOURCE_DIR}/core/action.h ${libcore_SOURCE_DIR}/core/animation.c ${libcore_SOURCE_DIR}/core/animation.h - ${libcore_SOURCE_DIR}/core/button.c - ${libcore_SOURCE_DIR}/core/button.h - ${libcore_SOURCE_DIR}/core/checkbox.c - ${libcore_SOURCE_DIR}/core/checkbox.h ${libcore_SOURCE_DIR}/core/clock.c ${libcore_SOURCE_DIR}/core/clock.h ${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 @@ -49,30 +43,15 @@ ${libcore_SOURCE_DIR}/core/event.h ${libcore_SOURCE_DIR}/core/font.c ${libcore_SOURCE_DIR}/core/font.h - ${libcore_SOURCE_DIR}/core/frame.c - ${libcore_SOURCE_DIR}/core/frame.h ${libcore_SOURCE_DIR}/core/game.c ${libcore_SOURCE_DIR}/core/game.h ${libcore_SOURCE_DIR}/core/image.c ${libcore_SOURCE_DIR}/core/image.h ${libcore_SOURCE_DIR}/core/inhibit.c ${libcore_SOURCE_DIR}/core/inhibit.h - ${libcore_SOURCE_DIR}/core/inventory.c - ${libcore_SOURCE_DIR}/core/inventory.h - ${libcore_SOURCE_DIR}/core/inventory_dialog.c - ${libcore_SOURCE_DIR}/core/inventory_dialog.h - ${libcore_SOURCE_DIR}/core/item.h ${libcore_SOURCE_DIR}/core/key.h - ${libcore_SOURCE_DIR}/core/label.c - ${libcore_SOURCE_DIR}/core/label.h - ${libcore_SOURCE_DIR}/core/map.c - ${libcore_SOURCE_DIR}/core/map.h - ${libcore_SOURCE_DIR}/core/map_state.c - ${libcore_SOURCE_DIR}/core/map_state.h ${libcore_SOURCE_DIR}/core/maths.c ${libcore_SOURCE_DIR}/core/maths.h - ${libcore_SOURCE_DIR}/core/message.c - ${libcore_SOURCE_DIR}/core/message.h ${libcore_SOURCE_DIR}/core/mouse.h ${libcore_SOURCE_DIR}/core/painter.c ${libcore_SOURCE_DIR}/core/painter.h @@ -95,16 +74,12 @@ ${libcore_SOURCE_DIR}/core/texture.c ${libcore_SOURCE_DIR}/core/texture.h ${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 ${libcore_SOURCE_DIR}/core/wait.h - ${libcore_SOURCE_DIR}/core/walksprite.c - ${libcore_SOURCE_DIR}/core/walksprite.h ${libcore_SOURCE_DIR}/core/window.c ${libcore_SOURCE_DIR}/core/window.h ${libcore_SOURCE_DIR}/core/window_p.h
--- a/libcore/core/button.c Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * button.c -- GUI button - * - * 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 "button.h" -#include "event.h" -#include "maths.h" -#include "theme.h" - -static bool -is_boxed(const struct button *button, const struct event_click *click) -{ - assert(button); - assert(click); - assert(click->type == EVENT_CLICKDOWN || click->type == EVENT_CLICKUP); - - return maths_is_boxed(button->x, button->y, button->w, button->h, - click->x, click->y); -} - -void -button_handle(struct button *button, const union event *ev) -{ - assert(button); - assert(ev); - - switch (ev->type) { - case EVENT_CLICKDOWN: - if (is_boxed(button, &ev->click)) - button->state = BUTTON_STATE_PRESSED; - break; - case EVENT_CLICKUP: - /* - * If the button was pressed, indicate that the button is - * finally activated. This let the user to move the cursor - * outside the button to "forget" the press. - */ - if (!is_boxed(button, &ev->click)) - button->state = BUTTON_STATE_NONE; - else if (button->state == BUTTON_STATE_PRESSED) - button->state = BUTTON_STATE_ACTIVATED; - break; - default: - break; - } -} - -void -button_reset(struct button *button) -{ - assert(button); - - button->state = BUTTON_STATE_NONE; -} - -void -button_draw(struct button *button) -{ - assert(button); - - theme_draw_button(button->theme, button); -}
--- a/libcore/core/button.h Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * button.h -- GUI button - * - * 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_BUTTON_H -#define MOLKO_BUTTON_H - -/** - * \file button.h - * \brief GUI button. - */ - -union event; - -struct theme; - -/** - * \brief Button state. - */ -enum button_state { - BUTTON_STATE_NONE, /*!< Button is inactive. */ - BUTTON_STATE_PRESSED, /*!< Button is currently pressed. */ - BUTTON_STATE_ACTIVATED /*!< Button is considered activated. */ -}; - -/** - * \brief GUI button. - */ -struct button { - int x; /*!< (+) Position in x. */ - int y; /*!< (+) Position in y. */ - unsigned int w; /*!< (+) Width. */ - unsigned int h; /*!< (+) Height. */ - const char *text; /*!< (+&) Text to draw. */ - enum button_state state; /*!< (+) Button state. */ - struct theme *theme; /*!< (+&?) Theme to use. */ -}; - -/** - * Handle the event. - * - * You should always call this function even if the event is completely - * unrelated. - * - * \pre button != NULL - * \pre ev != NULL - * \param button the button - * \param ev the event - */ -void -button_handle(struct button *button, const union event *ev); - -/** - * Use this function once the button has been considered activated. - * - * \pre button != NULL - * \param button the button - */ -void -button_reset(struct button *button); - -/** - * Draw the button. - * - * \pre button != NULL - * \param button the button - */ -void -button_draw(struct button *button); - -#endif /* !MOLKO_BUTTON_H */
--- a/libcore/core/checkbox.c Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * checkbox.c -- GUI checkbox - * - * 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 "checkbox.h" -#include "theme.h" -#include "event.h" -#include "maths.h" - -static bool -is_boxed(const struct checkbox *cb, const struct event_click *click) -{ - assert(cb); - assert(click && click->type == EVENT_CLICKDOWN); - - return maths_is_boxed(cb->x, cb->y, cb->w, cb->h, click->x, click->y); -} - -void -checkbox_handle(struct checkbox *cb, const union event *ev) -{ - assert(cb); - assert(ev); - - switch (ev->type) { - case EVENT_CLICKDOWN: - if (is_boxed(cb, &ev->click)) - cb->checked = !cb->checked; - break; - default: - break; - } -} - -void -checkbox_draw(const struct checkbox *cb) -{ - theme_draw_checkbox(cb->theme, cb); -}
--- a/libcore/core/checkbox.h Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * checkbox.h -- GUI checkbox - * - * 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_CHECKBOX_H -#define MOLKO_CHECKBOX_H - -/** - * \file checkbox.h - * \brief GUI checkbox. - */ - -#include <stdbool.h> - -union event; - -/** - * \brief GUI checkbox. - */ -struct checkbox { - int x; /*!< (+) Position in x. */ - int y; /*!< (+) Position in y. */ - unsigned int w; /*!< (+) Width. */ - unsigned int h; /*!< (+) Height. */ - const char *label; /*!< (+&) Text to show. */ - bool checked; /*!< (+) Is activated? */ - struct theme *theme; /*!< (+&?) Theme to use. */ -}; - -/** - * Draw the checkbox. - * - * \pre cb != NULL - * \pre ev != NULL - * \param cb the checkbox - * \param ev the event - */ -void -checkbox_handle(struct checkbox *cb, const union event *ev); - -/** - * Draw the checkbox. - * - * \pre cb != NULL - * \param cb the checkbox - */ -void -checkbox_draw(const struct checkbox *cb); - -#endif /* !MOLKO_CHECKBOX_H */
--- a/libcore/core/debug.c Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * 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" -#include "theme.h" - -#define PADDING_X 5 -#define PADDING_Y 5 - -struct debug_options debug_options = { -#if !defined(NDEBUG) - .enable = true -#endif -}; - -void -debug_printf(struct debug_report *report, const char *fmt, ...) -{ - assert(report); - assert(fmt); - - if (!debug_options.enable) - return; - - 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); - - if (!debug_options.enable) - return; - - char line[DEBUG_LINE_MAX]; - struct theme *theme; - struct font *font; - struct texture tex; - unsigned int gapy; - - vsnprintf(line, sizeof (line), fmt, ap); - - theme = report->theme ? report->theme : theme_default(); - font = theme->fonts[THEME_FONT_DEBUG]; - font->color = report->color; - - if (!font_render(font, &tex, line)) - return; - - gapy = (PADDING_Y * (report->count)) + - (font_height(font) * (report->count)); - report->count++; - - texture_draw(&tex, PADDING_X, gapy); - texture_finish(&tex); -}
--- a/libcore/core/debug.h Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/* - * 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 - -struct theme; - -/** - * \brief Debugging options. - * - * Fill this structure with appropriate values to change debugging behavior - * in core API. - */ -struct debug_options { - bool enable; /*!< (+) Enable core API debugging. */ -}; - -/** - * \brief Debug context. - * - * Use this structure each time you need to print one or more messages. - */ -struct debug_report { - struct theme *theme; /*!< (+&?) Theme to use. */ - unsigned long color; /*!< (+) Font foreground color to use. */ - unsigned int count; /*!< (-) 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/libcore/core/frame.c Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * frame.h -- GUI frame - * - * 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 "frame.h" -#include "theme.h" - -void -frame_draw(const struct frame *frame) -{ - assert(frame); - - theme_draw_frame(frame->theme, frame); -}
--- a/libcore/core/frame.h Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * frame.h -- GUI frame - * - * 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_FRAME_H -#define MOLKO_FRAME_H - -/** - * \file frame.h - * \brief GUI frame. - */ - -struct theme; - -/** - * \brief Frame style. - */ -enum frame_style { - FRAME_STYLE_NORMAL, - FRAME_STYLE_BOX -}; - -/** - * \brief GUI frame. - */ -struct frame { - int x; /*!< (+) Position in x. */ - int y; /*!< (+) Position in y. */ - unsigned int w; /*!< (+) Width. */ - unsigned int h; /*!< (+) Height. */ - enum frame_style style; /*!< (+) Frame style. */ - struct theme *theme; /*!< (+&?) Theme to use. */ -}; - -/** - * Draw the frame. - * - * \pre frame != NULL - * \param frame the frame to draw - */ -void -frame_draw(const struct frame *frame); - -#endif /* !MOLKO_FRAME_H */
--- a/libcore/core/inventory.c Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,210 +0,0 @@ -/* - * inventory.c -- inventory of items - * - * 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 "inventory.h" -#include "item.h" - -#define INVENTORY_TOTAL (INVENTORY_ROWS_MAX * INVENTORY_COLS_MAX) - -static bool -can_be_used(struct inventory_slot *slot, const struct item *item) -{ - assert(item); - - /* Empty slot. */ - if (!slot->item) - return false; - - /* Not same object. */ - if (strcmp(slot->item->name, item->name) != 0) - return false; - - /* No space in this slot. */ - if (slot->amount >= slot->item->stackable) - return false; - - return true; -} - -static struct inventory_slot * -find(struct inventory *iv, const struct item *item) -{ - assert(iv); - assert(item); - - /* First pass: find an entry with the same item. */ - for (unsigned int r = 0; r < INVENTORY_ROWS_MAX; ++r) - for (unsigned int c = 0; c < INVENTORY_COLS_MAX; ++c) - if (can_be_used(&iv->items[r][c], item)) - return &iv->items[r][c]; - - /* Second pass: try to find an empty slot. */ - for (unsigned int r = 0; r < INVENTORY_ROWS_MAX; ++r) - for (unsigned int c = 0; c < INVENTORY_COLS_MAX; ++c) - if (!iv->items[r][c].item) - return &iv->items[r][c]; - - return NULL; -} - -static unsigned -provide(struct inventory_slot *slot, struct item *item, unsigned int amount) -{ - assert(slot); - - unsigned int avail; - - /* The slot may be empty, make sure it contains this item. */ - slot->item = item; - - /* - * Example: - * - * The slot has already 10 items. - * The slot item is stackble up to 64 items. - * - * When pushing: - * - * 80: 54 pushed, 26 left - * 30: 30 pushed, 0 left. - */ - avail = slot->item->stackable - slot->amount; - - if (amount > avail) { - slot->amount += avail; - amount -= avail; - } else { - slot->amount += amount; - amount = 0; - } - - return amount; -} - -static bool -merge(struct inventory_slot *slot, struct inventory_slot *other) -{ - assert(slot); - assert(slot->item); - assert(other); - - /* Not compatible, return false to let the sorting continue. */ - if (slot->item != other->item) - return false; - - while (slot->amount < slot->item->stackable && other->amount) { - slot->amount++; - other->amount--; - } - - /* No more amount in the other slot, empty it. */ - if (other->amount == 0U) - memset(other, 0, sizeof (*other)); - - return slot->amount >= slot->item->stackable; -} - -static void -sort(struct inventory *iv, struct inventory_slot *slot, int r, int c) -{ - assert(slot); - assert(slot->item); - - /* Merge until the end of thiw row. */ - for (c = c + 1; c < INVENTORY_COLS_MAX; ++c) - if (merge(slot, &iv->items[r][c])) - return; - - /* Merge the next rows. */ - for (r = r + 1; r < INVENTORY_ROWS_MAX; ++r) - for (c = 0; c < INVENTORY_COLS_MAX; ++c) - if (merge(slot, &iv->items[r][c])) - return; -} - -unsigned int -inventory_push(struct inventory *iv, struct item *item, unsigned int amount) -{ - assert(iv); - assert(item); - - while (amount) { - struct inventory_slot *slot; - - if (!(slot = find(iv, item))) - break; - - /* Add as much as we can in this slot. */ - amount = provide(slot, item, amount); - } - - return amount; -} - -static int -compare_slot(const void *v1, const void *v2) -{ - const struct inventory_slot *slot1 = v1; - const struct inventory_slot *slot2 = v2; - int cmp; - - /* Two null slots compare equal. */ - if (!slot1->item && !slot2->item) - return 0; - - /* Null left should be moved after. */ - if (!slot1->item) - return 1; - - /* Null right slots should be moved after. */ - if (!slot2->item) - return -1; - - /* If they are identical, use amount to sort. */ - if ((cmp = strcmp(slot1->item->name, slot2->item->name)) == 0) - return (long long int)slot2->amount - (long long int)slot1->amount; - - return cmp; -} - -void -inventory_sort(struct inventory *iv) -{ - assert(iv); - - for (int r = 0; r < INVENTORY_ROWS_MAX; ++r) - for (int c = 0; c < INVENTORY_COLS_MAX; ++c) - if (iv->items[r][c].item) - sort(iv, &iv->items[r][c], r, c); - - /* Sort by names AND by amount. */ - qsort(iv->items, INVENTORY_TOTAL, sizeof (struct inventory_slot), compare_slot); -} - -void -inventory_clear(struct inventory *iv) -{ - assert(iv); - - memset(iv, 0, sizeof (*iv)); -}
--- a/libcore/core/inventory.h Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* - * inventory.h -- inventory of items - * - * 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_INVENTORY_H -#define MOLKO_INVENTORY_H - -/** - * \file inventory.h - * \brief Inventory of items. - */ - -/** - * \brief Maximum number of rows. - */ -#define INVENTORY_ROWS_MAX 3 - -/** - * \brief Maximum number of columns. - */ -#define INVENTORY_COLS_MAX 10 - -struct item; - -/** - * \brief Inventory slot. - * - * This structure describe a 'cell' into the inventory. It references a item - * and has a given amount of it. - */ -struct inventory_slot { - struct item *item; /*!< (+&?) Pointer to the item. */ - unsigned int amount; /*!< (-) Number of items in this slot. */ -}; - -/** - * \brief Inventory structure. - */ -struct inventory { - /** - * (-) Grid of objects. - */ - struct inventory_slot items[INVENTORY_ROWS_MAX][INVENTORY_COLS_MAX]; -}; - -/** - * Try to push as much as possible the given item. - * - * \pre iv != NULL - * \pre item != NULL - * \param iv the inventory - * \param item the item to reference - * \param amount the desired amount - * \return 0 if all items were pushed or the number left otherwise - */ -unsigned int -inventory_push(struct inventory *iv, struct item *item, unsigned int amount); - -/** - * Sort the inventory. - * - * \pre iv != NULL - * \pre item != NULL - * \param iv the inventory - */ -void -inventory_sort(struct inventory *iv); - -/** - * Clears the inventory. - * - * \pre iv != NULL - * \param iv the inventory - */ -void -inventory_clear(struct inventory *iv); - -#endif /* !MOLKO_INVENTORY_H */
--- a/libcore/core/inventory_dialog.c Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,324 +0,0 @@ -/* - * inventory_dialog.h -- dialog for items - * - * 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 "button.h" -#include "event.h" -#include "frame.h" -#include "game.h" -#include "inventory.h" -#include "inventory_dialog.h" -#include "item.h" -#include "maths.h" -#include "painter.h" -#include "texture.h" -#include "window.h" - -#define ITEM_SIZE 64 -#define ITEM_PADDING 32 - -#define GRID_WIDTH ((INVENTORY_COLS_MAX * ITEM_SIZE) + \ - ((INVENTORY_COLS_MAX + 1) * ITEM_PADDING)) -#define GRID_HEIGHT ((INVENTORY_ROWS_MAX * ITEM_SIZE) + \ - ((INVENTORY_ROWS_MAX + 1) * ITEM_PADDING)) - -#define LABEL_WIDTH (GRID_WIDTH) -#define LABEL_HEIGHT (64) - -#define BUTTON_HEIGHT (32) -#define BUTTON_WIDTH ((GRID_WIDTH) / 4) - -/* - * The frame looks like this: - * - * +----------------------------+ - * | [] [] [] [] [] [] [] [] [] | - * | [] [] [] [] [] [] [] [] [] | - * | [] [] [] [] [] [] [] [] [] | - * +----------------------------+ - * | Item name | - * | Item description | - * +----------------------------+ - * [ Sort ] - * - * Where space between cells is determined with ITEM_PADDING macro. - */ - -static unsigned int -total_width(void) -{ - return GRID_WIDTH; -} - -static unsigned int -total_height(void) -{ - return GRID_HEIGHT + LABEL_HEIGHT + BUTTON_HEIGHT; -} - -static void -compute_box_position(const struct inventory_dialog *dlg, int r, int c, int *x, int *y) -{ - assert(dlg); - assert(x); - assert(y); - - *x = dlg->fgrid.x + ((c * ITEM_SIZE) + ((c + 1) * ITEM_PADDING)); - *y = dlg->fgrid.y + ((r * ITEM_SIZE) + ((r + 1) * ITEM_PADDING)); -} - -static void -draw_grid_item_frame(int x, int y) -{ - struct frame frame = { - .x = x, - .y = y, - .w = ITEM_SIZE, - .h = ITEM_SIZE, - .style = FRAME_STYLE_BOX - }; - - frame_draw(&frame); -} - -static void -draw_grid_item_icon(struct item *item, int x, int y) -{ - struct texture *icon = item->icon; - - texture_scale(icon, 0, 0, icon->w, icon->h, x, y, ITEM_SIZE, ITEM_SIZE, 0.0); -} - -static void -draw_grid_item_amount(struct inventory_slot *slot, int x, int y) -{ - char nstr[16]; - struct label label = { - .text = nstr, - .x = x, - .y = y - }; - - /* Draw the number of item in this slot. */ - snprintf(nstr, sizeof (nstr), "%d", slot->amount); - label_draw(&label); -} - -static void -draw_grid_item(struct inventory_slot *slot, int x, int y, bool selected) -{ - draw_grid_item_frame(x, y); - - if (slot->item) { - draw_grid_item_icon(slot->item, x, y); - draw_grid_item_amount(slot, x, y); - } - - if (selected) { - x -= 16; - y += (ITEM_SIZE / 2) - 4; - painter_draw_circle(x, y, 8); - } -} - -static void -draw_grid_items(const struct inventory_dialog *dlg) -{ - int x, y; - bool selected; - - for (unsigned int r = 0; r < INVENTORY_ROWS_MAX; ++r) { - for (unsigned int c = 0; c < INVENTORY_COLS_MAX; ++c) { - selected = r == dlg->selrow && c == dlg->selcol; - compute_box_position(dlg, r, c, &x, &y); - draw_grid_item(&dlg->inv->items[r][c], x, y, selected); - } - } -} - -static void -draw_label(struct inventory_dialog *dlg) -{ - assert(dlg); - - struct item *item = dlg->inv->items[dlg->selrow][dlg->selcol].item; - - frame_draw(&dlg->fname); - frame_draw(&dlg->fdesc); - - if (item) { - dlg->lname.text = item->name; - dlg->ldesc.text = item->summary; - label_draw(&dlg->lname); - label_draw(&dlg->ldesc); - } -} - -void -inventory_dialog_open(struct inventory_dialog *dlg) -{ - assert(dlg); - assert(dlg->inv); - - int tw, th; - - dlg->state = INVENTORY_DIALOG_SHOWING; - - tw = total_width(); - th = total_height(); - - /* Grid frame position. */ - dlg->fgrid.w = GRID_WIDTH; - dlg->fgrid.h = GRID_HEIGHT; - dlg->fgrid.x = dlg->x; - dlg->fgrid.y = dlg->y; - - /* Name label. */ - dlg->fname.w = dlg->lname.w = LABEL_WIDTH; - dlg->fname.h = dlg->lname.h = LABEL_HEIGHT / 2; - dlg->fname.x = dlg->lname.x = dlg->x; - dlg->fname.y = dlg->lname.y = dlg->y + GRID_HEIGHT; - dlg->lname.x += ITEM_PADDING; - dlg->lname.align = LABEL_ALIGN_LEFT; - - /* Description label. */ - dlg->fdesc.w = dlg->ldesc.w = LABEL_WIDTH; - dlg->fdesc.h = dlg->ldesc.h = LABEL_HEIGHT / 2; - dlg->fdesc.x = dlg->ldesc.x = dlg->y; - dlg->fdesc.y = dlg->ldesc.y = dlg->y + GRID_HEIGHT + (LABEL_HEIGHT / 2); - dlg->ldesc.x += ITEM_PADDING; - dlg->ldesc.align = LABEL_ALIGN_LEFT; - - /* Button sort. */ - dlg->bsort.x = dlg->x; - dlg->bsort.y = dlg->y + GRID_HEIGHT + LABEL_HEIGHT; - dlg->bsort.w = BUTTON_WIDTH; - dlg->bsort.h = BUTTON_HEIGHT; - dlg->bsort.text = "Sort"; -} - -static void -handle_keydown(struct inventory_dialog *dlg, const struct event_key *ev) -{ - assert(ev && ev->type == EVENT_KEYDOWN); - - switch (ev->key) { - case KEY_LEFT: - if (dlg->selcol == 0) - dlg->selcol = INVENTORY_COLS_MAX - 1; - else - dlg->selcol--; - break; - case KEY_RIGHT: - dlg->selcol = (dlg->selcol + 1) % INVENTORY_COLS_MAX; - break; - case KEY_UP: - if (dlg->selrow == 0) - dlg->selrow = INVENTORY_ROWS_MAX - 1; - else - dlg->selrow--; - break; - case KEY_DOWN: - dlg->selrow = (dlg->selrow + 1) % INVENTORY_ROWS_MAX; - break; - default: - break; - } -} - -static void -handle_clickdown(struct inventory_dialog *dlg, const struct event_click *ev) -{ - assert(dlg); - assert(ev && ev->type == EVENT_CLICKDOWN); - - int x, y; - - for (int r = 0; r < INVENTORY_ROWS_MAX; ++r) { - for (int c = 0; c < INVENTORY_COLS_MAX; ++c) { - compute_box_position(dlg, r, c, &x, &y); - - if (maths_is_boxed(x, y, ITEM_SIZE, ITEM_SIZE, ev->x, ev->y)) { - dlg->selrow = r; - dlg->selcol = c; - } - } - } -} - -void -inventory_dialog_handle(struct inventory_dialog *dlg, const union event *event) -{ - assert(event); - - switch (event->type) { - case EVENT_KEYDOWN: - handle_keydown(dlg, &event->key); - break; - case EVENT_CLICKDOWN: - handle_clickdown(dlg, &event->click); - break; - default: - break; - } - - button_handle(&dlg->bsort, event); - - if (dlg->bsort.state == BUTTON_STATE_ACTIVATED) { - inventory_sort(dlg->inv); - button_reset(&dlg->bsort); - } -} - -void -inventory_dialog_update(struct inventory_dialog *dlg, unsigned int ticks) -{ - assert(dlg); - - (void)ticks; -} - -void -inventory_dialog_move(struct inventory_dialog *dlg, int x, int y) -{ - assert(dlg); - - dlg->x = x; - dlg->y = y; -} - -void -inventory_dialog_draw(struct inventory_dialog *dlg) -{ - assert(dlg); - - frame_draw(&dlg->fgrid); - draw_grid_items(dlg); - draw_label(dlg); - button_draw(&dlg->bsort); -} - -void -inventory_dialog_finish(struct inventory_dialog *dlg) -{ - assert(dlg); - - dlg->state = INVENTORY_DIALOG_NONE; -}
--- a/libcore/core/inventory_dialog.h Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * inventory_dialog.h -- dialog for items - * - * 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 INVENTORY_DIALOG_H -#define INVENTORY_DIALOG_H - -#include "button.h" -#include "label.h" -#include "frame.h" - -union event; - -struct inventory; -struct theme; - -/** - * \brief Inventory dialog state. - */ -enum inventory_dialog_state { - INVENTORY_DIALOG_NONE, - INVENTORY_DIALOG_SHOWING -}; - -/** - * \brief Inventory dialog. - */ -struct inventory_dialog { - int x; /*!< (+) Position in x. */ - int y; /*!< (+) Position in y. */ - struct inventory *inv; /*!< (+&) Inventory to use. */ - struct theme *theme; /*!< (+&?) Theme to use. */ - struct button bsort; /*!< (-) Button sort. */ - struct frame fgrid; /*!< (-) Grid frame. */ - struct frame fname; /*!< (-) Frame for name. */ - struct frame fdesc; /*!< (-) Frame for description. */ - struct label lname; /*!< (-) Label for name. */ - struct label ldesc; /*!< (-) Label for description. */ - enum inventory_dialog_state state; /*!< (-) Current dialog state. */ - unsigned int selrow; /*!< (-) Current selected row. */ - unsigned int selcol; /*!< (-) Current selected column. */ -}; - -void -inventory_dialog_open(struct inventory_dialog *dlg); - -void -inventory_dialog_handle(struct inventory_dialog *dlg, const union event *event); - -void -inventory_dialog_update(struct inventory_dialog *dlg, unsigned int ticks); - -void -inventory_dialog_move(struct inventory_dialog *dlg, int x, int y); - -void -inventory_dialog_draw(struct inventory_dialog *dlg); - -void -inventory_dialog_finish(struct inventory_dialog *dlg); - -#endif /* !INVENTORY_DIALOG_H */
--- a/libcore/core/item.h Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * item.h -- inventory items - * - * 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_ITEM_H -#define MOLKO_ITEM_H - -/** - * \file item.h - * \brief Inventory items. - */ - -#include <stdbool.h> - -/** - * \brief Maximum count of an item into a stack. - */ -#define ITEM_STACK_MAX 64 - -struct character; -struct texture; - -/** - * \brief Inventory items. - */ -struct item { - const char *name; /*!< (+) Name of item. */ - const char *summary; /*!< (+) Summary description. */ - struct texture *icon; /*!< (+&) Icon to show. */ - unsigned int stackable; /*!< (+) Stack count allowed. */ - - /** - * (+) Execute the action for this character. - */ - void (*exec)(const struct item *, struct character *); - - /** - * (+?) Tells if the item can be used in this context. - */ - bool (*allowed)(const struct item *, const struct character *); -}; - -#endif /* !MOLKO_ITEM_H */
--- a/libcore/core/label.c Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * label.c -- GUI label - * - * 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 "label.h" -#include "theme.h" -#include "trace.h" - -void -label_draw(const struct label *label) -{ - assert(label); - assert(label->text); - - if (label->w == 0 || label->h == 0) - trace("label %p has null dimensions", label); - - theme_draw_label(label->theme, label); -}
--- a/libcore/core/label.h Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * label.h -- GUI label - * - * 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_LABEL_H -#define MOLKO_LABEL_H - -/** - * \file label.h - * \brief GUI label. - */ - -struct theme; - -/** - * \brief Label flags. - */ -enum label_flags { - LABEL_FLAGS_NONE, /*!< No flags. */ - LABEL_FLAGS_SHADOW = (1 << 0), /*!< Enable shadow. */ -}; - -/** - * \brief Label alignment in bounding box. - * - * The alignment is described as following: - * - * ``` - * +---------------------+ - * | 1 2 3 | - * | | - * | 8 0 4 | - * | | - * | 7 6 5 | - * +---------------------+ - * ``` - */ -enum label_align { - LABEL_ALIGN_CENTER, /*!< Align to the center (default). */ - LABEL_ALIGN_TOP_LEFT, /*!< Top left. */ - LABEL_ALIGN_TOP, /*!< Top center (aligned horizontally). */ - LABEL_ALIGN_TOP_RIGHT, /*!< Top right. */ - LABEL_ALIGN_RIGHT, /*!< Right (aligned vertically). */ - LABEL_ALIGN_BOTTOM_RIGHT, /*!< Bottom right. */ - LABEL_ALIGN_BOTTOM, /*!< Bottom (aligned horizontally). */ - LABEL_ALIGN_BOTTOM_LEFT, /*!< Bottom left. */ - LABEL_ALIGN_LEFT /*!< Left (aligned vertically). */ -}; - -/** - * \brief GUI label. - */ -struct label { - int x; /*!< (+) Position in x. */ - int y; /*!< (+) Position in y. */ - unsigned int w; /*!< (+) Width. */ - unsigned int h; /*!< (+) Height. */ - const char *text; /*!< (+&) Text to show. */ - enum label_flags flags; /*!< (+) Optional flags. */ - enum label_align align; /*!< (+) How to positionate label. */ - struct theme *theme; /*!< (+&?) Theme to use. */ -}; - -/** - * Draw the label. - * - * \pre label != NULL - * \param label the label to draw - */ -void -label_draw(const struct label *label); - -#endif /* !MOLKO_LABEL_H */
--- a/libcore/core/map.c Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,237 +0,0 @@ -/* - * map.c -- game map - * - * 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 <stdlib.h> -#include <string.h> - -#include "error.h" -#include "error_p.h" -#include "image.h" -#include "map.h" -#include "painter.h" -#include "rbuf.h" -#include "sprite.h" -#include "sys.h" -#include "texture.h" -#include "window.h" - -/* Create %<v>c string literal for scanf */ -#define MAX_F(v) MAX_F_(v) -#define MAX_F_(v) "%" #v "c" - -static void -parse_layer(struct map_data *data, const char *line, FILE *fp) -{ - char layer_name[32 + 1] = { 0 }; - struct map_layer *layer; - size_t amount, current; - - /* Determine layer. */ - if (sscanf(line, "layer|%32s", layer_name) <= 0) - return; - if (strcmp(layer_name, "background") == 0) - layer = &data->layers[0]; - else if (strcmp(layer_name, "foreground") == 0) - layer = &data->layers[1]; - else - return; - - /* Check if weight/height has been specified. */ - if (data->w == 0 || data->h == 0) - return; - - amount = data->w * data->h; - current = 0; - - if (!(layer->tiles = calloc(amount, sizeof (unsigned short)))) - return; - - for (int tile; fscanf(fp, "%d", &tile) && current < amount; ++current) - layer->tiles[current] = tile; -} - -static void -parse(struct map_data *data, const char *line, FILE *fp) -{ - if (strncmp(line, "title", 5) == 0) - sscanf(line, "title|" MAX_F(MAP_TITLE_MAX), data->title); - else if (strncmp(line, "width", 5) == 0) - sscanf(line, "width|%u", &data->w); - else if (strncmp(line, "height", 6) == 0) - sscanf(line, "height|%u", &data->h); - else if (strncmp(line, "tilewidth", 9) == 0) - sscanf(line, "tilewidth|%hu", &data->tile_w); - else if (strncmp(line, "tileheight", 10) == 0) - sscanf(line, "tileheight|%hu", &data->tile_h); - else if (strncmp(line, "origin", 6) == 0) - sscanf(line, "origin|%d|%d", &data->origin_x, &data->origin_y); - else if (strncmp(line, "tileset", 7) == 0) - sscanf(line, "tileset|" MAX_F(MAP_TILESET_MAX), data->tileset); - else if (strncmp(line, "layer", 5) == 0) - parse_layer(data, line, fp); -} - -static bool -check(struct map_data *data) -{ - if (strlen(data->title) == 0) - return error_printf("data has no title"); - if (data->w == 0 || data->h == 0) - return error_printf("data has null sizes"); - if (data->tile_w == 0 || data->tile_h == 0) - return error_printf("data has null tile sizes"); - if (!data->layers[0].tiles || !data->layers[1].tiles) - return error_printf("could not allocate data"); - - return true; -} - -static void -draw_layer(struct map *map, const struct map_layer *layer) -{ - assert(map); - assert(layer); - - struct sprite sprite; - int x = 0, y = 0; - - sprite_init(&sprite, map->tileset, map->data->tile_w, map->data->tile_h); - - for (unsigned int r = 0; r < map->data->w; ++r) { - for (unsigned int c = 0; c < map->data->h; ++c) { - unsigned int si = r * map->data->w + c; - unsigned int sr = (layer->tiles[si] - 1) / sprite.ncols; - unsigned int sc = (layer->tiles[si] - 1) % sprite.nrows; - - if (layer->tiles[si] != 0) - sprite_draw(&sprite, sr, sc, x, y); - - x += map->data->tile_w; - } - - x = 0; - y += map->data->tile_h; - } -} - -bool -map_data_open_fp(struct map_data *data, FILE *fp) -{ - assert(data); - - char line[1024]; - - if (!fp) - return false; - - memset(data, 0, sizeof (*data)); - - while (fgets(line, sizeof (line), fp)) { - /* Remove \n if any */ - line[strcspn(line, "\n")] = '\0'; - parse(data, line, fp); - } - - fclose(fp); - - if (!check(data)) { - map_data_finish(data); - return false; - } - - /* Compute real size. */ - data->real_w = data->w * data->tile_w; - data->real_h = data->h * data->tile_h; - - return true; -} - -bool -map_data_open(struct map_data *data, const char *path) -{ - assert(data); - assert(path); - - return map_data_open_fp(data, fopen(path, "r")); -} - -bool -map_data_openmem(struct map_data *data, const void *buf, size_t bufsz) -{ - assert(data); - assert(buf); - - return map_data_open_fp(data, fmemopen((void *)buf, bufsz, "r")); -} - -void -map_data_finish(struct map_data *data) -{ - assert(data); - - free(data->layers[0].tiles); - free(data->layers[1].tiles); - - memset(data, 0, sizeof (*data)); -} - -bool -map_init(struct map *map, struct map_data *data, struct texture *tileset) -{ - assert(map); - assert(data); - assert(tileset && texture_ok(tileset)); - - if (!(texture_new(&map->picture, data->real_w, data->real_h))) - return false; - - map->data = data; - map->tileset = tileset; - - map_repaint(map); - - return true; -} - -void -map_draw(struct map *map, int srcx, int srcy) -{ - texture_scale(&map->picture, srcx, srcy, window.w, window.h, - 0, 0, window.w, window.h, 0.0); -} - -void -map_repaint(struct map *map) -{ - PAINTER_BEGIN(&map->picture); - draw_layer(map, &map->data->layers[0]); - draw_layer(map, &map->data->layers[1]); - PAINTER_END(); -} - -void -map_finish(struct map *map) -{ - assert(map); - - texture_finish(&map->picture); - - memset(map, 0, sizeof (*map)); -}
--- a/libcore/core/map.h Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -/* - * map.h -- game map - * - * 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_MAP_H -#define MOLKO_MAP_H - -/** - * \file map.h - * \brief Game map. - */ - -#include <stdbool.h> -#include <stdio.h> - -#include "texture.h" - -/** - * \brief Max title length for a map. - */ -#define MAP_TITLE_MAX 32 - -/** - * \brief Max filename for tilesets. - */ -#define MAP_TILESET_MAX FILENAME_MAX - -/** - * \brief Map layer. - */ -struct map_layer { - unsigned short *tiles; /*!< (+) Array of tiles, depending on the map size. */ -}; - -/** - * \brief Map definition structure. - * - * This structure only defines the map characteristics. It does not have any - * logic and is left for game state. - */ -struct map_data { - char title[MAP_TITLE_MAX]; /*!< (+) The map title. */ - char tileset[MAP_TILESET_MAX]; /*!< (+) Name of tileset to use. */ - int origin_x; /*!< (+) Where the player starts in X. */ - int origin_y; /*!< (+) Where the player starts in Y. */ - unsigned int real_w; /*!< (-) Real width in pixels. */ - unsigned int real_h; /*!< (-) Real height in pixels. */ - unsigned int w; /*!< (-) Map width in cells. */ - unsigned int h; /*!< (-) Map height in cells. */ - unsigned short tile_w; /*!< (-) Pixels per cell (width). */ - unsigned short tile_h; /*!< (-) Pixels per cell (height). */ - struct map_layer layers[2]; /*!< (+) Layers (background, foreground). */ -}; - -/** - * \brief High level map object. - * - * This structure reference a map and perform drawing operations. - */ -struct map { - struct map_data *data; /*!< (+&) Map data. */ - struct texture *tileset; /*!< (+&) Tileset to use. */ - struct texture picture; /*!< (-) Map drawn into a picture. */ -}; - -/** - * Open a map defintion. - * - * \pre data != NULL - * \pre path != NULL - * \param data the map defintion to fill - * \param path the path to the map - * \return True if successfully loaded. - */ -bool -map_data_open(struct map_data *data, const char *path); - -/** - * Open map data definition from memory. - * - *\pre data != NULL - *\pre buf != NULL - *\param data the map definition to fill - *\param buf the source buffer - *\param bufsz the source buffer size - */ -bool -map_data_openmem(struct map_data *data, const void *buf, size_t bufsz); - -/** - * Dispose the map definition data. - * - * \pre data != NULL - * \param data the map definition - */ -void -map_data_finish(struct map_data *data); - -/** - * Initialize this map. - * - * \pre map != NULL - * \pre data != NULL - * \pre tileset != NULL && texture_ok(tileset) - * \param map the map to initialize - * \param data the definition to reference - * \param tileset the tileset to use - * \return False on errors. - */ -bool -map_init(struct map *map, - struct map_data *data, - struct texture *tileset); - -/** - * Render a map. - * - * \pre map != NULL - * \param map the map to render - * \param srcx the x coordinate region - * \param srcy the y coordinate region - */ -void -map_draw(struct map *map, int srcx, int srcy); - -/** - * Force map repaint on its texture. - * - * \pre map != NULL - * \param map the map to repaint - * \warning This function does not render anything on the screen. - */ -void -map_repaint(struct map *map); - -/** - * Dispose map resources. - * - * \pre map != NULL - * \param map the map to close - */ -void -map_finish(struct map *map); - -#endif /* !MOLKO_MAP_H */
--- a/libcore/core/map_state.c Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,350 +0,0 @@ -/* - * map_state.c -- state when player is on a map - * - * 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 <stdio.h> - -#include "debug.h" -#include "event.h" -#include "game.h" -#include "map.h" -#include "map_state.h" -#include "painter.h" -#include "state.h" -#include "texture.h" -#include "walksprite.h" -#include "window.h" - -/* - * This is the speed the player moves on the map. - * - * SPEED represents the number of pixels it must move per SEC. - * SEC simply represends the number of milliseconds in one second. - */ -#define SPEED 100 -#define SEC 1000 - -/* - * Those are margins within the edge of the screen. The camera always try to - * keep those padding between the player and the screen. - */ -#define MARGIN_WIDTH 80 -#define MARGIN_HEIGHT 80 - -/* - * Convenient macros to access the state data. - */ -#define MAP() (&map_state_data.map) -#define PLAYER() (&map_state_data.player) -#define VIEW() (&map_state_data.view) - -/* - * This structure defines the possible movement of the player as flags since - * it's possible to make diagonal movements. - */ -enum movement { - MOVING_UP = 1 << 0, - MOVING_RIGHT = 1 << 1, - MOVING_DOWN = 1 << 2, - MOVING_LEFT = 1 << 3 -}; - -/* - * A bit of explanation within this array. The structure walksprite requires - * an orientation between 0-7 depending on the user direction. - * - * Since keys for moving the character may be pressed at the same time, we need - * a conversion table from "key pressed" to "orientation". - * - * When an orientation is impossible, it is set to -1. Example, when both left - * and right are pressed. - * - * MOVING_UP = 0001 = 0x1 - * MOVING_RIGHT = 0010 = 0x2 - * MOVING_DOWN = 0100 = 0x3 - * MOVING_LEFT = 1000 = 0x4 - */ -static unsigned int orientations[16] = { - [0x1] = 0, - [0x2] = 2, - [0x3] = 1, - [0x4] = 4, - [0x6] = 3, - [0x8] = 6, - [0x9] = 7, - [0xC] = 5 -}; - -/* - * Additional data that is not necessary to expose in map_state_data. - */ -static struct { - struct { - enum movement moving; - struct walksprite ws; - } player; - - struct { - int x; - int y; - unsigned int w; - unsigned int h; - } margin; -} cache; - -static void -center(void) -{ - VIEW()->x = PLAYER()->x - (VIEW()->w / 2); - VIEW()->y = PLAYER()->y - (VIEW()->h / 2); - - if (VIEW()->x < 0) - VIEW()->x = 0; - else if ((unsigned int)VIEW()->x > MAP()->data.real_w - VIEW()->w) - VIEW()->x = MAP()->data.real_w - VIEW()->w; - - if (VIEW()->y < 0) - VIEW()->y = 0; - else if ((unsigned int)VIEW()->y > MAP()->data.real_h - VIEW()->h) - VIEW()->y = MAP()->data.real_h - VIEW()->h; -} - -static void -enter(void) -{ - /* Adjust map properties. */ - struct map *m = &map_state_data.map.map; - - map_repaint(m); - MAP()->data.real_w = m->picture.w; - MAP()->data.real_h = m->picture.h; - - /* Adjust view. */ - VIEW()->w = window.w; - VIEW()->h = window.h; - - /* Adjust margin. */ - cache.margin.w = VIEW()->w - (MARGIN_WIDTH * 2); - cache.margin.h = VIEW()->h - (MARGIN_HEIGHT * 2); - - /* Center the view by default. */ - center(); - - /* Final bits. */ - walksprite_init(&cache.player.ws, &PLAYER()->sprite, 300); -} - -static void -leave(void) -{ -} - -static void -handle_keydown(const union event *event) -{ - switch (event->key.key) { - case KEY_UP: - cache.player.moving |= MOVING_UP; - break; - case KEY_RIGHT: - cache.player.moving |= MOVING_RIGHT; - break; - case KEY_DOWN: - cache.player.moving |= MOVING_DOWN; - break; - case KEY_LEFT: - cache.player.moving |= MOVING_LEFT; - break; - default: - break; - } - - PLAYER()->angle = orientations[cache.player.moving]; -} - -static void -handle_keyup(const union event *event) -{ - switch (event->key.key) { - case KEY_UP: - cache.player.moving &= ~(MOVING_UP); - break; - case KEY_RIGHT: - cache.player.moving &= ~(MOVING_RIGHT); - break; - case KEY_DOWN: - cache.player.moving &= ~(MOVING_DOWN); - break; - case KEY_LEFT: - cache.player.moving &= ~(MOVING_LEFT); - break; - default: - break; - } -} - -static void -move_right(unsigned int delta) -{ - PLAYER()->x += delta; - - if (PLAYER()->x > (int)(cache.margin.x + cache.margin.w)) { - VIEW()->x = (PLAYER()->x - VIEW()->w) + MARGIN_WIDTH; - - if (VIEW()->x >= (int)(MAP()->data.real_w - VIEW()->w)) - VIEW()->x = MAP()->data.real_w - VIEW()->w; - } - - if (PLAYER()->x > (int)MAP()->data.real_w - 48) - PLAYER()->x = MAP()->data.real_w - 48; -} - -static void -move_left(unsigned int delta) -{ - PLAYER()->x -= delta; - - if (PLAYER()->x < cache.margin.x) { - VIEW()->x = PLAYER()->x - MARGIN_WIDTH; - - if (VIEW()->x < 0) - VIEW()->x = 0; - } - - if (PLAYER()->x < 0) - PLAYER()->x = 0; -} - -static void -move_down(unsigned int delta) -{ - PLAYER()->y += delta; - - if (PLAYER()->y > (int)(cache.margin.y + cache.margin.h)) { - VIEW()->y = (PLAYER()->y - VIEW()->h) + MARGIN_HEIGHT; - - if (VIEW()->y >= (int)(MAP()->data.real_h - VIEW()->h)) - VIEW()->y = MAP()->data.real_h - VIEW()->h; - } - - if (PLAYER()->y > (int)MAP()->data.real_h - 48) - PLAYER()->y = MAP()->data.real_h - 48; -} - -static void -move_up(unsigned int delta) -{ - PLAYER()->y -= delta; - - if (PLAYER()->y < cache.margin.y) { - VIEW()->y = PLAYER()->y - MARGIN_HEIGHT; - - if (VIEW()->y < 0) - VIEW()->y = 0; - } - - if (PLAYER()->y < 0) - PLAYER()->y = 0; -} - -static void -move(unsigned int ticks) -{ - /* This is the amount of pixels the player must move. */ - const int delta = SPEED * ticks / SEC; - - /* This is the rectangle within the view where users must be. */ - cache.margin.x = VIEW()->x + MARGIN_WIDTH; - cache.margin.y = VIEW()->y + MARGIN_HEIGHT; - - int dx = 0; - int dy = 0; - - if (cache.player.moving == 0) - return; - - if (cache.player.moving & MOVING_UP) - dy = -1; - if (cache.player.moving & MOVING_DOWN) - dy = 1; - if (cache.player.moving & MOVING_LEFT) - dx = -1; - if (cache.player.moving & MOVING_RIGHT) - dx = 1; - - /* Move the player and adjust view if needed. */ - if (dx > 0) - move_right(delta); - else if (dx < 0) - move_left(delta); - - if (dy > 0) - move_down(delta); - else if (dy < 0) - move_up(delta); - - walksprite_update(&cache.player.ws, ticks); -} - -static void -handle(const union event *event) -{ - switch (event->type) { - case EVENT_KEYDOWN: - handle_keydown(event); - break; - case EVENT_KEYUP: - handle_keyup(event); - break; - default: - break; - } -} - -static void -update(unsigned int ticks) -{ - move(ticks); -} - -static void -draw(void) -{ - struct debug_report report = {0}; - - map_draw(&map_state_data.map.map, VIEW()->x, VIEW()->y); - walksprite_draw( - &cache.player.ws, - PLAYER()->angle, - PLAYER()->x - VIEW()->x, - PLAYER()->y - VIEW()->y); - - debug_printf(&report, "position: %d, %d", PLAYER()->x, - PLAYER()->y); - debug_printf(&report, "view: %d, %d", VIEW()->x, - VIEW()->y); -} - -struct map_state_data map_state_data; - -struct state map_state = { - .enter = enter, - .leave = leave, - .update = update, - .handle = handle, - .draw = draw -};
--- a/libcore/core/map_state.h Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * map_state.h -- state when player is on a map - * - * 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_MAP_STATE_H -#define MOLKO_MAP_STATE_H - -/** - * \file map_state.h - * \brief State when player is on a map. - * \ingroup states - */ - -#include "map.h" -#include "sprite.h" - -/** - * \brief Data for the state. - * - * Update this structure before switching to this state. - */ -extern struct map_state_data { - /** - * Map properties. - */ - struct { - struct map_data data; /*!< (+) Map data. */ - struct map map; /*!< (+) Map object. */ - } map; - - /** - * Player position. - * - * If you adjust this structure, it is strictly encouraged to update - * the view as well. - */ - struct { - struct sprite sprite; /*!< (+) The sprite to use */ - int x; /*!< (+) Player position in x */ - int y; /*!< (+) Player position in y */ - int angle; /*!< (+) Player angle (see walksprite) */ - } player; - - /** - * Position and size of the view. - */ - struct { - int x; /*!< (+) Position in x */ - int y; /*!< (+) Position in y */ - unsigned int w; /*!< (+) View width */ - unsigned int h; /*!< (+) View height */ - } view; -} map_state_data; /*!< Access to data. */ - -/** - * \brief State when player is on a map. - */ -extern struct state map_state; - -#endif /* !MOLKO_MAP_STATE_H */
--- a/libcore/core/message.c Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,270 +0,0 @@ -/* - * message.c -- message dialog - * - * 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 <stdlib.h> -#include <string.h> - -#include "action.h" -#include "event.h" -#include "font.h" -#include "frame.h" -#include "label.h" -#include "maths.h" -#include "message.h" -#include "painter.h" -#include "panic.h" -#include "sprite.h" -#include "texture.h" -#include "theme.h" -#include "trace.h" -#include "util.h" - -#define THEME(msg) (msg->theme ? msg->theme : theme_default()) - -static void -handle(struct action *action, const union event *ev) -{ - assert(action); - assert(ev); - - message_handle(action->data, ev); -} - -static bool -update(struct action *action, unsigned int ticks) -{ - assert(action); - - return message_update(action->data, ticks); -} - -static void -draw(struct action *action) -{ - assert(action); - - message_draw(action->data); -} - -static void -draw_frame(const struct message *msg) -{ - assert(msg); - - struct frame frame = { - .w = msg->w, - .h = msg->h, - .theme = msg->theme - }; - - frame_draw(&frame); -} - -static void -draw_lines(const struct message *msg) -{ - struct theme theme; - unsigned int lineh; - - /* Shallow copy theme to modify colors. */ - theme_shallow(&theme, msg->theme); - - /* Compute text size for list alignment. */ - lineh = font_height(theme.fonts[THEME_FONT_INTERFACE]); - - for (int i = 0; i < 6; ++i) { - if (!msg->text[i]) - continue; - - struct label label = { - .y = i * lineh, - .w = msg->w, - .h = msg->h, - .theme = &theme, - .text = msg->text[i], - .align = LABEL_ALIGN_TOP_LEFT, - .flags = LABEL_FLAGS_SHADOW - }; - - /* - * The function label_draw will use THEME_COLOR_NORMAL to draw - * text and THEME_COLOR_SHADOW so if we have selected a line - * we need to cheat the normal color. - */ - if (msg->flags & MESSAGE_FLAGS_QUESTION && msg->index == (unsigned int)i) - theme.colors[THEME_COLOR_NORMAL] = THEME(msg)->colors[THEME_COLOR_SELECTED]; - else - theme.colors[THEME_COLOR_NORMAL] = THEME(msg)->colors[THEME_COLOR_NORMAL]; - - label_draw(&label); - } -} - -void -message_start(struct message *msg) -{ - 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 -message_handle(struct message *msg, const union event *ev) -{ - assert(msg); - assert(ev); - - /* Skip if the message animation hasn't complete. */ - if (msg->state != MESSAGE_STATE_SHOWING) - return; - - /* Only keyboard event are valid. */ - if (ev->type != EVENT_KEYDOWN || msg->state == MESSAGE_STATE_NONE) - return; - - switch (ev->key.key) { - case KEY_UP: - if (msg->index > 0) - msg->index--; - break; - case KEY_DOWN: - if (msg->index < 5 && msg->text[msg->index + 1]) - msg->index++; - break; - case KEY_ENTER: - msg->state = msg->flags & MESSAGE_FLAGS_FADEOUT - ? MESSAGE_STATE_HIDING - : MESSAGE_STATE_NONE; - msg->elapsed = 0; - break; - default: - break; - } -} - -bool -message_update(struct message *msg, unsigned int ticks) -{ - assert(msg); - - msg->elapsed += ticks; - - switch (msg->state) { - case MESSAGE_STATE_OPENING: - msg->scale = (double)msg->elapsed / (double)msg->delay; - - if (msg->scale > 1) - msg->scale = 1; - - if (msg->elapsed >= msg->delay) { - msg->state = MESSAGE_STATE_SHOWING; - msg->elapsed = 0; - } - - break; - case MESSAGE_STATE_SHOWING: - /* Do automatically switch state if requested by the user. */ - if (msg->flags & MESSAGE_FLAGS_AUTOMATIC && msg->elapsed >= msg->timeout) { - msg->state = msg->flags & MESSAGE_FLAGS_FADEOUT - ? MESSAGE_STATE_HIDING - : MESSAGE_STATE_NONE; - msg->elapsed = 0; - } - - break; - case MESSAGE_STATE_HIDING: - msg->scale = 1 - (double)msg->elapsed / (double)msg->delay; - - if (msg->scale < 0) - msg->scale = 0; - if (msg->elapsed >= msg->delay) { - msg->state = MESSAGE_STATE_NONE; - msg->elapsed = 0; - } - - break; - default: - break; - } - - return msg->state == MESSAGE_STATE_NONE; -} - -void -message_draw(struct message *msg) -{ - assert(msg); - - struct texture tex; - int x, y; - unsigned int w, h; - - if (!texture_new(&tex, msg->w, msg->h)) - panic(); - - PAINTER_BEGIN(&tex); - draw_frame(msg); - draw_lines(msg); - PAINTER_END(); - - /* Compute scaling. */ - w = msg->w * msg->scale; - h = msg->h * msg->scale; - - /* Centerize within its drawing area. */ - maths_centerize(&x, &y, w, h, msg->x, msg->y, msg->w, msg->h); - - /* Draw and clear. */ - texture_scale(&tex, 0, 0, msg->w, msg->h, x, y, w, h, 0); - texture_finish(&tex); -} - -void -message_hide(struct message *msg) -{ - assert(msg); - - msg->state = MESSAGE_STATE_HIDING; - msg->elapsed = 0; -} - -void -message_action(struct message *msg, struct action *action) -{ - assert(msg); - assert(action); - - memset(action, 0, sizeof (struct action)); - action->data = msg; - action->handle = handle; - action->update = update; - action->draw = draw; - - message_start(msg); -}
--- a/libcore/core/message.h Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,197 +0,0 @@ -/* - * message.h -- message dialog - * - * 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_MESSAGE_H -#define MOLKO_MESSAGE_H - -/** - * \file message.h - * \brief Message dialog. - * \ingroup actions - * \ingroup drawing - * - * This module's purpose is to show a dialog box into the screen to show text - * and optionally ask the user a question. - * - * By itself, it is very low level and does not prevent other parts of the game - * to use the input so you probably need to inhibit input if your dialog is - * meant to be displayed on a map. - * - * To use it use the following procedure: - * - * 1. Create a struct message object and set required properties, - * 2. Call \ref message_start to reset the state, - * 3. Call \ref message_handle and \ref message_update with appropriate values, - * 4. Call \ref message_draw to render the dialog. - * - * Depending on message flags or user input, step 3 may return true in this - * case you should stop using the message as it has completed rendering. - * - * \note All properties must exist until the object is no longer used. - * - * \code - * struct message msg = { - * // You can show up to 6 lines. - * .text = { - * "Hello, what's up?" - * }, - * // This image will be shown on the left as user face. - * .avatar = mysuperavatar, - * // This should point to a image that is used as background. - * .frame = mysuperframe, - * // The first color is normal text, the second is for selected text - * // in case of question. - * .colors = { 0xffffffff, 0x0000ffff }, - * // This indicates this message is a question. - * .flags = MESSAGE_QUESTION - * }; - * \endcode - */ - -#include <stdbool.h> - -#include "texture.h" - -struct action; -struct font; -struct theme; - -union event; - -/** - * \brief Default animation speed in milliseconds. - */ -#define MESSAGE_DELAY_DEFAULT (150) - -/** - * \brief Default timeout in milliseconds for automatic messages. - */ -#define MESSAGE_TIMEOUT_DEFAULT (5000) - -/** - * \brief Message flags. - */ -enum message_flags { - MESSAGE_FLAGS_AUTOMATIC = (1 << 0), /*!< Will automatically change state by itself. */ - MESSAGE_FLAGS_QUESTION = (1 << 1), /*!< The message is a question. */ - MESSAGE_FLAGS_FADEIN = (1 << 2), /*!< Animate opening. */ - MESSAGE_FLAGS_FADEOUT = (1 << 3) /*!< Animate closing. */ -}; - -/** - * \brief Message state. - */ -enum message_state { - MESSAGE_STATE_NONE, /*!< Message hasn't start yet or is finished */ - MESSAGE_STATE_OPENING, /*!< Message animation is opening */ - MESSAGE_STATE_SHOWING, /*!< Message is displaying */ - MESSAGE_STATE_HIDING /*!< Message animation for hiding */ -}; - -/** - * \brief Message object. - * - * This structure is used to display a message into the screen. It does not own - * any user properties and therefore must exist while using it. - */ -struct message { - int x; /*!< (+) Position in x. */ - int y; /*!< (+) Position in y. */ - unsigned int w; /*!< (+) Width. */ - unsigned int h; /*!< (+) Height. */ - unsigned int delay; /*!< (+) Delay for animations. */ - unsigned int timeout; /*!< (+) Timeout in milliseconds. */ - const char *text[6]; /*!< (+) Lines of text to show. */ - struct texture *avatar; /*!< (+&?) Avatar face. */ - unsigned int index; /*!< (+) Line selected */ - enum message_flags flags; /*!< (+) Message flags */ - enum message_state state; /*!< (-) Current state */ - struct theme *theme; /*!< (+&?) Theme to use. */ - unsigned int elapsed; /*!< (-) Time elapsed. */ - double scale; /*!< (-) Current scale [0-1]. */ -}; - -/** - * Start opening the message. This function will reset the message state and - * 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 -message_start(struct message *msg); - -/** - * Handle input events. - * - * This function will alter state of the message and change its selection in - * case of question. - * - * \pre msg != NULL - * \pre ev != NULL - * \param msg the message - * \param ev the event which occured - */ -void -message_handle(struct message *msg, const union event *ev); - -/** - * Update the message state and elapsed time.. - * - * \pre msg != NULL - * \param msg the message - * \param ticks the elapsed delay since last frame - * \return true if it has finished - */ -bool -message_update(struct message *msg, unsigned int ticks); - -/** - * Draw the message into the screen. - * - * \pre msg != NULL - * \param msg the message - */ -void -message_draw(struct message *msg); - -/** - * Start hiding the message. - * - * \pre msg != NULL - * \param msg the message - * \note You should still continue to draw the message as the animation is not - * finished! - */ -void -message_hide(struct message *msg); - -/** - * Convert message into an action. - * - * \pre msg != NULL - * \pre action != NULL - * \param msg the message to reference - * \param action the action to fill - */ -void -message_action(struct message *msg, struct action *action); - -#endif /* !MOLKO_MESSAGE_H */
--- a/libcore/core/theme.c Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,308 +0,0 @@ -/* - * theme.c -- abstract theming - * - * 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 <string.h> - -#include "button.h" -#include "checkbox.h" -#include "font.h" -#include "frame.h" -#include "label.h" -#include "maths.h" -#include "painter.h" -#include "panic.h" -#include "texture.h" -#include "theme.h" -#include "util.h" - -#include <core/assets/fonts/f25-bank-printer.h> -#include <core/assets/fonts/comic-neue.h> - -#define THEME(t) (t ? t : &default_theme) - -#define CHECKBOX_W 16 -#define CHECKBOX_H 16 -#define CHECKBOX_RAD 6 - -static void -box(int x, int y, unsigned int w, unsigned int h) -{ - /* Some basic outlines. */ - painter_set_color(0x4d3533ff); - - painter_draw_line(x, y, x + w, y); - painter_draw_line(x, y + h, x + w, y + h); - painter_draw_line(x, y, x, y + h); - painter_draw_line(x + w, y, x + w, y + h); -} - -static void -draw_frame(struct theme *t, const struct frame *frame) -{ - (void)t; - - if (frame->style == FRAME_STYLE_BOX) - painter_set_color(0x6e4c30ff); - else - painter_set_color(0xce9248ff); - - painter_draw_rectangle(frame->x, frame->y, frame->w, frame->h); - box(frame->x, frame->y, frame->w, frame->h); -} - -static void -draw_label(struct theme *t, const struct label *label) -{ - struct font *font; - struct texture tex; - int x, y, bx, by; - unsigned int tw, th, bw, bh; - - /* Compute real box size according to padding. */ - bx = label->x + t->padding; - by = label->y + t->padding; - bw = label->w - (t->padding * 2); - bh = label->h - (t->padding * 2); - - /* Make a shallow copy of the interface font. */ - font = t->fonts[THEME_FONT_INTERFACE]; - - /* Compute text size. */ - if (!font_box(font, label->text, &tw, &th)) - panic(); - - /* Compute position according to alignment and box. */ - switch (label->align) { - case LABEL_ALIGN_CENTER: - maths_centerize(&x, &y, tw, th, bx, by, bw, bh); - break; - case LABEL_ALIGN_TOP_LEFT: - x = bx; - y = by; - break; - case LABEL_ALIGN_TOP: - maths_centerize(&x, NULL, tw, th, bx, by, bw, bh); - y = by; - break; - case LABEL_ALIGN_TOP_RIGHT: - x = bx + bw - tw; - y = by; - break; - case LABEL_ALIGN_RIGHT: - maths_centerize(NULL, &y, tw, th, bx, by, bw, bh); - x = bx + bw - tw; - break; - case LABEL_ALIGN_BOTTOM_RIGHT: - x = bx + bw - tw; - y = by + bh - th; - break; - case LABEL_ALIGN_BOTTOM: - maths_centerize(&x, NULL, tw, th, bx, by, bw, bh); - y = by + bh - th; - break; - case LABEL_ALIGN_BOTTOM_LEFT: - x = bx; - y = by + bh - th; - break; - case LABEL_ALIGN_LEFT: - maths_centerize(NULL, &y, tw, th, bx, by, bw, bh); - x = bx; - default: - break; - } - - /* Shadow text, only if enabled. */ - if (label->flags & LABEL_FLAGS_SHADOW) { - font->color = t->colors[THEME_COLOR_SHADOW]; - - if (!font_render(font, &tex, label->text)) - panic(); - - texture_draw(&tex, x + 1, y + 1); - texture_finish(&tex); - } - - /* Normal text. */ - font->color = t->colors[THEME_COLOR_NORMAL]; - - if (!font_render(font, &tex, label->text)) - panic(); - - texture_draw(&tex, x, y); - texture_finish(&tex); -} - -static void -draw_button(struct theme *t, const struct button *button) -{ - (void)t; - - struct label label = { - .text = button->text, - .x = button->x, - .y = button->y, - .w = button->w, - .h = button->h - }; - - painter_set_color(0xabcdefff); - painter_draw_rectangle(button->x, button->y, button->w, button->h); - - label_draw(&label); - - box(button->x, button->y, button->w, button->h); -} - -static void -draw_checkbox(struct theme *t, const struct checkbox *cb) -{ - box(cb->x, cb->y, CHECKBOX_W, CHECKBOX_H); - - if (cb->checked) - painter_draw_rectangle(cb->x + 5, cb->y + 5, CHECKBOX_W - 9, CHECKBOX_H - 9); - - if (cb->label) { - const unsigned int w = cb->w - (t->padding * 2) - CHECKBOX_W; - const int x = cb->x + (t->padding * 2) + CHECKBOX_W; - - struct label label = { - .text = cb->label, - .align = LABEL_ALIGN_LEFT, - .x = x, - .y = cb->y, - .w = w, - .h = cb->h - }; - - draw_label(t, &label); - } -} - -/* Default theme. */ -static struct theme default_theme = { - .colors = { - [THEME_COLOR_NORMAL] = 0xffffffff, - [THEME_COLOR_SELECTED] = 0x006554ff, - [THEME_COLOR_SHADOW] = 0x000000ff - }, - .padding = 10, - .draw_frame = draw_frame, - .draw_label = draw_label, - .draw_button = draw_button, - .draw_checkbox = draw_checkbox -}; - -/* Default font catalog. */ -#define FONT(bin, size, index) \ - { bin, sizeof (bin), size, &default_theme.fonts[index], {0} } - -static struct font_catalog { - const unsigned char *data; - const size_t datasz; - unsigned int size; - struct font **dest; - struct font font; -} default_fonts[] = { - FONT(fonts_f25_bank_printer, 10, THEME_FONT_DEBUG), - FONT(fonts_comic_neue, 20, THEME_FONT_INTERFACE) -}; - -bool -theme_init(void) -{ - /* Open all fonts. */ - for (size_t i = 0; i < NELEM(default_fonts); ++i) { - struct font_catalog *fc = &default_fonts[i]; - - if (!font_openmem(&fc->font, fc->data, fc->datasz, fc->size)) - goto failed; - - /* Reference this font into the catalog. */ - *default_fonts[i].dest = &default_fonts[i].font; - } - - return true; - -failed: - theme_finish(); - - return false; -} - -struct theme * -theme_default(void) -{ - return &default_theme; -} - -unsigned int -theme_padding(const struct theme *t) -{ - return THEME(t)->padding; -} - -void -theme_shallow(struct theme *dst, const struct theme *src) -{ - assert(dst); - - memcpy(dst, src ? src : &default_theme, sizeof (*src)); -} - -void -theme_draw_frame(struct theme *t, const struct frame *frame) -{ - assert(frame); - - THEME(t)->draw_frame(THEME(t), frame); -} - -void -theme_draw_label(struct theme *t, const struct label *label) -{ - assert(label); - - THEME(t)->draw_label(THEME(t), label); -} - -void -theme_draw_button(struct theme *t, const struct button *button) -{ - assert(button); - - THEME(t)->draw_button(THEME(t), button); -} - -void -theme_draw_checkbox(struct theme *t, const struct checkbox *cb) -{ - assert(cb); - - THEME(t)->draw_checkbox(THEME(t), cb); -} - -void -theme_finish(void) -{ - for (size_t i = 0; i < NELEM(default_fonts); ++i) { - font_finish(&default_fonts[i].font); - *default_fonts[i].dest = NULL; - } -}
--- a/libcore/core/theme.h Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,194 +0,0 @@ -/* - * theme.h -- abstract theming - * - * 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_THEME_H -#define MOLKO_THEME_H - -/** - * \file theme.h - * \brief Abstract theming. - */ - -#include <stdbool.h> - -struct checkbox; -struct button; -struct font; -struct frame; -struct label; - -/** - * \brief Font component. - */ -enum theme_font { - THEME_FONT_DEBUG, /*!< Font for debug messages. */ - THEME_FONT_INTERFACE, /*!< Font for interface elements. */ - THEME_FONT_LAST /*!< Unused. */ -}; - -/** - * \brief Theme colors. - */ -enum theme_color { - THEME_COLOR_DEBUG, /*!< Debug color font. */ - THEME_COLOR_NORMAL, /*!< Normal font color. */ - THEME_COLOR_SELECTED, /*!< Font color for selected elements. */ - THEME_COLOR_SHADOW, /*!< Shadow color. */ - THEME_COLOR_LAST /*!< Unused. */ -}; - -/** - * \brief Abstract theme structure. - */ -struct theme { - /** - * (+&) Fonts catalog. - */ - struct font *fonts[THEME_FONT_LAST]; - - /** - * (+) Miscellaneous colors. - */ - unsigned long colors[THEME_COLOR_LAST]; - - /** - * (+) Padding between GUI elements. - */ - unsigned int padding; - - /** - * (+) Draw a frame. - * - * This function is used to draw a box usually as a container where UI - * elements will be put. - * - * \see \ref theme_draw_frame - */ - void (*draw_frame)(struct theme *, const struct frame *); - - /** - * (+) Draw a label. - * - * \see \ref theme_draw_label - */ - void (*draw_label)(struct theme *, const struct label *); - - /** - * (+) Draw a button. - * - * \see \ref theme_draw_button - */ - void (*draw_button)(struct theme *, const struct button *); - - /** - * (+) Draw a checkbox. - * - * \see \ref theme_draw_button - */ - void (*draw_checkbox)(struct theme *t, const struct checkbox *); -}; - -/** - * Initialize the theming system. - * - * \return false on errors - * \warning This function must be called before any other theme functions. - */ -bool -theme_init(void); - -/** - * Get a reference to the default theme. - * - * \return A non-owning pointer to a static storage for the default theme - */ -struct theme * -theme_default(void); - -/** - * Convenient shortcut to shallow copy src into dst. - * - * Use this function when you want your own local copy of a theme because you - * want to modify some attributes. - * - * This is a shortcut to `memcpy(dst, src, sizeof (*src))`. - * - * \pre dst != NULL - * \param dst the destination theme - * \param src the source theme (may be NULL) - * \note Resources are not cloned, internal pointers will adress the same - * regions. - */ -void -theme_shallow(struct theme *dst, const struct theme *src); - -/** - * Get the desired padding between GUI elements. - * - * \param t the theme to use (may be NULL) - * \return the padding in pixels - */ -unsigned int -theme_padding(const struct theme *t); - -/** - * Draw a frame. - * - * \pre frame != NULL - * \param t the theme to use (may be NULL) - * \param frame the frame - */ -void -theme_draw_frame(struct theme *t, const struct frame *frame); - -/** - * Draw a label. - * - * \pre label != NULL - * \param t the theme to use (may be NULL) - * \param label the label - */ -void -theme_draw_label(struct theme *t, const struct label *label); - -/** - * Draw a button. - * - * \pre button != NULL - * \param t the theme to use (may be NULL) - * \param button the button - */ -void -theme_draw_button(struct theme *t, const struct button *button); - -/** - * Draw a checkbox. - * - * \param t the theme to use (may be NULL) - * \param cb the checkbox - */ -void -theme_draw_checkbox(struct theme *t, const struct checkbox *cb); - -/** - * Close associated resources. - */ -void -theme_finish(void); - -#endif /* !MOLKO_THEME_H */
--- a/libcore/core/walksprite.c Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * walksprite.c -- sprite designed for walking entities - * - * 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 <string.h> - -#include "walksprite.h" -#include "sprite.h" - -void -walksprite_init(struct walksprite *ws, struct sprite *sprite, unsigned int delay) -{ - assert(ws); - assert(sprite); - - memset(ws, 0, sizeof (struct walksprite)); - ws->sprite = sprite; - ws->delay = delay; -} - -void -walksprite_update(struct walksprite *ws, unsigned int ticks) -{ - assert(ws); - - ws->elapsed += ticks; - - if (ws->elapsed >= ws->delay) { - ws->index += 1; - - if (ws->index >= ws->sprite->ncols) - ws->index = 0; - - ws->elapsed = 0; - } -} - -void -walksprite_draw(struct walksprite *ws, unsigned int orientation, int x, int y) -{ - assert(ws); - assert(orientation < 8); - - sprite_draw(ws->sprite, orientation, ws->index, x, y); -}
--- a/libcore/core/walksprite.h Thu Oct 15 09:21:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* - * walksprite.h -- sprite designed for walking entities - * - * 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_WALKSPRITE_H -#define MOLKO_WALKSPRITE_H - -/** - * \file walksprite.h - * \brief Sprite designed for walking entities. - * \ingroup drawing - */ - -struct sprite; - -/** - * \brief Sprite designed for walking entities. - * - * This structure works with sprite images that are defined as using the - * following conventions: - * - * ``` - * 7 0 1 - * ↖ ↑ ↗ - * 6 ← → 2 - * ↙ ↓ ↘ - * 5 4 3 - * ``` - * - * Where numbers define row in the sprite according to the character - * orientation. In other terms, your image sprite should look like this: - * - * ``` - * row columns in your image - * ---|--------------------- - * 0 | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ - * 1 | ↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗ - * 2 | →→→→→→→→→→→→→→→→→→→→ - * 3 | ↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘ - * 4 | ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ - * 5 | ↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙ - * 6 | ←←←←←←←←←←←←←←←←←←←← - * 7 | ↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖ - * ``` - */ -struct walksprite { - struct sprite *sprite; /*!< (+&) The sprite to use */ - unsigned int delay; /*!< (+) The delay between frames */ - unsigned int index; /*!< (-) Current column index */ - unsigned int elapsed; /*!< (-) Elapsed time since last frame */ -}; - -/** - * Initialize the walking sprite. - * - * \pre ws != NULL - * \pre sprite != NULL - * \param ws the walking sprite - * \param sprite the sprite to use - * \param delay the delay between sprites - */ -void -walksprite_init(struct walksprite *ws, struct sprite *sprite, unsigned int delay); - -/** - * Update the walking sprite - * - * \pre ws != NULL - * \param ws the walking sprite - * \param ticks the number of milliseconds between last frame - */ -void -walksprite_update(struct walksprite *ws, unsigned int ticks); - -/** - * Draw the appropriate sprite cell to the screen according to the orientation - * given. - * - * \pre ws != NULL - * \pre orientation < 8 - * \param ws the walking sprite - * \param orientation the orientation (or the row between 0 and 7) - * \param x the x coordinate - * \param y the y coordinate - */ -void -walksprite_draw(struct walksprite *ws, unsigned int orientation, int x, int y); - -#endif /* !MOLKO_WALKSPRITE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/CMakeLists.txt Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,49 @@ +# +# CMakeLists.txt -- CMake build system for librpg +# +# 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. +# + +project(librpg) + +set( + SOURCES + ${librpg_SOURCE_DIR}/rpg/inventory.c + ${librpg_SOURCE_DIR}/rpg/inventory.h + ${librpg_SOURCE_DIR}/rpg/inventory_dialog.c + ${librpg_SOURCE_DIR}/rpg/inventory_dialog.h + ${librpg_SOURCE_DIR}/rpg/item.h + ${librpg_SOURCE_DIR}/rpg/map.c + ${librpg_SOURCE_DIR}/rpg/map.h + ${librpg_SOURCE_DIR}/rpg/map_state.c + ${librpg_SOURCE_DIR}/rpg/map_state.h + ${librpg_SOURCE_DIR}/rpg/message.c + ${librpg_SOURCE_DIR}/rpg/message.h + ${librpg_SOURCE_DIR}/rpg/walksprite.c + ${librpg_SOURCE_DIR}/rpg/walksprite.h +) + +molko_define_library( + TARGET librpg + SOURCES ${SOURCES} + LIBRARIES + libcore + libui + PUBLIC_INCLUDES + $<BUILD_INTERFACE:${librpg_SOURCE_DIR}> +) + +source_group(rpg FILES ${SOURCES}) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/inventory.c Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,210 @@ +/* + * inventory.c -- inventory of items + * + * 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 "inventory.h" +#include "item.h" + +#define INVENTORY_TOTAL (INVENTORY_ROWS_MAX * INVENTORY_COLS_MAX) + +static bool +can_be_used(struct inventory_slot *slot, const struct item *item) +{ + assert(item); + + /* Empty slot. */ + if (!slot->item) + return false; + + /* Not same object. */ + if (strcmp(slot->item->name, item->name) != 0) + return false; + + /* No space in this slot. */ + if (slot->amount >= slot->item->stackable) + return false; + + return true; +} + +static struct inventory_slot * +find(struct inventory *iv, const struct item *item) +{ + assert(iv); + assert(item); + + /* First pass: find an entry with the same item. */ + for (unsigned int r = 0; r < INVENTORY_ROWS_MAX; ++r) + for (unsigned int c = 0; c < INVENTORY_COLS_MAX; ++c) + if (can_be_used(&iv->items[r][c], item)) + return &iv->items[r][c]; + + /* Second pass: try to find an empty slot. */ + for (unsigned int r = 0; r < INVENTORY_ROWS_MAX; ++r) + for (unsigned int c = 0; c < INVENTORY_COLS_MAX; ++c) + if (!iv->items[r][c].item) + return &iv->items[r][c]; + + return NULL; +} + +static unsigned +provide(struct inventory_slot *slot, struct item *item, unsigned int amount) +{ + assert(slot); + + unsigned int avail; + + /* The slot may be empty, make sure it contains this item. */ + slot->item = item; + + /* + * Example: + * + * The slot has already 10 items. + * The slot item is stackble up to 64 items. + * + * When pushing: + * + * 80: 54 pushed, 26 left + * 30: 30 pushed, 0 left. + */ + avail = slot->item->stackable - slot->amount; + + if (amount > avail) { + slot->amount += avail; + amount -= avail; + } else { + slot->amount += amount; + amount = 0; + } + + return amount; +} + +static bool +merge(struct inventory_slot *slot, struct inventory_slot *other) +{ + assert(slot); + assert(slot->item); + assert(other); + + /* Not compatible, return false to let the sorting continue. */ + if (slot->item != other->item) + return false; + + while (slot->amount < slot->item->stackable && other->amount) { + slot->amount++; + other->amount--; + } + + /* No more amount in the other slot, empty it. */ + if (other->amount == 0U) + memset(other, 0, sizeof (*other)); + + return slot->amount >= slot->item->stackable; +} + +static void +sort(struct inventory *iv, struct inventory_slot *slot, int r, int c) +{ + assert(slot); + assert(slot->item); + + /* Merge until the end of thiw row. */ + for (c = c + 1; c < INVENTORY_COLS_MAX; ++c) + if (merge(slot, &iv->items[r][c])) + return; + + /* Merge the next rows. */ + for (r = r + 1; r < INVENTORY_ROWS_MAX; ++r) + for (c = 0; c < INVENTORY_COLS_MAX; ++c) + if (merge(slot, &iv->items[r][c])) + return; +} + +unsigned int +inventory_push(struct inventory *iv, struct item *item, unsigned int amount) +{ + assert(iv); + assert(item); + + while (amount) { + struct inventory_slot *slot; + + if (!(slot = find(iv, item))) + break; + + /* Add as much as we can in this slot. */ + amount = provide(slot, item, amount); + } + + return amount; +} + +static int +compare_slot(const void *v1, const void *v2) +{ + const struct inventory_slot *slot1 = v1; + const struct inventory_slot *slot2 = v2; + int cmp; + + /* Two null slots compare equal. */ + if (!slot1->item && !slot2->item) + return 0; + + /* Null left should be moved after. */ + if (!slot1->item) + return 1; + + /* Null right slots should be moved after. */ + if (!slot2->item) + return -1; + + /* If they are identical, use amount to sort. */ + if ((cmp = strcmp(slot1->item->name, slot2->item->name)) == 0) + return (long long int)slot2->amount - (long long int)slot1->amount; + + return cmp; +} + +void +inventory_sort(struct inventory *iv) +{ + assert(iv); + + for (int r = 0; r < INVENTORY_ROWS_MAX; ++r) + for (int c = 0; c < INVENTORY_COLS_MAX; ++c) + if (iv->items[r][c].item) + sort(iv, &iv->items[r][c], r, c); + + /* Sort by names AND by amount. */ + qsort(iv->items, INVENTORY_TOTAL, sizeof (struct inventory_slot), compare_slot); +} + +void +inventory_clear(struct inventory *iv) +{ + assert(iv); + + memset(iv, 0, sizeof (*iv)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/inventory.h Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,92 @@ +/* + * inventory.h -- inventory of items + * + * 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_INVENTORY_H +#define MOLKO_INVENTORY_H + +/** + * \file inventory.h + * \brief Inventory of items. + */ + +/** + * \brief Maximum number of rows. + */ +#define INVENTORY_ROWS_MAX 3 + +/** + * \brief Maximum number of columns. + */ +#define INVENTORY_COLS_MAX 10 + +struct item; + +/** + * \brief Inventory slot. + * + * This structure describe a 'cell' into the inventory. It references a item + * and has a given amount of it. + */ +struct inventory_slot { + struct item *item; /*!< (+&?) Pointer to the item. */ + unsigned int amount; /*!< (-) Number of items in this slot. */ +}; + +/** + * \brief Inventory structure. + */ +struct inventory { + /** + * (-) Grid of objects. + */ + struct inventory_slot items[INVENTORY_ROWS_MAX][INVENTORY_COLS_MAX]; +}; + +/** + * Try to push as much as possible the given item. + * + * \pre iv != NULL + * \pre item != NULL + * \param iv the inventory + * \param item the item to reference + * \param amount the desired amount + * \return 0 if all items were pushed or the number left otherwise + */ +unsigned int +inventory_push(struct inventory *iv, struct item *item, unsigned int amount); + +/** + * Sort the inventory. + * + * \pre iv != NULL + * \pre item != NULL + * \param iv the inventory + */ +void +inventory_sort(struct inventory *iv); + +/** + * Clears the inventory. + * + * \pre iv != NULL + * \param iv the inventory + */ +void +inventory_clear(struct inventory *iv); + +#endif /* !MOLKO_INVENTORY_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/inventory_dialog.c Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,323 @@ +/* + * inventory_dialog.h -- dialog for items + * + * 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 <core/event.h> +#include <core/game.h> +#include <core/maths.h> +#include <core/painter.h> +#include <core/texture.h> +#include <core/window.h> + +#include "inventory.h" +#include "inventory_dialog.h" +#include "item.h" + +#define ITEM_SIZE 64 +#define ITEM_PADDING 32 + +#define GRID_WIDTH ((INVENTORY_COLS_MAX * ITEM_SIZE) + \ + ((INVENTORY_COLS_MAX + 1) * ITEM_PADDING)) +#define GRID_HEIGHT ((INVENTORY_ROWS_MAX * ITEM_SIZE) + \ + ((INVENTORY_ROWS_MAX + 1) * ITEM_PADDING)) + +#define LABEL_WIDTH (GRID_WIDTH) +#define LABEL_HEIGHT (64) + +#define BUTTON_HEIGHT (32) +#define BUTTON_WIDTH ((GRID_WIDTH) / 4) + +/* + * The frame looks like this: + * + * +----------------------------+ + * | [] [] [] [] [] [] [] [] [] | + * | [] [] [] [] [] [] [] [] [] | + * | [] [] [] [] [] [] [] [] [] | + * +----------------------------+ + * | Item name | + * | Item description | + * +----------------------------+ + * [ Sort ] + * + * Where space between cells is determined with ITEM_PADDING macro. + */ + +static unsigned int +total_width(void) +{ + return GRID_WIDTH; +} + +static unsigned int +total_height(void) +{ + return GRID_HEIGHT + LABEL_HEIGHT + BUTTON_HEIGHT; +} + +static void +compute_box_position(const struct inventory_dialog *dlg, int r, int c, int *x, int *y) +{ + assert(dlg); + assert(x); + assert(y); + + *x = dlg->fgrid.x + ((c * ITEM_SIZE) + ((c + 1) * ITEM_PADDING)); + *y = dlg->fgrid.y + ((r * ITEM_SIZE) + ((r + 1) * ITEM_PADDING)); +} + +static void +draw_grid_item_frame(int x, int y) +{ + struct frame frame = { + .x = x, + .y = y, + .w = ITEM_SIZE, + .h = ITEM_SIZE, + .style = FRAME_STYLE_BOX + }; + + frame_draw(&frame); +} + +static void +draw_grid_item_icon(struct item *item, int x, int y) +{ + struct texture *icon = item->icon; + + texture_scale(icon, 0, 0, icon->w, icon->h, x, y, ITEM_SIZE, ITEM_SIZE, 0.0); +} + +static void +draw_grid_item_amount(struct inventory_slot *slot, int x, int y) +{ + char nstr[16]; + struct label label = { + .text = nstr, + .x = x, + .y = y + }; + + /* Draw the number of item in this slot. */ + snprintf(nstr, sizeof (nstr), "%d", slot->amount); + label_draw(&label); +} + +static void +draw_grid_item(struct inventory_slot *slot, int x, int y, bool selected) +{ + draw_grid_item_frame(x, y); + + if (slot->item) { + draw_grid_item_icon(slot->item, x, y); + draw_grid_item_amount(slot, x, y); + } + + if (selected) { + x -= 16; + y += (ITEM_SIZE / 2) - 4; + painter_draw_circle(x, y, 8); + } +} + +static void +draw_grid_items(const struct inventory_dialog *dlg) +{ + int x, y; + bool selected; + + for (unsigned int r = 0; r < INVENTORY_ROWS_MAX; ++r) { + for (unsigned int c = 0; c < INVENTORY_COLS_MAX; ++c) { + selected = r == dlg->selrow && c == dlg->selcol; + compute_box_position(dlg, r, c, &x, &y); + draw_grid_item(&dlg->inv->items[r][c], x, y, selected); + } + } +} + +static void +draw_label(struct inventory_dialog *dlg) +{ + assert(dlg); + + struct item *item = dlg->inv->items[dlg->selrow][dlg->selcol].item; + + frame_draw(&dlg->fname); + frame_draw(&dlg->fdesc); + + if (item) { + dlg->lname.text = item->name; + dlg->ldesc.text = item->summary; + label_draw(&dlg->lname); + label_draw(&dlg->ldesc); + } +} + +void +inventory_dialog_open(struct inventory_dialog *dlg) +{ + assert(dlg); + assert(dlg->inv); + + int tw, th; + + dlg->state = INVENTORY_DIALOG_SHOWING; + + tw = total_width(); + th = total_height(); + + /* Grid frame position. */ + dlg->fgrid.w = GRID_WIDTH; + dlg->fgrid.h = GRID_HEIGHT; + dlg->fgrid.x = dlg->x; + dlg->fgrid.y = dlg->y; + + /* Name label. */ + dlg->fname.w = dlg->lname.w = LABEL_WIDTH; + dlg->fname.h = dlg->lname.h = LABEL_HEIGHT / 2; + dlg->fname.x = dlg->lname.x = dlg->x; + dlg->fname.y = dlg->lname.y = dlg->y + GRID_HEIGHT; + dlg->lname.x += ITEM_PADDING; + dlg->lname.align = LABEL_ALIGN_LEFT; + + /* Description label. */ + dlg->fdesc.w = dlg->ldesc.w = LABEL_WIDTH; + dlg->fdesc.h = dlg->ldesc.h = LABEL_HEIGHT / 2; + dlg->fdesc.x = dlg->ldesc.x = dlg->y; + dlg->fdesc.y = dlg->ldesc.y = dlg->y + GRID_HEIGHT + (LABEL_HEIGHT / 2); + dlg->ldesc.x += ITEM_PADDING; + dlg->ldesc.align = LABEL_ALIGN_LEFT; + + /* Button sort. */ + dlg->bsort.x = dlg->x; + dlg->bsort.y = dlg->y + GRID_HEIGHT + LABEL_HEIGHT; + dlg->bsort.w = BUTTON_WIDTH; + dlg->bsort.h = BUTTON_HEIGHT; + dlg->bsort.text = "Sort"; +} + +static void +handle_keydown(struct inventory_dialog *dlg, const struct event_key *ev) +{ + assert(ev && ev->type == EVENT_KEYDOWN); + + switch (ev->key) { + case KEY_LEFT: + if (dlg->selcol == 0) + dlg->selcol = INVENTORY_COLS_MAX - 1; + else + dlg->selcol--; + break; + case KEY_RIGHT: + dlg->selcol = (dlg->selcol + 1) % INVENTORY_COLS_MAX; + break; + case KEY_UP: + if (dlg->selrow == 0) + dlg->selrow = INVENTORY_ROWS_MAX - 1; + else + dlg->selrow--; + break; + case KEY_DOWN: + dlg->selrow = (dlg->selrow + 1) % INVENTORY_ROWS_MAX; + break; + default: + break; + } +} + +static void +handle_clickdown(struct inventory_dialog *dlg, const struct event_click *ev) +{ + assert(dlg); + assert(ev && ev->type == EVENT_CLICKDOWN); + + int x, y; + + for (int r = 0; r < INVENTORY_ROWS_MAX; ++r) { + for (int c = 0; c < INVENTORY_COLS_MAX; ++c) { + compute_box_position(dlg, r, c, &x, &y); + + if (maths_is_boxed(x, y, ITEM_SIZE, ITEM_SIZE, ev->x, ev->y)) { + dlg->selrow = r; + dlg->selcol = c; + } + } + } +} + +void +inventory_dialog_handle(struct inventory_dialog *dlg, const union event *event) +{ + assert(event); + + switch (event->type) { + case EVENT_KEYDOWN: + handle_keydown(dlg, &event->key); + break; + case EVENT_CLICKDOWN: + handle_clickdown(dlg, &event->click); + break; + default: + break; + } + + button_handle(&dlg->bsort, event); + + if (dlg->bsort.state == BUTTON_STATE_ACTIVATED) { + inventory_sort(dlg->inv); + button_reset(&dlg->bsort); + } +} + +void +inventory_dialog_update(struct inventory_dialog *dlg, unsigned int ticks) +{ + assert(dlg); + + (void)ticks; +} + +void +inventory_dialog_move(struct inventory_dialog *dlg, int x, int y) +{ + assert(dlg); + + dlg->x = x; + dlg->y = y; +} + +void +inventory_dialog_draw(struct inventory_dialog *dlg) +{ + assert(dlg); + + frame_draw(&dlg->fgrid); + draw_grid_items(dlg); + draw_label(dlg); + button_draw(&dlg->bsort); +} + +void +inventory_dialog_finish(struct inventory_dialog *dlg) +{ + assert(dlg); + + dlg->state = INVENTORY_DIALOG_NONE; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/inventory_dialog.h Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,76 @@ +/* + * inventory_dialog.h -- dialog for items + * + * 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 INVENTORY_DIALOG_H +#define INVENTORY_DIALOG_H + +#include <ui/button.h> +#include <ui/frame.h> +#include <ui/label.h> + +union event; + +struct inventory; +struct theme; + +/** + * \brief Inventory dialog state. + */ +enum inventory_dialog_state { + INVENTORY_DIALOG_NONE, + INVENTORY_DIALOG_SHOWING +}; + +/** + * \brief Inventory dialog. + */ +struct inventory_dialog { + int x; /*!< (+) Position in x. */ + int y; /*!< (+) Position in y. */ + struct inventory *inv; /*!< (+&) Inventory to use. */ + struct theme *theme; /*!< (+&?) Theme to use. */ + struct button bsort; /*!< (-) Button sort. */ + struct frame fgrid; /*!< (-) Grid frame. */ + struct frame fname; /*!< (-) Frame for name. */ + struct frame fdesc; /*!< (-) Frame for description. */ + struct label lname; /*!< (-) Label for name. */ + struct label ldesc; /*!< (-) Label for description. */ + enum inventory_dialog_state state; /*!< (-) Current dialog state. */ + unsigned int selrow; /*!< (-) Current selected row. */ + unsigned int selcol; /*!< (-) Current selected column. */ +}; + +void +inventory_dialog_open(struct inventory_dialog *dlg); + +void +inventory_dialog_handle(struct inventory_dialog *dlg, const union event *event); + +void +inventory_dialog_update(struct inventory_dialog *dlg, unsigned int ticks); + +void +inventory_dialog_move(struct inventory_dialog *dlg, int x, int y); + +void +inventory_dialog_draw(struct inventory_dialog *dlg); + +void +inventory_dialog_finish(struct inventory_dialog *dlg); + +#endif /* !INVENTORY_DIALOG_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/item.h Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,57 @@ +/* + * item.h -- inventory items + * + * 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_ITEM_H +#define MOLKO_ITEM_H + +/** + * \file item.h + * \brief Inventory items. + */ + +#include <stdbool.h> + +/** + * \brief Maximum count of an item into a stack. + */ +#define ITEM_STACK_MAX 64 + +struct character; +struct texture; + +/** + * \brief Inventory items. + */ +struct item { + const char *name; /*!< (+) Name of item. */ + const char *summary; /*!< (+) Summary description. */ + struct texture *icon; /*!< (+&) Icon to show. */ + unsigned int stackable; /*!< (+) Stack count allowed. */ + + /** + * (+) Execute the action for this character. + */ + void (*exec)(const struct item *, struct character *); + + /** + * (+?) Tells if the item can be used in this context. + */ + bool (*allowed)(const struct item *, const struct character *); +}; + +#endif /* !MOLKO_ITEM_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/map.c Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,237 @@ +/* + * map.c -- game map + * + * 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 <stdlib.h> +#include <string.h> + +#include <core/error.h> +#include <core/error_p.h> +#include <core/image.h> +#include <core/painter.h> +#include <core/sprite.h> +#include <core/sys.h> +#include <core/texture.h> +#include <core/window.h> + +#include "map.h" + +/* Create %<v>c string literal for scanf */ +#define MAX_F(v) MAX_F_(v) +#define MAX_F_(v) "%" #v "c" + +static void +parse_layer(struct map_data *data, const char *line, FILE *fp) +{ + char layer_name[32 + 1] = { 0 }; + struct map_layer *layer; + size_t amount, current; + + /* Determine layer. */ + if (sscanf(line, "layer|%32s", layer_name) <= 0) + return; + if (strcmp(layer_name, "background") == 0) + layer = &data->layers[0]; + else if (strcmp(layer_name, "foreground") == 0) + layer = &data->layers[1]; + else + return; + + /* Check if weight/height has been specified. */ + if (data->w == 0 || data->h == 0) + return; + + amount = data->w * data->h; + current = 0; + + if (!(layer->tiles = calloc(amount, sizeof (unsigned short)))) + return; + + for (int tile; fscanf(fp, "%d", &tile) && current < amount; ++current) + layer->tiles[current] = tile; +} + +static void +parse(struct map_data *data, const char *line, FILE *fp) +{ + if (strncmp(line, "title", 5) == 0) + sscanf(line, "title|" MAX_F(MAP_TITLE_MAX), data->title); + else if (strncmp(line, "width", 5) == 0) + sscanf(line, "width|%u", &data->w); + else if (strncmp(line, "height", 6) == 0) + sscanf(line, "height|%u", &data->h); + else if (strncmp(line, "tilewidth", 9) == 0) + sscanf(line, "tilewidth|%hu", &data->tile_w); + else if (strncmp(line, "tileheight", 10) == 0) + sscanf(line, "tileheight|%hu", &data->tile_h); + else if (strncmp(line, "origin", 6) == 0) + sscanf(line, "origin|%d|%d", &data->origin_x, &data->origin_y); + else if (strncmp(line, "tileset", 7) == 0) + sscanf(line, "tileset|" MAX_F(MAP_TILESET_MAX), data->tileset); + else if (strncmp(line, "layer", 5) == 0) + parse_layer(data, line, fp); +} + +static bool +check(struct map_data *data) +{ + if (strlen(data->title) == 0) + return error_printf("data has no title"); + if (data->w == 0 || data->h == 0) + return error_printf("data has null sizes"); + if (data->tile_w == 0 || data->tile_h == 0) + return error_printf("data has null tile sizes"); + if (!data->layers[0].tiles || !data->layers[1].tiles) + return error_printf("could not allocate data"); + + return true; +} + +static void +draw_layer(struct map *map, const struct map_layer *layer) +{ + assert(map); + assert(layer); + + struct sprite sprite; + int x = 0, y = 0; + + sprite_init(&sprite, map->tileset, map->data->tile_w, map->data->tile_h); + + for (unsigned int r = 0; r < map->data->w; ++r) { + for (unsigned int c = 0; c < map->data->h; ++c) { + unsigned int si = r * map->data->w + c; + unsigned int sr = (layer->tiles[si] - 1) / sprite.ncols; + unsigned int sc = (layer->tiles[si] - 1) % sprite.nrows; + + if (layer->tiles[si] != 0) + sprite_draw(&sprite, sr, sc, x, y); + + x += map->data->tile_w; + } + + x = 0; + y += map->data->tile_h; + } +} + +bool +map_data_open_fp(struct map_data *data, FILE *fp) +{ + assert(data); + + char line[1024]; + + if (!fp) + return false; + + memset(data, 0, sizeof (*data)); + + while (fgets(line, sizeof (line), fp)) { + /* Remove \n if any */ + line[strcspn(line, "\n")] = '\0'; + parse(data, line, fp); + } + + fclose(fp); + + if (!check(data)) { + map_data_finish(data); + return false; + } + + /* Compute real size. */ + data->real_w = data->w * data->tile_w; + data->real_h = data->h * data->tile_h; + + return true; +} + +bool +map_data_open(struct map_data *data, const char *path) +{ + assert(data); + assert(path); + + return map_data_open_fp(data, fopen(path, "r")); +} + +bool +map_data_openmem(struct map_data *data, const void *buf, size_t bufsz) +{ + assert(data); + assert(buf); + + return map_data_open_fp(data, fmemopen((void *)buf, bufsz, "r")); +} + +void +map_data_finish(struct map_data *data) +{ + assert(data); + + free(data->layers[0].tiles); + free(data->layers[1].tiles); + + memset(data, 0, sizeof (*data)); +} + +bool +map_init(struct map *map, struct map_data *data, struct texture *tileset) +{ + assert(map); + assert(data); + assert(tileset && texture_ok(tileset)); + + if (!(texture_new(&map->picture, data->real_w, data->real_h))) + return false; + + map->data = data; + map->tileset = tileset; + + map_repaint(map); + + return true; +} + +void +map_draw(struct map *map, int srcx, int srcy) +{ + texture_scale(&map->picture, srcx, srcy, window.w, window.h, + 0, 0, window.w, window.h, 0.0); +} + +void +map_repaint(struct map *map) +{ + PAINTER_BEGIN(&map->picture); + draw_layer(map, &map->data->layers[0]); + draw_layer(map, &map->data->layers[1]); + PAINTER_END(); +} + +void +map_finish(struct map *map) +{ + assert(map); + + texture_finish(&map->picture); + + memset(map, 0, sizeof (*map)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/map.h Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,159 @@ +/* + * map.h -- game map + * + * 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_MAP_H +#define MOLKO_MAP_H + +/** + * \file map.h + * \brief Game map. + */ + +#include <stdbool.h> +#include <stdio.h> + +#include <core/texture.h> + +/** + * \brief Max title length for a map. + */ +#define MAP_TITLE_MAX 32 + +/** + * \brief Max filename for tilesets. + */ +#define MAP_TILESET_MAX FILENAME_MAX + +/** + * \brief Map layer. + */ +struct map_layer { + unsigned short *tiles; /*!< (+) Array of tiles, depending on the map size. */ +}; + +/** + * \brief Map definition structure. + * + * This structure only defines the map characteristics. It does not have any + * logic and is left for game state. + */ +struct map_data { + char title[MAP_TITLE_MAX]; /*!< (+) The map title. */ + char tileset[MAP_TILESET_MAX]; /*!< (+) Name of tileset to use. */ + int origin_x; /*!< (+) Where the player starts in X. */ + int origin_y; /*!< (+) Where the player starts in Y. */ + unsigned int real_w; /*!< (-) Real width in pixels. */ + unsigned int real_h; /*!< (-) Real height in pixels. */ + unsigned int w; /*!< (-) Map width in cells. */ + unsigned int h; /*!< (-) Map height in cells. */ + unsigned short tile_w; /*!< (-) Pixels per cell (width). */ + unsigned short tile_h; /*!< (-) Pixels per cell (height). */ + struct map_layer layers[2]; /*!< (+) Layers (background, foreground). */ +}; + +/** + * \brief High level map object. + * + * This structure reference a map and perform drawing operations. + */ +struct map { + struct map_data *data; /*!< (+&) Map data. */ + struct texture *tileset; /*!< (+&) Tileset to use. */ + struct texture picture; /*!< (-) Map drawn into a picture. */ +}; + +/** + * Open a map defintion. + * + * \pre data != NULL + * \pre path != NULL + * \param data the map defintion to fill + * \param path the path to the map + * \return True if successfully loaded. + */ +bool +map_data_open(struct map_data *data, const char *path); + +/** + * Open map data definition from memory. + * + *\pre data != NULL + *\pre buf != NULL + *\param data the map definition to fill + *\param buf the source buffer + *\param bufsz the source buffer size + */ +bool +map_data_openmem(struct map_data *data, const void *buf, size_t bufsz); + +/** + * Dispose the map definition data. + * + * \pre data != NULL + * \param data the map definition + */ +void +map_data_finish(struct map_data *data); + +/** + * Initialize this map. + * + * \pre map != NULL + * \pre data != NULL + * \pre tileset != NULL && texture_ok(tileset) + * \param map the map to initialize + * \param data the definition to reference + * \param tileset the tileset to use + * \return False on errors. + */ +bool +map_init(struct map *map, + struct map_data *data, + struct texture *tileset); + +/** + * Render a map. + * + * \pre map != NULL + * \param map the map to render + * \param srcx the x coordinate region + * \param srcy the y coordinate region + */ +void +map_draw(struct map *map, int srcx, int srcy); + +/** + * Force map repaint on its texture. + * + * \pre map != NULL + * \param map the map to repaint + * \warning This function does not render anything on the screen. + */ +void +map_repaint(struct map *map); + +/** + * Dispose map resources. + * + * \pre map != NULL + * \param map the map to close + */ +void +map_finish(struct map *map); + +#endif /* !MOLKO_MAP_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/map_state.c Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,352 @@ +/* + * map_state.c -- state when player is on a map + * + * 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 <stdio.h> + +#include <core/event.h> +#include <core/game.h> +#include <core/painter.h> +#include <core/state.h> +#include <core/texture.h> +#include <core/window.h> + +#include <ui/debug.h> + +#include "map.h" +#include "map_state.h" +#include "walksprite.h" + +/* + * This is the speed the player moves on the map. + * + * SPEED represents the number of pixels it must move per SEC. + * SEC simply represends the number of milliseconds in one second. + */ +#define SPEED 100 +#define SEC 1000 + +/* + * Those are margins within the edge of the screen. The camera always try to + * keep those padding between the player and the screen. + */ +#define MARGIN_WIDTH 80 +#define MARGIN_HEIGHT 80 + +/* + * Convenient macros to access the state data. + */ +#define MAP() (&map_state_data.map) +#define PLAYER() (&map_state_data.player) +#define VIEW() (&map_state_data.view) + +/* + * This structure defines the possible movement of the player as flags since + * it's possible to make diagonal movements. + */ +enum movement { + MOVING_UP = 1 << 0, + MOVING_RIGHT = 1 << 1, + MOVING_DOWN = 1 << 2, + MOVING_LEFT = 1 << 3 +}; + +/* + * A bit of explanation within this array. The structure walksprite requires + * an orientation between 0-7 depending on the user direction. + * + * Since keys for moving the character may be pressed at the same time, we need + * a conversion table from "key pressed" to "orientation". + * + * When an orientation is impossible, it is set to -1. Example, when both left + * and right are pressed. + * + * MOVING_UP = 0001 = 0x1 + * MOVING_RIGHT = 0010 = 0x2 + * MOVING_DOWN = 0100 = 0x3 + * MOVING_LEFT = 1000 = 0x4 + */ +static unsigned int orientations[16] = { + [0x1] = 0, + [0x2] = 2, + [0x3] = 1, + [0x4] = 4, + [0x6] = 3, + [0x8] = 6, + [0x9] = 7, + [0xC] = 5 +}; + +/* + * Additional data that is not necessary to expose in map_state_data. + */ +static struct { + struct { + enum movement moving; + struct walksprite ws; + } player; + + struct { + int x; + int y; + unsigned int w; + unsigned int h; + } margin; +} cache; + +static void +center(void) +{ + VIEW()->x = PLAYER()->x - (VIEW()->w / 2); + VIEW()->y = PLAYER()->y - (VIEW()->h / 2); + + if (VIEW()->x < 0) + VIEW()->x = 0; + else if ((unsigned int)VIEW()->x > MAP()->data.real_w - VIEW()->w) + VIEW()->x = MAP()->data.real_w - VIEW()->w; + + if (VIEW()->y < 0) + VIEW()->y = 0; + else if ((unsigned int)VIEW()->y > MAP()->data.real_h - VIEW()->h) + VIEW()->y = MAP()->data.real_h - VIEW()->h; +} + +static void +enter(void) +{ + /* Adjust map properties. */ + struct map *m = &map_state_data.map.map; + + map_repaint(m); + MAP()->data.real_w = m->picture.w; + MAP()->data.real_h = m->picture.h; + + /* Adjust view. */ + VIEW()->w = window.w; + VIEW()->h = window.h; + + /* Adjust margin. */ + cache.margin.w = VIEW()->w - (MARGIN_WIDTH * 2); + cache.margin.h = VIEW()->h - (MARGIN_HEIGHT * 2); + + /* Center the view by default. */ + center(); + + /* Final bits. */ + walksprite_init(&cache.player.ws, &PLAYER()->sprite, 300); +} + +static void +leave(void) +{ +} + +static void +handle_keydown(const union event *event) +{ + switch (event->key.key) { + case KEY_UP: + cache.player.moving |= MOVING_UP; + break; + case KEY_RIGHT: + cache.player.moving |= MOVING_RIGHT; + break; + case KEY_DOWN: + cache.player.moving |= MOVING_DOWN; + break; + case KEY_LEFT: + cache.player.moving |= MOVING_LEFT; + break; + default: + break; + } + + PLAYER()->angle = orientations[cache.player.moving]; +} + +static void +handle_keyup(const union event *event) +{ + switch (event->key.key) { + case KEY_UP: + cache.player.moving &= ~(MOVING_UP); + break; + case KEY_RIGHT: + cache.player.moving &= ~(MOVING_RIGHT); + break; + case KEY_DOWN: + cache.player.moving &= ~(MOVING_DOWN); + break; + case KEY_LEFT: + cache.player.moving &= ~(MOVING_LEFT); + break; + default: + break; + } +} + +static void +move_right(unsigned int delta) +{ + PLAYER()->x += delta; + + if (PLAYER()->x > (int)(cache.margin.x + cache.margin.w)) { + VIEW()->x = (PLAYER()->x - VIEW()->w) + MARGIN_WIDTH; + + if (VIEW()->x >= (int)(MAP()->data.real_w - VIEW()->w)) + VIEW()->x = MAP()->data.real_w - VIEW()->w; + } + + if (PLAYER()->x > (int)MAP()->data.real_w - 48) + PLAYER()->x = MAP()->data.real_w - 48; +} + +static void +move_left(unsigned int delta) +{ + PLAYER()->x -= delta; + + if (PLAYER()->x < cache.margin.x) { + VIEW()->x = PLAYER()->x - MARGIN_WIDTH; + + if (VIEW()->x < 0) + VIEW()->x = 0; + } + + if (PLAYER()->x < 0) + PLAYER()->x = 0; +} + +static void +move_down(unsigned int delta) +{ + PLAYER()->y += delta; + + if (PLAYER()->y > (int)(cache.margin.y + cache.margin.h)) { + VIEW()->y = (PLAYER()->y - VIEW()->h) + MARGIN_HEIGHT; + + if (VIEW()->y >= (int)(MAP()->data.real_h - VIEW()->h)) + VIEW()->y = MAP()->data.real_h - VIEW()->h; + } + + if (PLAYER()->y > (int)MAP()->data.real_h - 48) + PLAYER()->y = MAP()->data.real_h - 48; +} + +static void +move_up(unsigned int delta) +{ + PLAYER()->y -= delta; + + if (PLAYER()->y < cache.margin.y) { + VIEW()->y = PLAYER()->y - MARGIN_HEIGHT; + + if (VIEW()->y < 0) + VIEW()->y = 0; + } + + if (PLAYER()->y < 0) + PLAYER()->y = 0; +} + +static void +move(unsigned int ticks) +{ + /* This is the amount of pixels the player must move. */ + const int delta = SPEED * ticks / SEC; + + /* This is the rectangle within the view where users must be. */ + cache.margin.x = VIEW()->x + MARGIN_WIDTH; + cache.margin.y = VIEW()->y + MARGIN_HEIGHT; + + int dx = 0; + int dy = 0; + + if (cache.player.moving == 0) + return; + + if (cache.player.moving & MOVING_UP) + dy = -1; + if (cache.player.moving & MOVING_DOWN) + dy = 1; + if (cache.player.moving & MOVING_LEFT) + dx = -1; + if (cache.player.moving & MOVING_RIGHT) + dx = 1; + + /* Move the player and adjust view if needed. */ + if (dx > 0) + move_right(delta); + else if (dx < 0) + move_left(delta); + + if (dy > 0) + move_down(delta); + else if (dy < 0) + move_up(delta); + + walksprite_update(&cache.player.ws, ticks); +} + +static void +handle(const union event *event) +{ + switch (event->type) { + case EVENT_KEYDOWN: + handle_keydown(event); + break; + case EVENT_KEYUP: + handle_keyup(event); + break; + default: + break; + } +} + +static void +update(unsigned int ticks) +{ + move(ticks); +} + +static void +draw(void) +{ + struct debug_report report = {0}; + + map_draw(&map_state_data.map.map, VIEW()->x, VIEW()->y); + walksprite_draw( + &cache.player.ws, + PLAYER()->angle, + PLAYER()->x - VIEW()->x, + PLAYER()->y - VIEW()->y); + + debug_printf(&report, "position: %d, %d", PLAYER()->x, + PLAYER()->y); + debug_printf(&report, "view: %d, %d", VIEW()->x, + VIEW()->y); +} + +struct map_state_data map_state_data; + +struct state map_state = { + .enter = enter, + .leave = leave, + .update = update, + .handle = handle, + .draw = draw +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/map_state.h Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,75 @@ +/* + * map_state.h -- state when player is on a map + * + * 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_MAP_STATE_H +#define MOLKO_MAP_STATE_H + +/** + * \file map_state.h + * \brief State when player is on a map. + * \ingroup states + */ + +#include <core/sprite.h> + +#include "map.h" + +/** + * \brief Data for the state. + * + * Update this structure before switching to this state. + */ +extern struct map_state_data { + /** + * Map properties. + */ + struct { + struct map_data data; /*!< (+) Map data. */ + struct map map; /*!< (+) Map object. */ + } map; + + /** + * Player position. + * + * If you adjust this structure, it is strictly encouraged to update + * the view as well. + */ + struct { + struct sprite sprite; /*!< (+) The sprite to use */ + int x; /*!< (+) Player position in x */ + int y; /*!< (+) Player position in y */ + int angle; /*!< (+) Player angle (see walksprite) */ + } player; + + /** + * Position and size of the view. + */ + struct { + int x; /*!< (+) Position in x */ + int y; /*!< (+) Position in y */ + unsigned int w; /*!< (+) View width */ + unsigned int h; /*!< (+) View height */ + } view; +} map_state_data; /*!< Access to data. */ + +/** + * \brief State when player is on a map. + */ +extern struct state map_state; + +#endif /* !MOLKO_MAP_STATE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/message.c Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,271 @@ +/* + * message.c -- message dialog + * + * 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 <stdlib.h> +#include <string.h> + +#include <core/action.h> +#include <core/event.h> +#include <core/font.h> +#include <core/maths.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/sprite.h> +#include <core/trace.h> +#include <core/util.h> + +#include <ui/frame.h> +#include <ui/label.h> +#include <ui/theme.h> + +#include "message.h" + +#define THEME(msg) (msg->theme ? msg->theme : theme_default()) + +static void +handle(struct action *action, const union event *ev) +{ + assert(action); + assert(ev); + + message_handle(action->data, ev); +} + +static bool +update(struct action *action, unsigned int ticks) +{ + assert(action); + + return message_update(action->data, ticks); +} + +static void +draw(struct action *action) +{ + assert(action); + + message_draw(action->data); +} + +static void +draw_frame(const struct message *msg) +{ + assert(msg); + + struct frame frame = { + .w = msg->w, + .h = msg->h, + .theme = msg->theme + }; + + frame_draw(&frame); +} + +static void +draw_lines(const struct message *msg) +{ + struct theme theme; + unsigned int lineh; + + /* Shallow copy theme to modify colors. */ + theme_shallow(&theme, msg->theme); + + /* Compute text size for list alignment. */ + lineh = font_height(theme.fonts[THEME_FONT_INTERFACE]); + + for (int i = 0; i < 6; ++i) { + if (!msg->text[i]) + continue; + + struct label label = { + .y = i * lineh, + .w = msg->w, + .h = msg->h, + .theme = &theme, + .text = msg->text[i], + .align = LABEL_ALIGN_TOP_LEFT, + .flags = LABEL_FLAGS_SHADOW + }; + + /* + * The function label_draw will use THEME_COLOR_NORMAL to draw + * text and THEME_COLOR_SHADOW so if we have selected a line + * we need to cheat the normal color. + */ + if (msg->flags & MESSAGE_FLAGS_QUESTION && msg->index == (unsigned int)i) + theme.colors[THEME_COLOR_NORMAL] = THEME(msg)->colors[THEME_COLOR_SELECTED]; + else + theme.colors[THEME_COLOR_NORMAL] = THEME(msg)->colors[THEME_COLOR_NORMAL]; + + label_draw(&label); + } +} + +void +message_start(struct message *msg) +{ + 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 +message_handle(struct message *msg, const union event *ev) +{ + assert(msg); + assert(ev); + + /* Skip if the message animation hasn't complete. */ + if (msg->state != MESSAGE_STATE_SHOWING) + return; + + /* Only keyboard event are valid. */ + if (ev->type != EVENT_KEYDOWN || msg->state == MESSAGE_STATE_NONE) + return; + + switch (ev->key.key) { + case KEY_UP: + if (msg->index > 0) + msg->index--; + break; + case KEY_DOWN: + if (msg->index < 5 && msg->text[msg->index + 1]) + msg->index++; + break; + case KEY_ENTER: + msg->state = msg->flags & MESSAGE_FLAGS_FADEOUT + ? MESSAGE_STATE_HIDING + : MESSAGE_STATE_NONE; + msg->elapsed = 0; + break; + default: + break; + } +} + +bool +message_update(struct message *msg, unsigned int ticks) +{ + assert(msg); + + msg->elapsed += ticks; + + switch (msg->state) { + case MESSAGE_STATE_OPENING: + msg->scale = (double)msg->elapsed / (double)msg->delay; + + if (msg->scale > 1) + msg->scale = 1; + + if (msg->elapsed >= msg->delay) { + msg->state = MESSAGE_STATE_SHOWING; + msg->elapsed = 0; + } + + break; + case MESSAGE_STATE_SHOWING: + /* Do automatically switch state if requested by the user. */ + if (msg->flags & MESSAGE_FLAGS_AUTOMATIC && msg->elapsed >= msg->timeout) { + msg->state = msg->flags & MESSAGE_FLAGS_FADEOUT + ? MESSAGE_STATE_HIDING + : MESSAGE_STATE_NONE; + msg->elapsed = 0; + } + + break; + case MESSAGE_STATE_HIDING: + msg->scale = 1 - (double)msg->elapsed / (double)msg->delay; + + if (msg->scale < 0) + msg->scale = 0; + if (msg->elapsed >= msg->delay) { + msg->state = MESSAGE_STATE_NONE; + msg->elapsed = 0; + } + + break; + default: + break; + } + + return msg->state == MESSAGE_STATE_NONE; +} + +void +message_draw(struct message *msg) +{ + assert(msg); + + struct texture tex; + int x, y; + unsigned int w, h; + + if (!texture_new(&tex, msg->w, msg->h)) + panic(); + + PAINTER_BEGIN(&tex); + draw_frame(msg); + draw_lines(msg); + PAINTER_END(); + + /* Compute scaling. */ + w = msg->w * msg->scale; + h = msg->h * msg->scale; + + /* Centerize within its drawing area. */ + maths_centerize(&x, &y, w, h, msg->x, msg->y, msg->w, msg->h); + + /* Draw and clear. */ + texture_scale(&tex, 0, 0, msg->w, msg->h, x, y, w, h, 0); + texture_finish(&tex); +} + +void +message_hide(struct message *msg) +{ + assert(msg); + + msg->state = MESSAGE_STATE_HIDING; + msg->elapsed = 0; +} + +void +message_action(struct message *msg, struct action *action) +{ + assert(msg); + assert(action); + + memset(action, 0, sizeof (struct action)); + action->data = msg; + action->handle = handle; + action->update = update; + action->draw = draw; + + message_start(msg); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/message.h Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,197 @@ +/* + * message.h -- message dialog + * + * 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_MESSAGE_H +#define MOLKO_MESSAGE_H + +/** + * \file message.h + * \brief Message dialog. + * \ingroup actions + * \ingroup drawing + * + * This module's purpose is to show a dialog box into the screen to show text + * and optionally ask the user a question. + * + * By itself, it is very low level and does not prevent other parts of the game + * to use the input so you probably need to inhibit input if your dialog is + * meant to be displayed on a map. + * + * To use it use the following procedure: + * + * 1. Create a struct message object and set required properties, + * 2. Call \ref message_start to reset the state, + * 3. Call \ref message_handle and \ref message_update with appropriate values, + * 4. Call \ref message_draw to render the dialog. + * + * Depending on message flags or user input, step 3 may return true in this + * case you should stop using the message as it has completed rendering. + * + * \note All properties must exist until the object is no longer used. + * + * \code + * struct message msg = { + * // You can show up to 6 lines. + * .text = { + * "Hello, what's up?" + * }, + * // This image will be shown on the left as user face. + * .avatar = mysuperavatar, + * // This should point to a image that is used as background. + * .frame = mysuperframe, + * // The first color is normal text, the second is for selected text + * // in case of question. + * .colors = { 0xffffffff, 0x0000ffff }, + * // This indicates this message is a question. + * .flags = MESSAGE_QUESTION + * }; + * \endcode + */ + +#include <stdbool.h> + +#include <core/texture.h> + +struct action; +struct font; +struct theme; + +union event; + +/** + * \brief Default animation speed in milliseconds. + */ +#define MESSAGE_DELAY_DEFAULT (150) + +/** + * \brief Default timeout in milliseconds for automatic messages. + */ +#define MESSAGE_TIMEOUT_DEFAULT (5000) + +/** + * \brief Message flags. + */ +enum message_flags { + MESSAGE_FLAGS_AUTOMATIC = (1 << 0), /*!< Will automatically change state by itself. */ + MESSAGE_FLAGS_QUESTION = (1 << 1), /*!< The message is a question. */ + MESSAGE_FLAGS_FADEIN = (1 << 2), /*!< Animate opening. */ + MESSAGE_FLAGS_FADEOUT = (1 << 3) /*!< Animate closing. */ +}; + +/** + * \brief Message state. + */ +enum message_state { + MESSAGE_STATE_NONE, /*!< Message hasn't start yet or is finished */ + MESSAGE_STATE_OPENING, /*!< Message animation is opening */ + MESSAGE_STATE_SHOWING, /*!< Message is displaying */ + MESSAGE_STATE_HIDING /*!< Message animation for hiding */ +}; + +/** + * \brief Message object. + * + * This structure is used to display a message into the screen. It does not own + * any user properties and therefore must exist while using it. + */ +struct message { + int x; /*!< (+) Position in x. */ + int y; /*!< (+) Position in y. */ + unsigned int w; /*!< (+) Width. */ + unsigned int h; /*!< (+) Height. */ + unsigned int delay; /*!< (+) Delay for animations. */ + unsigned int timeout; /*!< (+) Timeout in milliseconds. */ + const char *text[6]; /*!< (+) Lines of text to show. */ + struct texture *avatar; /*!< (+&?) Avatar face. */ + unsigned int index; /*!< (+) Line selected */ + enum message_flags flags; /*!< (+) Message flags */ + enum message_state state; /*!< (-) Current state */ + struct theme *theme; /*!< (+&?) Theme to use. */ + unsigned int elapsed; /*!< (-) Time elapsed. */ + double scale; /*!< (-) Current scale [0-1]. */ +}; + +/** + * Start opening the message. This function will reset the message state and + * 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 +message_start(struct message *msg); + +/** + * Handle input events. + * + * This function will alter state of the message and change its selection in + * case of question. + * + * \pre msg != NULL + * \pre ev != NULL + * \param msg the message + * \param ev the event which occured + */ +void +message_handle(struct message *msg, const union event *ev); + +/** + * Update the message state and elapsed time.. + * + * \pre msg != NULL + * \param msg the message + * \param ticks the elapsed delay since last frame + * \return true if it has finished + */ +bool +message_update(struct message *msg, unsigned int ticks); + +/** + * Draw the message into the screen. + * + * \pre msg != NULL + * \param msg the message + */ +void +message_draw(struct message *msg); + +/** + * Start hiding the message. + * + * \pre msg != NULL + * \param msg the message + * \note You should still continue to draw the message as the animation is not + * finished! + */ +void +message_hide(struct message *msg); + +/** + * Convert message into an action. + * + * \pre msg != NULL + * \pre action != NULL + * \param msg the message to reference + * \param action the action to fill + */ +void +message_action(struct message *msg, struct action *action); + +#endif /* !MOLKO_MESSAGE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/walksprite.c Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,61 @@ +/* + * walksprite.c -- sprite designed for walking entities + * + * 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 <string.h> + +#include <core/sprite.h> + +#include "walksprite.h" + +void +walksprite_init(struct walksprite *ws, struct sprite *sprite, unsigned int delay) +{ + assert(ws); + assert(sprite); + + memset(ws, 0, sizeof (struct walksprite)); + ws->sprite = sprite; + ws->delay = delay; +} + +void +walksprite_update(struct walksprite *ws, unsigned int ticks) +{ + assert(ws); + + ws->elapsed += ticks; + + if (ws->elapsed >= ws->delay) { + ws->index += 1; + + if (ws->index >= ws->sprite->ncols) + ws->index = 0; + + ws->elapsed = 0; + } +} + +void +walksprite_draw(struct walksprite *ws, unsigned int orientation, int x, int y) +{ + assert(ws); + assert(orientation < 8); + + sprite_draw(ws->sprite, orientation, ws->index, x, y); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/walksprite.h Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,103 @@ +/* + * walksprite.h -- sprite designed for walking entities + * + * 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_WALKSPRITE_H +#define MOLKO_WALKSPRITE_H + +/** + * \file walksprite.h + * \brief Sprite designed for walking entities. + * \ingroup drawing + */ + +struct sprite; + +/** + * \brief Sprite designed for walking entities. + * + * This structure works with sprite images that are defined as using the + * following conventions: + * + * ``` + * 7 0 1 + * ↖ ↑ ↗ + * 6 ← → 2 + * ↙ ↓ ↘ + * 5 4 3 + * ``` + * + * Where numbers define row in the sprite according to the character + * orientation. In other terms, your image sprite should look like this: + * + * ``` + * row columns in your image + * ---|--------------------- + * 0 | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ + * 1 | ↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗ + * 2 | →→→→→→→→→→→→→→→→→→→→ + * 3 | ↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘ + * 4 | ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ + * 5 | ↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙ + * 6 | ←←←←←←←←←←←←←←←←←←←← + * 7 | ↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖ + * ``` + */ +struct walksprite { + struct sprite *sprite; /*!< (+&) The sprite to use */ + unsigned int delay; /*!< (+) The delay between frames */ + unsigned int index; /*!< (-) Current column index */ + unsigned int elapsed; /*!< (-) Elapsed time since last frame */ +}; + +/** + * Initialize the walking sprite. + * + * \pre ws != NULL + * \pre sprite != NULL + * \param ws the walking sprite + * \param sprite the sprite to use + * \param delay the delay between sprites + */ +void +walksprite_init(struct walksprite *ws, struct sprite *sprite, unsigned int delay); + +/** + * Update the walking sprite + * + * \pre ws != NULL + * \param ws the walking sprite + * \param ticks the number of milliseconds between last frame + */ +void +walksprite_update(struct walksprite *ws, unsigned int ticks); + +/** + * Draw the appropriate sprite cell to the screen according to the orientation + * given. + * + * \pre ws != NULL + * \pre orientation < 8 + * \param ws the walking sprite + * \param orientation the orientation (or the row between 0 and 7) + * \param x the x coordinate + * \param y the y coordinate + */ +void +walksprite_draw(struct walksprite *ws, unsigned int orientation, int x, int y); + +#endif /* !MOLKO_WALKSPRITE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/CMakeLists.txt Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,46 @@ +# +# CMakeLists.txt -- CMake build system for libui +# +# 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. +# + +project(libui) + +set( + SOURCES + ${libui_SOURCE_DIR}/ui/button.c + ${libui_SOURCE_DIR}/ui/button.h + ${libui_SOURCE_DIR}/ui/checkbox.c + ${libui_SOURCE_DIR}/ui/checkbox.h + ${libui_SOURCE_DIR}/ui/debug.c + ${libui_SOURCE_DIR}/ui/debug.h + ${libui_SOURCE_DIR}/ui/frame.c + ${libui_SOURCE_DIR}/ui/frame.h + ${libui_SOURCE_DIR}/ui/label.c + ${libui_SOURCE_DIR}/ui/label.h + ${libui_SOURCE_DIR}/ui/theme.c + ${libui_SOURCE_DIR}/ui/theme.h +) + +molko_define_library( + TARGET libui + SOURCES ${SOURCES} + LIBRARIES + libcore + PUBLIC_INCLUDES + $<BUILD_INTERFACE:${libui_SOURCE_DIR}> +) + +source_group(ui FILES ${SOURCES})
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/ui/button.c Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,79 @@ +/* + * button.c -- GUI button + * + * 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 <core/event.h> +#include <core/maths.h> + +#include "button.h" +#include "theme.h" + +static bool +is_boxed(const struct button *button, const struct event_click *click) +{ + assert(button); + assert(click); + assert(click->type == EVENT_CLICKDOWN || click->type == EVENT_CLICKUP); + + return maths_is_boxed(button->x, button->y, button->w, button->h, + click->x, click->y); +} + +void +button_handle(struct button *button, const union event *ev) +{ + assert(button); + assert(ev); + + switch (ev->type) { + case EVENT_CLICKDOWN: + if (is_boxed(button, &ev->click)) + button->state = BUTTON_STATE_PRESSED; + break; + case EVENT_CLICKUP: + /* + * If the button was pressed, indicate that the button is + * finally activated. This let the user to move the cursor + * outside the button to "forget" the press. + */ + if (!is_boxed(button, &ev->click)) + button->state = BUTTON_STATE_NONE; + else if (button->state == BUTTON_STATE_PRESSED) + button->state = BUTTON_STATE_ACTIVATED; + break; + default: + break; + } +} + +void +button_reset(struct button *button) +{ + assert(button); + + button->state = BUTTON_STATE_NONE; +} + +void +button_draw(struct button *button) +{ + assert(button); + + theme_draw_button(button->theme, button); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/ui/button.h Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,85 @@ +/* + * button.h -- GUI button + * + * 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_BUTTON_H +#define MOLKO_BUTTON_H + +/** + * \file button.h + * \brief GUI button. + */ + +union event; + +struct theme; + +/** + * \brief Button state. + */ +enum button_state { + BUTTON_STATE_NONE, /*!< Button is inactive. */ + BUTTON_STATE_PRESSED, /*!< Button is currently pressed. */ + BUTTON_STATE_ACTIVATED /*!< Button is considered activated. */ +}; + +/** + * \brief GUI button. + */ +struct button { + int x; /*!< (+) Position in x. */ + int y; /*!< (+) Position in y. */ + unsigned int w; /*!< (+) Width. */ + unsigned int h; /*!< (+) Height. */ + const char *text; /*!< (+&) Text to draw. */ + enum button_state state; /*!< (+) Button state. */ + struct theme *theme; /*!< (+&?) Theme to use. */ +}; + +/** + * Handle the event. + * + * You should always call this function even if the event is completely + * unrelated. + * + * \pre button != NULL + * \pre ev != NULL + * \param button the button + * \param ev the event + */ +void +button_handle(struct button *button, const union event *ev); + +/** + * Use this function once the button has been considered activated. + * + * \pre button != NULL + * \param button the button + */ +void +button_reset(struct button *button); + +/** + * Draw the button. + * + * \pre button != NULL + * \param button the button + */ +void +button_draw(struct button *button); + +#endif /* !MOLKO_BUTTON_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/ui/checkbox.c Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,56 @@ +/* + * checkbox.c -- GUI checkbox + * + * 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 <core/event.h> +#include <core/maths.h> + +#include "checkbox.h" +#include "theme.h" + +static bool +is_boxed(const struct checkbox *cb, const struct event_click *click) +{ + assert(cb); + assert(click && click->type == EVENT_CLICKDOWN); + + return maths_is_boxed(cb->x, cb->y, cb->w, cb->h, click->x, click->y); +} + +void +checkbox_handle(struct checkbox *cb, const union event *ev) +{ + assert(cb); + assert(ev); + + switch (ev->type) { + case EVENT_CLICKDOWN: + if (is_boxed(cb, &ev->click)) + cb->checked = !cb->checked; + break; + default: + break; + } +} + +void +checkbox_draw(const struct checkbox *cb) +{ + theme_draw_checkbox(cb->theme, cb); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/ui/checkbox.h Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,64 @@ +/* + * checkbox.h -- GUI checkbox + * + * 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_CHECKBOX_H +#define MOLKO_CHECKBOX_H + +/** + * \file checkbox.h + * \brief GUI checkbox. + */ + +#include <stdbool.h> + +union event; + +/** + * \brief GUI checkbox. + */ +struct checkbox { + int x; /*!< (+) Position in x. */ + int y; /*!< (+) Position in y. */ + unsigned int w; /*!< (+) Width. */ + unsigned int h; /*!< (+) Height. */ + const char *label; /*!< (+&) Text to show. */ + bool checked; /*!< (+) Is activated? */ + struct theme *theme; /*!< (+&?) Theme to use. */ +}; + +/** + * Draw the checkbox. + * + * \pre cb != NULL + * \pre ev != NULL + * \param cb the checkbox + * \param ev the event + */ +void +checkbox_handle(struct checkbox *cb, const union event *ev); + +/** + * Draw the checkbox. + * + * \pre cb != NULL + * \param cb the checkbox + */ +void +checkbox_draw(const struct checkbox *cb); + +#endif /* !MOLKO_CHECKBOX_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/ui/debug.c Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,82 @@ +/* + * 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 <core/texture.h> + +#include "debug.h" +#include "theme.h" + +#define PADDING_X 5 +#define PADDING_Y 5 + +struct debug_options debug_options = { +#if !defined(NDEBUG) + .enable = true +#endif +}; + +void +debug_printf(struct debug_report *report, const char *fmt, ...) +{ + assert(report); + assert(fmt); + + if (!debug_options.enable) + return; + + 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); + + if (!debug_options.enable) + return; + + char line[DEBUG_LINE_MAX]; + struct theme *theme; + struct font *font; + struct texture tex; + unsigned int gapy; + + vsnprintf(line, sizeof (line), fmt, ap); + + theme = report->theme ? report->theme : theme_default(); + font = theme->fonts[THEME_FONT_DEBUG]; + font->color = report->color; + + if (!font_render(font, &tex, line)) + return; + + gapy = (PADDING_Y * (report->count)) + + (font_height(font) * (report->count)); + report->count++; + + texture_draw(&tex, PADDING_X, gapy); + texture_finish(&tex); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/ui/debug.h Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,131 @@ +/* + * 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 <core/font.h> + +/** + * Maximum content length per report. + */ +#define DEBUG_LINE_MAX 1024 + +struct theme; + +/** + * \brief Debugging options. + * + * Fill this structure with appropriate values to change debugging behavior + * in core API. + */ +struct debug_options { + bool enable; /*!< (+) Enable core API debugging. */ +}; + +/** + * \brief Debug context. + * + * Use this structure each time you need to print one or more messages. + */ +struct debug_report { + struct theme *theme; /*!< (+&?) Theme to use. */ + unsigned long color; /*!< (+) Font foreground color to use. */ + unsigned int count; /*!< (-) 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 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/ui/frame.c Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,30 @@ +/* + * frame.h -- GUI frame + * + * 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 "frame.h" +#include "theme.h" + +void +frame_draw(const struct frame *frame) +{ + assert(frame); + + theme_draw_frame(frame->theme, frame); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/ui/frame.h Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,58 @@ +/* + * frame.h -- GUI frame + * + * 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_FRAME_H +#define MOLKO_FRAME_H + +/** + * \file frame.h + * \brief GUI frame. + */ + +struct theme; + +/** + * \brief Frame style. + */ +enum frame_style { + FRAME_STYLE_NORMAL, + FRAME_STYLE_BOX +}; + +/** + * \brief GUI frame. + */ +struct frame { + int x; /*!< (+) Position in x. */ + int y; /*!< (+) Position in y. */ + unsigned int w; /*!< (+) Width. */ + unsigned int h; /*!< (+) Height. */ + enum frame_style style; /*!< (+) Frame style. */ + struct theme *theme; /*!< (+&?) Theme to use. */ +}; + +/** + * Draw the frame. + * + * \pre frame != NULL + * \param frame the frame to draw + */ +void +frame_draw(const struct frame *frame); + +#endif /* !MOLKO_FRAME_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/ui/label.c Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,36 @@ +/* + * label.c -- GUI label + * + * 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 <core/trace.h> + +#include "label.h" +#include "theme.h" + +void +label_draw(const struct label *label) +{ + assert(label); + assert(label->text); + + if (label->w == 0 || label->h == 0) + trace("label %p has null dimensions", label); + + theme_draw_label(label->theme, label); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/ui/label.h Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,87 @@ +/* + * label.h -- GUI label + * + * 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_LABEL_H +#define MOLKO_LABEL_H + +/** + * \file label.h + * \brief GUI label. + */ + +struct theme; + +/** + * \brief Label flags. + */ +enum label_flags { + LABEL_FLAGS_NONE, /*!< No flags. */ + LABEL_FLAGS_SHADOW = (1 << 0), /*!< Enable shadow. */ +}; + +/** + * \brief Label alignment in bounding box. + * + * The alignment is described as following: + * + * ``` + * +---------------------+ + * | 1 2 3 | + * | | + * | 8 0 4 | + * | | + * | 7 6 5 | + * +---------------------+ + * ``` + */ +enum label_align { + LABEL_ALIGN_CENTER, /*!< Align to the center (default). */ + LABEL_ALIGN_TOP_LEFT, /*!< Top left. */ + LABEL_ALIGN_TOP, /*!< Top center (aligned horizontally). */ + LABEL_ALIGN_TOP_RIGHT, /*!< Top right. */ + LABEL_ALIGN_RIGHT, /*!< Right (aligned vertically). */ + LABEL_ALIGN_BOTTOM_RIGHT, /*!< Bottom right. */ + LABEL_ALIGN_BOTTOM, /*!< Bottom (aligned horizontally). */ + LABEL_ALIGN_BOTTOM_LEFT, /*!< Bottom left. */ + LABEL_ALIGN_LEFT /*!< Left (aligned vertically). */ +}; + +/** + * \brief GUI label. + */ +struct label { + int x; /*!< (+) Position in x. */ + int y; /*!< (+) Position in y. */ + unsigned int w; /*!< (+) Width. */ + unsigned int h; /*!< (+) Height. */ + const char *text; /*!< (+&) Text to show. */ + enum label_flags flags; /*!< (+) Optional flags. */ + enum label_align align; /*!< (+) How to positionate label. */ + struct theme *theme; /*!< (+&?) Theme to use. */ +}; + +/** + * Draw the label. + * + * \pre label != NULL + * \param label the label to draw + */ +void +label_draw(const struct label *label); + +#endif /* !MOLKO_LABEL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/ui/theme.c Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,309 @@ +/* + * theme.c -- abstract theming + * + * 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 <string.h> + +#include <core/font.h> +#include <core/maths.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/texture.h> +#include <core/util.h> + +#include <core/assets/fonts/f25-bank-printer.h> +#include <core/assets/fonts/comic-neue.h> + +#include "button.h" +#include "checkbox.h" +#include "frame.h" +#include "label.h" +#include "theme.h" + +#define THEME(t) (t ? t : &default_theme) + +#define CHECKBOX_W 16 +#define CHECKBOX_H 16 +#define CHECKBOX_RAD 6 + +static void +box(int x, int y, unsigned int w, unsigned int h) +{ + /* Some basic outlines. */ + painter_set_color(0x4d3533ff); + + painter_draw_line(x, y, x + w, y); + painter_draw_line(x, y + h, x + w, y + h); + painter_draw_line(x, y, x, y + h); + painter_draw_line(x + w, y, x + w, y + h); +} + +static void +draw_frame(struct theme *t, const struct frame *frame) +{ + (void)t; + + if (frame->style == FRAME_STYLE_BOX) + painter_set_color(0x6e4c30ff); + else + painter_set_color(0xce9248ff); + + painter_draw_rectangle(frame->x, frame->y, frame->w, frame->h); + box(frame->x, frame->y, frame->w, frame->h); +} + +static void +draw_label(struct theme *t, const struct label *label) +{ + struct font *font; + struct texture tex; + int x, y, bx, by; + unsigned int tw, th, bw, bh; + + /* Compute real box size according to padding. */ + bx = label->x + t->padding; + by = label->y + t->padding; + bw = label->w - (t->padding * 2); + bh = label->h - (t->padding * 2); + + /* Make a shallow copy of the interface font. */ + font = t->fonts[THEME_FONT_INTERFACE]; + + /* Compute text size. */ + if (!font_box(font, label->text, &tw, &th)) + panic(); + + /* Compute position according to alignment and box. */ + switch (label->align) { + case LABEL_ALIGN_CENTER: + maths_centerize(&x, &y, tw, th, bx, by, bw, bh); + break; + case LABEL_ALIGN_TOP_LEFT: + x = bx; + y = by; + break; + case LABEL_ALIGN_TOP: + maths_centerize(&x, NULL, tw, th, bx, by, bw, bh); + y = by; + break; + case LABEL_ALIGN_TOP_RIGHT: + x = bx + bw - tw; + y = by; + break; + case LABEL_ALIGN_RIGHT: + maths_centerize(NULL, &y, tw, th, bx, by, bw, bh); + x = bx + bw - tw; + break; + case LABEL_ALIGN_BOTTOM_RIGHT: + x = bx + bw - tw; + y = by + bh - th; + break; + case LABEL_ALIGN_BOTTOM: + maths_centerize(&x, NULL, tw, th, bx, by, bw, bh); + y = by + bh - th; + break; + case LABEL_ALIGN_BOTTOM_LEFT: + x = bx; + y = by + bh - th; + break; + case LABEL_ALIGN_LEFT: + maths_centerize(NULL, &y, tw, th, bx, by, bw, bh); + x = bx; + default: + break; + } + + /* Shadow text, only if enabled. */ + if (label->flags & LABEL_FLAGS_SHADOW) { + font->color = t->colors[THEME_COLOR_SHADOW]; + + if (!font_render(font, &tex, label->text)) + panic(); + + texture_draw(&tex, x + 1, y + 1); + texture_finish(&tex); + } + + /* Normal text. */ + font->color = t->colors[THEME_COLOR_NORMAL]; + + if (!font_render(font, &tex, label->text)) + panic(); + + texture_draw(&tex, x, y); + texture_finish(&tex); +} + +static void +draw_button(struct theme *t, const struct button *button) +{ + (void)t; + + struct label label = { + .text = button->text, + .x = button->x, + .y = button->y, + .w = button->w, + .h = button->h + }; + + painter_set_color(0xabcdefff); + painter_draw_rectangle(button->x, button->y, button->w, button->h); + + label_draw(&label); + + box(button->x, button->y, button->w, button->h); +} + +static void +draw_checkbox(struct theme *t, const struct checkbox *cb) +{ + box(cb->x, cb->y, CHECKBOX_W, CHECKBOX_H); + + if (cb->checked) + painter_draw_rectangle(cb->x + 5, cb->y + 5, CHECKBOX_W - 9, CHECKBOX_H - 9); + + if (cb->label) { + const unsigned int w = cb->w - (t->padding * 2) - CHECKBOX_W; + const int x = cb->x + (t->padding * 2) + CHECKBOX_W; + + struct label label = { + .text = cb->label, + .align = LABEL_ALIGN_LEFT, + .x = x, + .y = cb->y, + .w = w, + .h = cb->h + }; + + draw_label(t, &label); + } +} + +/* Default theme. */ +static struct theme default_theme = { + .colors = { + [THEME_COLOR_NORMAL] = 0xffffffff, + [THEME_COLOR_SELECTED] = 0x006554ff, + [THEME_COLOR_SHADOW] = 0x000000ff + }, + .padding = 10, + .draw_frame = draw_frame, + .draw_label = draw_label, + .draw_button = draw_button, + .draw_checkbox = draw_checkbox +}; + +/* Default font catalog. */ +#define FONT(bin, size, index) \ + { bin, sizeof (bin), size, &default_theme.fonts[index], {0} } + +static struct font_catalog { + const unsigned char *data; + const size_t datasz; + unsigned int size; + struct font **dest; + struct font font; +} default_fonts[] = { + FONT(fonts_f25_bank_printer, 10, THEME_FONT_DEBUG), + FONT(fonts_comic_neue, 20, THEME_FONT_INTERFACE) +}; + +bool +theme_init(void) +{ + /* Open all fonts. */ + for (size_t i = 0; i < NELEM(default_fonts); ++i) { + struct font_catalog *fc = &default_fonts[i]; + + if (!font_openmem(&fc->font, fc->data, fc->datasz, fc->size)) + goto failed; + + /* Reference this font into the catalog. */ + *default_fonts[i].dest = &default_fonts[i].font; + } + + return true; + +failed: + theme_finish(); + + return false; +} + +struct theme * +theme_default(void) +{ + return &default_theme; +} + +unsigned int +theme_padding(const struct theme *t) +{ + return THEME(t)->padding; +} + +void +theme_shallow(struct theme *dst, const struct theme *src) +{ + assert(dst); + + memcpy(dst, src ? src : &default_theme, sizeof (*src)); +} + +void +theme_draw_frame(struct theme *t, const struct frame *frame) +{ + assert(frame); + + THEME(t)->draw_frame(THEME(t), frame); +} + +void +theme_draw_label(struct theme *t, const struct label *label) +{ + assert(label); + + THEME(t)->draw_label(THEME(t), label); +} + +void +theme_draw_button(struct theme *t, const struct button *button) +{ + assert(button); + + THEME(t)->draw_button(THEME(t), button); +} + +void +theme_draw_checkbox(struct theme *t, const struct checkbox *cb) +{ + assert(cb); + + THEME(t)->draw_checkbox(THEME(t), cb); +} + +void +theme_finish(void) +{ + for (size_t i = 0; i < NELEM(default_fonts); ++i) { + font_finish(&default_fonts[i].font); + *default_fonts[i].dest = NULL; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/ui/theme.h Thu Oct 15 10:32:18 2020 +0200 @@ -0,0 +1,194 @@ +/* + * theme.h -- abstract theming + * + * 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_THEME_H +#define MOLKO_THEME_H + +/** + * \file theme.h + * \brief Abstract theming. + */ + +#include <stdbool.h> + +struct checkbox; +struct button; +struct font; +struct frame; +struct label; + +/** + * \brief Font component. + */ +enum theme_font { + THEME_FONT_DEBUG, /*!< Font for debug messages. */ + THEME_FONT_INTERFACE, /*!< Font for interface elements. */ + THEME_FONT_LAST /*!< Unused. */ +}; + +/** + * \brief Theme colors. + */ +enum theme_color { + THEME_COLOR_DEBUG, /*!< Debug color font. */ + THEME_COLOR_NORMAL, /*!< Normal font color. */ + THEME_COLOR_SELECTED, /*!< Font color for selected elements. */ + THEME_COLOR_SHADOW, /*!< Shadow color. */ + THEME_COLOR_LAST /*!< Unused. */ +}; + +/** + * \brief Abstract theme structure. + */ +struct theme { + /** + * (+&) Fonts catalog. + */ + struct font *fonts[THEME_FONT_LAST]; + + /** + * (+) Miscellaneous colors. + */ + unsigned long colors[THEME_COLOR_LAST]; + + /** + * (+) Padding between GUI elements. + */ + unsigned int padding; + + /** + * (+) Draw a frame. + * + * This function is used to draw a box usually as a container where UI + * elements will be put. + * + * \see \ref theme_draw_frame + */ + void (*draw_frame)(struct theme *, const struct frame *); + + /** + * (+) Draw a label. + * + * \see \ref theme_draw_label + */ + void (*draw_label)(struct theme *, const struct label *); + + /** + * (+) Draw a button. + * + * \see \ref theme_draw_button + */ + void (*draw_button)(struct theme *, const struct button *); + + /** + * (+) Draw a checkbox. + * + * \see \ref theme_draw_button + */ + void (*draw_checkbox)(struct theme *t, const struct checkbox *); +}; + +/** + * Initialize the theming system. + * + * \return false on errors + * \warning This function must be called before any other theme functions. + */ +bool +theme_init(void); + +/** + * Get a reference to the default theme. + * + * \return A non-owning pointer to a static storage for the default theme + */ +struct theme * +theme_default(void); + +/** + * Convenient shortcut to shallow copy src into dst. + * + * Use this function when you want your own local copy of a theme because you + * want to modify some attributes. + * + * This is a shortcut to `memcpy(dst, src, sizeof (*src))`. + * + * \pre dst != NULL + * \param dst the destination theme + * \param src the source theme (may be NULL) + * \note Resources are not cloned, internal pointers will adress the same + * regions. + */ +void +theme_shallow(struct theme *dst, const struct theme *src); + +/** + * Get the desired padding between GUI elements. + * + * \param t the theme to use (may be NULL) + * \return the padding in pixels + */ +unsigned int +theme_padding(const struct theme *t); + +/** + * Draw a frame. + * + * \pre frame != NULL + * \param t the theme to use (may be NULL) + * \param frame the frame + */ +void +theme_draw_frame(struct theme *t, const struct frame *frame); + +/** + * Draw a label. + * + * \pre label != NULL + * \param t the theme to use (may be NULL) + * \param label the label + */ +void +theme_draw_label(struct theme *t, const struct label *label); + +/** + * Draw a button. + * + * \pre button != NULL + * \param t the theme to use (may be NULL) + * \param button the button + */ +void +theme_draw_button(struct theme *t, const struct button *button); + +/** + * Draw a checkbox. + * + * \param t the theme to use (may be NULL) + * \param cb the checkbox + */ +void +theme_draw_checkbox(struct theme *t, const struct checkbox *cb); + +/** + * Close associated resources. + */ +void +theme_finish(void); + +#endif /* !MOLKO_THEME_H */
--- a/molko/main.c Thu Oct 15 09:21:04 2020 +0200 +++ b/molko/main.c Thu Oct 15 10:32:18 2020 +0200 @@ -24,10 +24,11 @@ #include <core/game.h> #include <core/panic.h> #include <core/sys.h> -#include <core/theme.h> #include <core/util.h> #include <core/window.h> +#include <ui/theme.h> + #include <adventure/panic_state.h> #include <adventure/splashscreen_state.h>
--- a/tests/test-inventory.c Thu Oct 15 09:21:04 2020 +0200 +++ b/tests/test-inventory.c Thu Oct 15 10:32:18 2020 +0200 @@ -19,8 +19,8 @@ #define GREATEST_USE_ABBREVS 0 #include <greatest.h> -#include <core/item.h> -#include <core/inventory.h> +#include <rpg/item.h> +#include <rpg/inventory.h> static struct item potion = { .name = "Potion",
--- a/tests/test-map.c Thu Oct 15 09:21:04 2020 +0200 +++ b/tests/test-map.c Thu Oct 15 10:32:18 2020 +0200 @@ -20,11 +20,12 @@ #include <greatest.h> #include <core/error.h> -#include <core/map.h> #include <core/panic.h> #include <core/sys.h> #include <core/window.h> +#include <rpg/map.h> + #include <assets/maps/sample-map.h> #include <assets/maps/error-title.h> #include <assets/maps/error-width.h>