Mercurial > molko
changeset 415:a5b98db4fd87
misc: fix .hgignore too greedy
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 09 Oct 2022 13:53:33 +0200 |
parents | 6947c1fefe5c |
children | 2862526f1fc9 |
files | .hgignore examples/example-action/example-action.c examples/example-animation/example-animation.c examples/example-audio/example-audio.c examples/example-cursor/example-cursor.c examples/example-debug/example-debug.c examples/example-drawable/example-drawable.c examples/example-font/example-font.c examples/example-gridmenu/example-gridmenu.c examples/example-label/example-label.c examples/example-message/example-message.c examples/example-notify/example-notify.c examples/example-sprite/example-sprite.c examples/example-trace/example-trace.c examples/example-ui/example-ui.c src/tools/bcc/mlk-bcc.c |
diffstat | 16 files changed, 2929 insertions(+), 37 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Sun Oct 09 13:51:03 2022 +0200 +++ b/.hgignore Sun Oct 09 13:53:33 2022 +0200 @@ -29,44 +29,44 @@ ^src/libmlk-data/maps/.*\.tileset$ # Examples. -examples/example-action/example-action -examples/example-animation/example-animation -examples/example-audio/example-audio -examples/example-battle/main -examples/example-cursor/example-cursor -examples/example-debug/example-debug -examples/example-drawable/example-drawable -examples/example-font/example-font -examples/example-gridmenu/example-gridmenu -examples/example-label/example-label -examples/example-message/example-message -examples/example-notify/example-notify -examples/example-sprite/example-sprite -examples/example-trace/example-trace -examples/example-ui/example-ui -examples/example/character-john -examples/example/registry -examples/example/spell-fire -examples/example/trace_hud +^examples/example-action/example-action$ +^examples/example-animation/example-animation$ +^examples/example-audio/example-audio$ +^examples/example-battle/main$ +^examples/example-cursor/example-cursor$ +^examples/example-debug/example-debug$ +^examples/example-drawable/example-drawable$ +^examples/example-font/example-font$ +^examples/example-gridmenu/example-gridmenu$ +^examples/example-label/example-label$ +^examples/example-message/example-message$ +^examples/example-notify/example-notify$ +^examples/example-sprite/example-sprite$ +^examples/example-trace/example-trace$ +^examples/example-ui/example-ui$ +^examples/example/character-john$ +^examples/example/registry$ +^examples/example/spell-fire$ +^examples/example/trace_hud$ # Tests. -tests/test-action-script -tests/test-action -tests/test-alloc -tests/test-character -tests/test-color -tests/test-drawable -tests/test-error -tests/test-map -tests/test-save-quest -tests/test-save -tests/test-state -tests/test-tileset -tests/test-util -tests/test-vfs-directory -tests/test-vfs-zip +^tests/test-action-script$ +^tests/test-action$ +^tests/test-alloc$ +^tests/test-character$ +^tests/test-color$ +^tests/test-drawable$ +^tests/test-error$ +^tests/test-map$ +^tests/test-save-quest$ +^tests/test-save$ +^tests/test-state$ +^tests/test-tileset$ +^tests/test-util$ +^tests/test-vfs-directory$ +^tests/test-vfs-zip$ # Tools. -src/tools/bcc/mlk-bcc -src/tools/bcc/mlk-map -src/tools/bcc/mlk-tileset +^src/tools/bcc/mlk-bcc$ +^src/tools/bcc/mlk-map$ +^src/tools/bcc/mlk-tileset$
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-action/example-action.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,425 @@ +/* + * example-action.c -- example on how to use automatic actions + * + * Copyright (c) 2020-2022 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/action.h> +#include <core/action-stack.h> +#include <core/core.h> +#include <core/event.h> +#include <core/game.h> +#include <core/image.h> +#include <core/maths.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/script.h> +#include <core/sprite.h> +#include <core/state.h> +#include <core/sys.h> +#include <core/texture.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/theme.h> +#include <ui/ui.h> + +#include <rpg/message.h> +#include <rpg/rpg.h> + +#include <assets/sprites/chest.h> +#include <assets/sprites/people.h> + +#define W 1280 +#define H 720 + +#define MW (W * 0.75) +#define MX ((W / 2) - (MW / 2)) +#define MY (100) + +/* This is a stack of "parallel" events. */ +static struct action *events_actions[32]; +static struct action_stack events; + +/* This is a stack of modal events. */ +static struct action *modal_actions[32]; +static struct action_stack modal; + +/* Maximum number of states. */ +static struct state *states[1]; + +/* + * Event object for the chest to click on. + */ +static struct { + const char *text[2]; + struct message msg; + struct action msg_act; + int x; + int y; + int opened; + struct texture image; + struct sprite sprite; + struct action event; +} chest = { + .text = { + "100000 pièces.", + "Te voilà riche sale file de crevette." + }, + .msg = { + .x = MX, + .y = MY, + .w = MW, + .lines = chest.text, + .linesz = 2 + } +}; + +/* + * Event object for the guide who ask dialog with you. + * + * It is a script spawned upon click like this. + * + * [guide.event] + * | spawn + * (on click)------------------->[message 1] + * v + * [message 2] + * v + * [question 3] + * spawn v + * [response]<---------------------[check result] + * v + * [message 4/5] + */ +static struct { + struct { + const char *text[6]; + struct message msg; + struct action act; + } msgs[5]; + + /* This is the sprite and action to click on. */ + int x; + int y; + struct texture image; + struct sprite sprite; + struct action event; + + /* This is the event for the response. */ + struct action response; + + struct script script; + struct action script_act; +} guide = { + .msgs = { + { + .text = { + "Bienvenue dans ce monde Molko." + }, + .msg = { + .x = MX, + .y = MY, + .w = MW, + .delay = MESSAGE_DELAY_DEFAULT, + .flags = MESSAGE_FLAGS_FADEIN, + .lines = guide.msgs[0].text, + .linesz = 1 + }, + }, + { + .text = { + "Penses tu vraiment pouvoir me battre ?" + }, + .msg = { + .x = MX, + .y = MY, + .w = MW, + .lines = guide.msgs[1].text, + .linesz = 1 + } + }, + { + .text = { + "Non j'ai la trouille.", + "Bien sûr, je suis la légende." + }, + .msg = { + .x = MX, + .y = MY, + .w = MW, + .flags = MESSAGE_FLAGS_QUESTION, + .lines = guide.msgs[2].text, + .linesz = 2 + } + }, + + /* In case of NO. */ + { + .text = { + "Poule mouillée." + }, + .msg = { + .x = MX, + .y = MY, + .w = MW, + .lines = guide.msgs[3].text, + .linesz = 1 + } + }, + + /* In case of YES. */ + { + .text = { + "Prépare toi à souffrir." + }, + .msg = { + .x = MX, + .y = MY, + .w = MW, + .lines = guide.msgs[4].text, + .linesz = 1 + } + } + } +}; + +static int +guide_response_update(struct action *act, unsigned int ticks) +{ + /* Immediately return to get access to end. */ + (void)act; + (void)ticks; + + return 1; +} + +static void +guide_response_end(struct action *act) +{ + (void)act; + + /* We add a final response depending on the result. */ + const int index = guide.msgs[2].msg.index + 3; + + message_action(&guide.msgs[index].msg, &guide.msgs[index].act); + message_query(&guide.msgs[index].msg, NULL, &guide.msgs[index].msg.h); + action_stack_add(&modal, &guide.msgs[index].act); +} + +static void +guide_popup(void) +{ + /* Prepare the script with first 3 messages. */ + for (size_t i = 0; i < 3; ++i) { + message_action(&guide.msgs[i].msg, &guide.msgs[i].act); + message_query(&guide.msgs[i].msg, NULL, &guide.msgs[i].msg.h); + script_append(&guide.script, &guide.msgs[i].act); + } + + /* Reset the message index. */ + guide.msgs[2].msg.index = 0; + + /* This is final action that analyze user input. */ + guide.response.update = guide_response_update; + guide.response.end = guide_response_end; + script_append(&guide.script, &guide.response); + + script_action(&guide.script, &guide.script_act); + action_stack_add(&modal, &guide.script_act); +} + +static void +guide_handle(struct action *act, const union event *ev) +{ + (void)act; + + if (!action_stack_completed(&modal)) + return; + + switch (ev->type) { + case EVENT_CLICKDOWN: + if (maths_is_boxed(guide.x, guide.y, + guide.sprite.cellw, guide.sprite.cellh, + ev->click.x, ev->click.y)) + guide_popup(); + break; + default: + break; + } +} + +static void +guide_draw(struct action *act) +{ + (void)act; + + sprite_draw(&guide.sprite, 0, 0, guide.x, guide.y); +} + +static void +guide_init(void) +{ + if (image_openmem(&guide.image, assets_people, sizeof (assets_people)) < 0) + panic(); + + sprite_init(&guide.sprite, &guide.image, 48, 48); + + /* This is the global guide action. */ + guide.event.handle = guide_handle; + guide.event.draw = guide_draw; + guide.x = 200; + guide.y = 200; +} + +static void +chest_handle(struct action *act, const union event *ev) +{ + (void)act; + + if (chest.opened || !action_stack_completed(&modal)) + return; + + switch (ev->type) { + case EVENT_CLICKDOWN: + if (maths_is_boxed(chest.x, chest.y, chest.sprite.cellw, chest.sprite.cellh, + ev->click.x, ev->click.y)) { + chest.opened = 1; + message_action(&chest.msg, &chest.msg_act); + message_query(&chest.msg, NULL, &chest.msg.h); + action_stack_add(&modal, &chest.msg_act); + } + default: + break; + } +} + +static void +chest_draw(struct action *act) +{ + (void)act; + + const int row = chest.opened ? chest.sprite.nrows - 1 : 0; + const int col = chest.opened ? chest.sprite.ncols - 1 : 0; + + sprite_draw(&chest.sprite, row, col, chest.x, chest.y); +} + +static void +chest_init(void) +{ + if (image_openmem(&chest.image, assets_chest, sizeof (assets_chest)) < 0) + panic(); + + sprite_init(&chest.sprite, &chest.image, 32, 32); + + chest.x = 100; + chest.y = 100; + chest.event.handle = chest_handle; + chest.event.draw = chest_draw; +} + +static void +init(void) +{ + if (core_init("fr.malikania", "example-action") < 0 || ui_init() < 0 || rpg_init() < 0) + panic(); + if (window_open("Example - Action", W, H) < 0) + panic(); + + guide_init(); + chest_init(); +} + +static void +handle(struct state *st, const union event *ev) +{ + (void)st; + + switch (ev->type) { + case EVENT_QUIT: + game_quit(); + break; + default: + action_stack_handle(&events, ev); + action_stack_handle(&modal, ev); + break; + } +} + +static void +update(struct state *st, unsigned int ticks) +{ + (void)st; + + action_stack_update(&events, ticks); + action_stack_update(&modal, ticks); +} + +static void +draw(struct state *st) +{ + (void)st; + + painter_set_color(0xffffffff); + painter_clear(); + action_stack_draw(&events); + action_stack_draw(&modal); + painter_present(); +} + +static void +run(void) +{ + struct state state = { + .handle = handle, + .update = update, + .draw = draw + }; + + action_stack_init(&modal, modal_actions, UTIL_SIZE(modal_actions)); + + action_stack_init(&events, events_actions, UTIL_SIZE(events_actions)); + action_stack_add(&events, &chest.event); + action_stack_add(&events, &guide.event); + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); +} + +static void +quit(void) +{ + window_finish(); + rpg_finish(); + ui_finish(); + core_finish(); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-animation/example-animation.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,148 @@ +/* + * example-animation.c -- example on how to use animations + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <core/animation.h> +#include <core/core.h> +#include <core/event.h> +#include <core/game.h> +#include <core/image.h> +#include <core/sys.h> +#include <core/window.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/sprite.h> +#include <core/state.h> +#include <core/texture.h> +#include <core/util.h> + +#include <ui/label.h> +#include <ui/ui.h> + +#include <assets/sprites/numbers.h> + +#define W 1280 +#define H 720 + +static struct label label = { + .text = "Keys: <Space> start or reset the animation.", + .x = 10, + .y = 10, + .flags = LABEL_FLAGS_SHADOW +}; + +static struct state *states[1]; +static struct texture numbers; +static struct animation animation; +static struct sprite sprite; +static int completed = 1; + +static void +init(void) +{ + if (core_init("fr.malikania", "example-animation") < 0 || ui_init() < 0) + panic(); + if (window_open("Example - Animation", W, H) < 0) + panic(); + if (image_openmem(&numbers, assets_numbers, sizeof (assets_numbers)) < 0) + panic(); +} + +static void +handle(struct state *st, const union event *ev) +{ + (void)st; + + switch (ev->type) { + case EVENT_KEYDOWN: + switch (ev->key.key) { + case KEY_SPACE: + animation_start(&animation); + completed = animation_completed(&animation); + break; + default: + break; + } + break; + case EVENT_QUIT: + game_quit(); + break; + default: + break; + } +} + +static void +update(struct state *st, unsigned int ticks) +{ + (void)st; + + if (!completed) + completed = animation_update(&animation, ticks); +} + +static void +draw(struct state *st) +{ + (void)st; + + painter_set_color(0x4f8fbaff); + painter_clear(); + label_draw(&label); + + if (!completed) + animation_draw(&animation, (window.w - sprite.cellw) / 2, (window.h - sprite.cellh) / 2); + + painter_present(); +} + +static void +run(void) +{ + struct state state = { + .handle = handle, + .update = update, + .draw = draw + }; + + sprite_init(&sprite, &numbers, 48, 48); + animation_init(&animation, &sprite, 1000); + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); +} + +static void +quit(void) +{ + window_finish(); + ui_finish(); + core_finish(); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-audio/example-audio.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,155 @@ +/* + * example-audio.c -- show how to use sounds and music + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <core/core.h> +#include <core/event.h> +#include <core/game.h> +#include <core/music.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/sound.h> +#include <core/state.h> +#include <core/sys.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/label.h> +#include <ui/theme.h> +#include <ui/ui.h> + +#include <assets/music/vabsounds-romance.h> +#include <assets/sounds/fire.h> + +#define W 1280 +#define H 720 + +static struct state *states[1]; +static struct music music; +static struct sound sound; + +static struct label label_music = { + .text = "Music: <Space> play, <p> pause, <r> resume, <q> stop, <l> loop.", + .x = 10, + .y = 10, + .flags = LABEL_FLAGS_SHADOW +}; + +static struct label label_sound = { + .text = "Sound: click anywhere to pop a sound.", + .x = 10, + .y = 30, + .flags = LABEL_FLAGS_SHADOW +}; + +static void +init(void) +{ + if (core_init("fr.malikania", "example-audio") < 0 || ui_init() < 0) + panic(); + if (window_open("Example - Audio", W, H) < 0) + panic(); + if (music_openmem(&music, assets_vabsounds_romance, sizeof (assets_vabsounds_romance)) < 0 || + sound_openmem(&sound, assets_fire, sizeof (assets_fire)) < 0) + panic(); +} + +static void +quit(void) +{ + window_finish(); + ui_finish(); + core_finish(); +} + +static void +handle(struct state *st, const union event *ev) +{ + (void)st; + + switch (ev->type) { + case EVENT_CLICKDOWN: + if (sound_play(&sound) < 0) + panic(); + break; + case EVENT_KEYDOWN: + switch (ev->key.key) { + case KEY_p: + music_pause(&music); + break; + case KEY_r: + music_resume(&music); + break; + case KEY_q: + music_stop(&music); + break; + case KEY_l: + music_play(&music, MUSIC_LOOP); + break; + case KEY_SPACE: + music_play(&music, 0); + break; + default: + break; + } + break; + case EVENT_QUIT: + game_quit(); + break; + default: + break; + } +} + +static void +draw(struct state *st) +{ + (void)st; + + painter_set_color(0x006554ff); + painter_clear(); + label_draw(&label_music); + label_draw(&label_sound); + painter_present(); +} + +static void +run(void) +{ + struct state state = { + .handle = handle, + .draw = draw + }; + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); + + music_finish(&music); + sound_finish(&sound); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-cursor/example-cursor.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,148 @@ +/* + * example-cursor.c -- example on how to change cursor + * + * Copyright (c) 2020-2022 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/core.h> +#include <core/event.h> +#include <core/game.h> +#include <core/key.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/state.h> +#include <core/sys.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/label.h> +#include <ui/ui.h> + +#define W 1280 +#define H 720 + +static struct state *states[1]; +static char help_text[128]; +static enum window_cursor cursor = WINDOW_CURSOR_ARROW; + +static struct label help = { + .x = 10, + .y = 10, + .text = help_text, + .flags = LABEL_FLAGS_SHADOW +}; + +static void +init(void) +{ + if (core_init("fr.malikania", "example-cursor") < 0 || ui_init() < 0) + panic(); + if (window_open("Example - Cursor", W, H) < 0) + panic(); +} + +static void +change(enum window_cursor cursor) +{ + static const char *names[] = { + [WINDOW_CURSOR_ARROW] = "WINDOW_CURSOR_ARROW", + [WINDOW_CURSOR_EDIT] = "WINDOW_CURSOR_EDIT", + [WINDOW_CURSOR_WAIT] = "WINDOW_CURSOR_WAIT", + [WINDOW_CURSOR_CROSSHAIR] = "WINDOW_CURSOR_CROSSHAIR", + [WINDOW_CURSOR_SIZE] = "WINDOW_CURSOR_SIZE", + [WINDOW_CURSOR_NO] = "WINDOW_CURSOR_NO", + [WINDOW_CURSOR_HAND] = "WINDOW_CURSOR_HAND" + }; + + snprintf(help_text, sizeof (help_text), "Keys: <Left>/<Right> to change cursor. Current: %s", names[cursor]); + window_set_cursor(cursor); +} + +static void +handle(struct state *st, const union event *ev) +{ + (void)st; + + switch (ev->type) { + case EVENT_KEYDOWN: + switch (ev->key.key) { + case KEY_LEFT: + if (cursor > 0) + change(--cursor); + break; + case KEY_RIGHT: + if (cursor + 1 < WINDOW_CURSOR_LAST) + change(++cursor); + break; + default: + break; + } + + + break; + case EVENT_QUIT: + game_quit(); + break; + default: + break; + } +} + +static void +draw(struct state *st) +{ + (void)st; + + painter_set_color(0xebede9ff); + painter_clear(); + label_draw(&help); + painter_present(); +} + +static void +run(void) +{ + struct state state = { + .handle = handle, + .draw = draw + }; + + change(cursor); + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); +} + +static void +quit(void) +{ + window_finish(); + ui_finish(); + core_finish(); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-debug/example-debug.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,113 @@ +/* + * example-debug.c -- example on how to use debug interface + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <core/core.h> +#include <core/event.h> +#include <core/game.h> +#include <core/window.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/state.h> +#include <core/util.h> + +#include <ui/debug.h> +#include <ui/theme.h> +#include <ui/ui.h> + +#define W 1280 +#define H 720 + +static struct state *states[1]; +static int mouse_x; +static int mouse_y; + +static void +init(void) +{ + if (core_init("fr.malikania", "example-debug") < 0 || ui_init() < 0) + panic(); + if (window_open("Example - Debug", W, H) < 0) + panic(); + + debug_options.enable = 1; +} + +static void +handle(struct state *st, const union event *ev) +{ + (void)st; + + switch (ev->type) { + case EVENT_MOUSE: + mouse_x = ev->mouse.x; + mouse_y = ev->mouse.y; + break; + case EVENT_QUIT: + game_quit(); + break; + default: + break; + } +} + +static void +draw(struct state *st) +{ + (void)st; + + struct debug_report report = {0}; + + painter_set_color(0x4f8fbaff); + painter_clear(); + debugf(&report, "Game running."); + debugf(&report, "mouse: %d, %d", mouse_x, mouse_y); + painter_present(); +} + +static void +run(void) +{ + struct state state = { + .handle = handle, + .draw = draw + }; + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); +} + +static void +quit(void) +{ + window_finish(); + ui_finish(); + core_finish(); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-drawable/example-drawable.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,208 @@ +/* + * example-drawable.c -- example on how to use automatic drawables + * + * Copyright (c) 2020-2022 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 <stdlib.h> + +#include <core/alloc.h> +#include <core/animation.h> +#include <core/core.h> +#include <core/event.h> +#include <core/game.h> +#include <core/drawable.h> +#include <core/drawable-stack.h> +#include <core/key.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/sys.h> +#include <core/image.h> +#include <core/sprite.h> +#include <core/state.h> +#include <core/texture.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/label.h> +#include <ui/theme.h> +#include <ui/ui.h> + +#include <assets/sprites/explosion.h> + +#define W 1280 +#define H 720 + +static struct label help = { + .x = 10, + .y = 10, + .text = "Keys: <Esc> to reset. Click anywhere to spawn a drawable.", + .flags = LABEL_FLAGS_SHADOW +}; + +static struct state *states[1]; +static struct drawable *drawables[64]; +static struct drawable_stack stack; + +/* + * List of drawables for this example. + * ----------------------------------------------------------------------------- + */ + +/* 0: Explosion animation. */ +static struct texture explosion_tex; +static struct sprite explosion_sprite; + +struct explosion { + struct animation anim; + struct drawable dw; +}; + +static void +init(void) +{ + if (core_init("fr.malikania", "example-drawable") < 0 || ui_init() < 0) + panic(); + if (window_open("Example - Drawable", W, H) < 0) + panic(); + + /* 0: Explosion animation. */ + if (image_openmem(&explosion_tex, assets_explosion, sizeof (assets_explosion)) < 0) + panic(); + + sprite_init(&explosion_sprite, &explosion_tex, 256, 256); +} + +static int +explosion_update(struct drawable *dw, unsigned int ticks) +{ + struct explosion *ex = dw->data; + + return animation_update(&ex->anim, ticks); +} + +static void +explosion_draw(struct drawable *dw) +{ + struct explosion *ex = dw->data; + + animation_draw(&ex->anim, ex->dw.x, ex->dw.y); +} + +static void +explosion_finish(struct drawable *dw) +{ + free(dw->data); +} + +static void +spawn(int x, int y) +{ + struct explosion *ex = alloc_new0(sizeof (*ex)); + + animation_init(&ex->anim, &explosion_sprite, 15); + + ex->dw.data = ex; + ex->dw.x = x - (int)(explosion_sprite.cellw / 2); + ex->dw.y = y - (int)(explosion_sprite.cellh / 2); + ex->dw.update = explosion_update; + ex->dw.draw = explosion_draw; + ex->dw.finish = explosion_finish; + + drawable_stack_add(&stack, &ex->dw); +} + +static void +handle(struct state *st, const union event *ev) +{ + (void)st; + + switch (ev->type) { + case EVENT_KEYDOWN: + switch (ev->key.key) { + case KEY_ESCAPE: + drawable_stack_finish(&stack); + break; + default: + break; + } + break; + case EVENT_CLICKDOWN: + spawn(ev->click.x, ev->click.y); + break; + case EVENT_QUIT: + game_quit(); + break; + default: + break; + } +} + +static void +update(struct state *st, unsigned int ticks) +{ + (void)st; + + drawable_stack_update(&stack, ticks); + +} + +static void +draw(struct state *st) +{ + (void)st; + + painter_set_color(0xebede9ff); + painter_clear(); + label_draw(&help); + drawable_stack_draw(&stack); + painter_present(); +} + +static void +run(void) +{ + struct state state = { + .handle = handle, + .update = update, + .draw = draw + }; + + drawable_stack_init(&stack, drawables, UTIL_SIZE(drawables)); + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); +} + +static void +quit(void) +{ + window_finish(); + ui_finish(); + core_finish(); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-font/example-font.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,148 @@ +/* + * example-font.c -- show how to use fonts + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <core/core.h> +#include <core/event.h> +#include <core/font.h> +#include <core/game.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/state.h> +#include <core/sys.h> +#include <core/texture.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/theme.h> +#include <ui/ui.h> + +#define W (1280) +#define H (720) + +/* Friendly taken from: https://lospec.com/palette-list/apollo */ +static const unsigned long colors[] = { + 0x3c5e8bff, /* Blue. */ + 0x468232ff, /* Green. */ + 0xad7757ff, /* Light brown. */ + 0x884b2bff, /* Brown. */ + 0x752438ff, /* Red. */ + 0x7a367bff, /* Magenta. */ + 0x151d28ff, /* Dark */ + 0xc7cfccff, /* Christian Grey. */ +}; + +static struct state *states[1]; +static int ci = 0; +static enum font_style style = FONT_STYLE_ANTIALIASED; + +static void +init(void) +{ + if (core_init("fr.malikania", "example-font") < 0 || ui_init() < 0) + panic(); + if (window_open("Example - Font", W, H) < 0) + panic(); +} + +static void +handle(struct state *st, const union event *ev) +{ + (void)st; + + switch (ev->type) { + case EVENT_KEYDOWN: + switch (ev->key.key) { + case KEY_LEFT: + if (ci > 0) + ci--; + break; + case KEY_RIGHT: + if ((size_t)ci < UTIL_SIZE(colors)) + ci++; + break; + case KEY_SPACE: + if (style == FONT_STYLE_ANTIALIASED) + style = FONT_STYLE_NONE; + else + style = FONT_STYLE_ANTIALIASED; + + theme_default()->fonts[THEME_FONT_INTERFACE]->style = style; + default: + break; + } + break; + case EVENT_QUIT: + game_quit(); + break; + default: + break; + } +} + +static void +draw(struct state *st) +{ + (void)st; + + struct font *font = theme_default()->fonts[THEME_FONT_INTERFACE]; + struct texture tex; + + painter_set_color(0xffffffff); + painter_clear(); + + if (font_render(font, &tex, "Example of text. Use <Left>/<Right> to change color and <Space> to toggle antialiasing.", colors[ci]) < 0) + panic(); + + texture_draw(&tex, 10, 10); + painter_present(); + texture_finish(&tex); +} + +static void +run(void) +{ + struct state state = { + .handle = handle, + .draw = draw + }; + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); +} + +static void +quit(void) +{ + window_finish(); + ui_finish(); + core_finish(); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-gridmenu/example-gridmenu.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,132 @@ +/* + * example-gridmenu.c -- show how to use grid menu + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <core/core.h> +#include <core/event.h> +#include <core/game.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/state.h> +#include <core/sys.h> +#include <core/trace.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/align.h> +#include <ui/gridmenu.h> +#include <ui/label.h> +#include <ui/theme.h> +#include <ui/ui.h> + +#define W (1280) +#define H (720) + +static struct state *states[1]; + +static void +init(void) +{ + if (core_init("fr.malikania", "example-gridmenu") < 0 || ui_init() < 0) + panic(); + if (window_open("Example - Grid menu", W, H) < 0) + panic(); +} + +static void +quit(void) +{ + window_finish(); + ui_finish(); + core_finish(); +} + +static void +handle(struct state *st, const union event *ev) +{ + struct gridmenu *menu = st->data; + + switch (ev->type) { + case EVENT_QUIT: + game_quit(); + break; + default: + if (gridmenu_handle(st->data, ev)) + tracef("selected index: %zu (%s)", menu->selected, menu->items[menu->selected]); + break; + } +} + +static void +draw(struct state *st) +{ + painter_set_color(0x4f8fbaff); + painter_clear(); + gridmenu_draw(st->data); + painter_present(); +} + +static void +run(void) +{ + const char * const items[] = { + "Feu mineur", + "Feu majeur", + "Feu septième", + "Glace mineure", + "Glace majeure", + "Glace septième", + "Foudre mineure", + "Foudre majeure", + "Foudre septième", + "Choc mineur", + "Choc majeur", + "Choc septième", + "Portée", + "Escapade", + "Destruction", + "Résurrection", + "Double tour" + }; + + struct gridmenu menu = {0}; + struct state state = { + .data = &menu, + .handle = handle, + .draw = draw, + }; + + gridmenu_init(&menu, 3, 2, items, UTIL_SIZE(items)); + gridmenu_resize(&menu, 0, 0, 300, 100); + + align(ALIGN_CENTER, &menu.x, &menu.y, menu.w, menu.h, 0, 0, W, H); + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-label/example-label.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,186 @@ +/* + * example-label.c -- show how to use label and alignments + * + * Copyright (c) 2020-2022 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 <stddef.h> + +#include <core/core.h> +#include <core/event.h> +#include <core/game.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/state.h> +#include <core/sys.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/align.h> +#include <ui/label.h> +#include <ui/theme.h> +#include <ui/ui.h> + +#define W (1280) +#define H (720) + +struct { + enum align align; + struct label label; +} table[] = { + { + .align = ALIGN_TOP_LEFT, + .label = { + .text = "Top left" + } + }, + { + .align = ALIGN_TOP, + .label = { + .text = "Top", + } + }, + { + .align = ALIGN_TOP_RIGHT, + .label = { + .text = "Top right", + } + }, + { + .align = ALIGN_RIGHT, + .label = { + .text = "Right", + } + }, + { + .align = ALIGN_BOTTOM_RIGHT, + .label = { + .text = "Bottom right", + } + }, + { + .align = ALIGN_BOTTOM, + .label = { + .text = "Bottom", + } + }, + { + .align = ALIGN_BOTTOM_LEFT, + .label = { + .text = "Bottom left", + } + }, + { + .align = ALIGN_LEFT, + .label = { + .text = "Left", + } + }, + { + .align = ALIGN_CENTER, + .label = { + .text = "The world is Malikania.", + .flags = LABEL_FLAGS_SHADOW + } + } +}; + +static struct label mlabel = { + .text = "This one follows your mouse and is not aligned." +}; + +static struct state *states[1]; + +static void +init(void) +{ + if (core_init("fr.malikania", "example-label") < 0 || ui_init() < 0) + panic(); + if (window_open("Example - Label", W, H) < 0) + panic(); + + for (size_t i = 0; i < UTIL_SIZE(table); ++i) { + struct label *l = &table[i].label; + unsigned int w, h; + + label_query(l, &w, &h); + align(table[i].align, &l->x, &l->y, w, h, 0, 0, W, H); + } +} + +static void +quit(void) +{ + window_finish(); + ui_finish(); + core_finish(); +} + +static void +handle(struct state *st, const union event *ev) +{ + (void)st; + + switch (ev->type) { + case EVENT_MOUSE: + mlabel.x = ev->mouse.x; + mlabel.y = ev->mouse.y; + break; + case EVENT_QUIT: + game_quit(); + break; + default: + break; + } +} + +static void +draw(struct state *st) +{ + (void)st; + + painter_set_color(0x4f8fbaff); + painter_clear(); + + for (size_t i = 0; i < UTIL_SIZE(table); ++i) + label_draw(&table[i].label); + + label_draw(&mlabel); + painter_present(); +} + +static void +run(void) +{ + struct state state = { + .handle = handle, + .draw = draw + }; + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-message/example-message.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,350 @@ +/* + * example-message.c -- show how to use messages + * + * Copyright (c) 2020-2022 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 <stddef.h> + +#include <core/core.h> +#include <core/event.h> +#include <core/game.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/state.h> +#include <core/sys.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/frame.h> +#include <ui/theme.h> +#include <ui/ui.h> + +#include <rpg/message.h> +#include <rpg/rpg.h> + +#define W (1280) +#define H (720) + +#define MW (W * 0.75) +#define MH (H * 0.120) +#define MX ((W / 2) - (MW / 2)) +#define MY (100) + +static struct state *states[1]; + +static void +init(void) +{ + if (core_init("fr.malikania", "example-message") < 0 || ui_init() < 0 || rpg_init() < 0) + panic(); + if (window_open("Example - Message", W, H) < 0) + panic(); +} + +static void +quit(void) +{ + window_finish(); + rpg_finish(); + ui_finish(); + core_finish(); +} + +static void +handle(struct state *st, const union event *ev) +{ + switch (ev->type) { + case EVENT_QUIT: + game_quit(); + break; + default: + message_handle(st->data, ev); + break; + } +} + +static void +update(struct state *st, unsigned int ticks) +{ + if (message_update(st->data, ticks)) + game_quit(); +} + +static void +draw(struct state *st) +{ + painter_set_color(0xffffffff); + painter_clear(); + message_draw(st->data); + painter_present(); +} + +static void +run(struct message *msg) +{ + struct state state = { + .data = msg, + .handle = handle, + .update = update, + .draw = draw + }; + + message_start(msg); + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); +} + +static void +my_draw_frame(const struct theme *th, const struct frame *f) +{ + (void)th; + + painter_set_color(0xff0000ff); + painter_draw_rectangle(f->x, f->y, f->w, f->h); +} + +static void +basic(void) +{ + const char * const text[] = { + "This is a basic message.", + "Vertical spacing is automatically computed.", + "You need to press <Enter> to close it.", + }; + struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .spacing = 12, + .lines = text, + .linesz = 3 + }; + + message_query(&msg, NULL, &msg.h); + run(&msg); +} + +static void +automatic(void) +{ + const char * const text[] = { + "This is a an automatic message.", + "It will disappear in a few seconds.", + "You can still press <Enter> to close it quicker." + }; + struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .timeout = MESSAGE_TIMEOUT_DEFAULT, + .lines = text, + .linesz = 3, + .flags = MESSAGE_FLAGS_AUTOMATIC + }; + + message_query(&msg, NULL, &msg.h); + run(&msg); +} + +static void +fadein(void) +{ + const char * const text[] = { + "This message will fade in." + }; + struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .delay = MESSAGE_DELAY_DEFAULT, + .lines = text, + .linesz = 1, + .flags = MESSAGE_FLAGS_FADEIN + }; + + message_query(&msg, NULL, &msg.h); + run(&msg); +} + +static void +fadeout(void) +{ + const char * const text[] = { + "This message will fade out." + }; + struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .delay = MESSAGE_DELAY_DEFAULT, + .lines = text, + .linesz = 1, + .flags = MESSAGE_FLAGS_FADEOUT + }; + + message_query(&msg, NULL, &msg.h); + run(&msg); +} + +static void +fade(void) +{ + const char * const text[] = { + "This message will fade in and out." + }; + struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .delay = MESSAGE_DELAY_DEFAULT, + .lines = text, + .linesz = 1, + .flags = MESSAGE_FLAGS_FADEIN | MESSAGE_FLAGS_FADEOUT + }; + + message_query(&msg, NULL, &msg.h); + run(&msg); +} + +static void +question(void) +{ + const char * const text[] = { + "Okay, I've understood.", + "Nevermind, I'll do it again." + }; + struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .lines = text, + .linesz = 2, + .flags = MESSAGE_FLAGS_QUESTION + }; + + message_query(&msg, NULL, &msg.h); + run(&msg); +} + +static void +smallbottom(void) +{ + const unsigned int w = window.w / 4; + const unsigned int h = MH; + const int x = (window.w / 2) - (w / 2); + const int y = (window.h - h - 10); + const char * const text[] = { + "This one is small here." + }; + + struct message msg = { + .x = x, + .y = y, + .w = w, + .h = h, + .delay = MESSAGE_DELAY_DEFAULT, + .flags = MESSAGE_FLAGS_FADEIN | MESSAGE_FLAGS_FADEOUT, + .lines = text, + .linesz = 1 + }; + + run(&msg); +} + +static void +toosmallh(void) +{ + const char * const text[] = { + "This one is too small in height and will emit a warning.", + "Because this line will be incomplete." + }; + struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .h = 40, + .lines = text, + .linesz = 2 + }; + + run(&msg); +} + +static void +toosmallw(void) +{ + const char * const text[] = { + "This one is too small in width." + }; + struct message msg = { + .x = MX, + .y = MY, + .w = 160, + .h = MH, + .lines = text, + .linesz = 1 + }; + + run(&msg); +} + +static void +custom(void) +{ + const char * const text[] = { + "This one will destroy your eyes.", + "Because it use a terrible custom theme." + }; + struct theme theme; + struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .h = MH, + .lines = text, + .linesz = 2, + .theme = &theme + }; + + /* Borrow default theme and change its frame drawing. */ + theme_shallow(&theme, NULL); + theme.draw_frame = my_draw_frame; + theme.colors[THEME_COLOR_NORMAL] = 0x0000ffff; + + run(&msg); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + basic(); + fadein(); + fadeout(); + fade(); + automatic(); + question(); + smallbottom(); + toosmallh(); + toosmallw(); + custom(); + quit(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-notify/example-notify.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,133 @@ +/* + * example-notify -- show how notifications work + * + * Copyright (c) 2020-2022 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/core.h> +#include <core/event.h> +#include <core/game.h> +#include <core/image.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/state.h> +#include <core/texture.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/notify.h> +#include <ui/label.h> +#include <ui/ui.h> + +/* Sword by Icongeek26 (https://www.flaticon.com). */ +#include <assets/images/sword.h> + +#define W 1280 +#define H 720 + +static struct label help = { + .text = "Keys: <Space> to generate a notification.", + .x = 10, + .y = 10, + .flags = LABEL_FLAGS_SHADOW +}; +static struct texture icon; +static struct state *states[1]; + +static void +init(void) +{ + if (core_init("fr.malikania", "example-notify") < 0 || ui_init() < 0) + panic(); + if (window_open("Example - Notify", W, H) < 0) + panic(); + if (image_openmem(&icon, assets_sword, sizeof (assets_sword)) < 0) + panic(); +} + +static void +handle(struct state *st, const union event *ev) +{ + (void)st; + + switch (ev->type) { + case EVENT_QUIT: + game_quit(); + break; + case EVENT_KEYDOWN: + if (ev->key.key == KEY_SPACE) + notify(&icon, "Quest", "Quest finished."); + break; + default: + break; + } +} + +static void +update(struct state *st, unsigned int ticks) +{ + (void)st; + + notify_update(ticks); +} + +static void +draw(struct state *st) +{ + (void)st; + + painter_set_color(0xffffffff); + painter_clear(); + label_draw(&help); + notify_draw(); + painter_present(); +} + +static void +run(void) +{ + struct state state = { + .handle = handle, + .update = update, + .draw = draw + }; + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); +} + +static void +quit(void) +{ + window_finish(); + ui_finish(); + core_finish(); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-sprite/example-sprite.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,164 @@ +/* + * example-sprite.c -- example on how to use sprites + * + * Copyright (c) 2020-2022 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/core.h> +#include <core/event.h> +#include <core/game.h> +#include <core/image.h> +#include <core/key.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/image.h> +#include <core/sprite.h> +#include <core/state.h> +#include <core/sys.h> +#include <core/texture.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/align.h> +#include <ui/label.h> +#include <ui/ui.h> + +#include <assets/sprites/people.h> + +#define W 1280 +#define H 720 +#define HEADER "Keys: <Left>/<Right> and <Up/Down> to select a column/row. Current: %u, %u (total %u/%u)" + +static char msg[512]; +static struct texture texture; +static struct sprite sprite; +static unsigned int row, column; +static struct state *states[1]; + +static struct label help = { + .x = 10, + .y = 10, + .text = msg, + .flags = LABEL_FLAGS_SHADOW +}; + +static void +changed(void) +{ + snprintf(msg, sizeof (msg), HEADER, column, row, sprite.ncols, sprite.nrows); +} + +static void +init(void) +{ + if (core_init("fr.malikania", "example-sprite") < 0 || ui_init() < 0) + panic(); + if (window_open("Example - Sprite", W, H) < 0) + panic(); + if (image_openmem(&texture, assets_people, sizeof (assets_people)) < 0) + panic(); + + sprite_init(&sprite, &texture, 48, 48); +} + +static void +handle(struct state *st, const union event *ev) +{ + (void)st; + + switch (ev->type) { + case EVENT_KEYDOWN: + switch (ev->key.key) { + case KEY_LEFT: + if (column > 0) + column--; + break; + case KEY_RIGHT: + if (column + 1 < sprite.ncols) + column++; + break; + case KEY_UP: + if (row > 0) + row--; + break; + case KEY_DOWN: + if (row + 1 < sprite.nrows) + row++; + break; + default: + break; + } + + changed(); + break; + case EVENT_QUIT: + game_quit(); + break; + default: + break; + } +} + +static void +draw(struct state *st) +{ + (void)st; + + int x, y; + + painter_set_color(0xebede9ff); + painter_clear(); + align(ALIGN_CENTER, &x, &y, sprite.cellw, sprite.cellh, 0, 0, W, H); + sprite_draw(&sprite, row, column, x, y); + label_draw(&help); + painter_present(); +} + +static void +run(void) +{ + struct state state = { + .handle = handle, + .draw = draw + }; + + changed(); + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); +} + +static void +quit(void) +{ + texture_finish(&texture); + window_finish(); + ui_finish(); + core_finish(); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-trace/example-trace.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,129 @@ +/* + * example-trace.c -- example on how to use custom trace handlers + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <core/core.h> +#include <core/event.h> +#include <core/game.h> +#include <core/sys.h> +#include <core/window.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/state.h> +#include <core/trace.h> +#include <core/util.h> + +#include <ui/theme.h> +#include <ui/ui.h> + +#include "trace_hud.h" + +#define W 1280 +#define H 720 + +static struct state *states[1]; + +static void +init(void) +{ + if (core_init("fr.malikania", "example-trace") < 0 || ui_init() < 0) + panic(); + if (window_open("Example - Trace", W, H) < 0) + panic(); + + trace_handler = trace_hud_handler; +} + +static void +handle(struct state *st, const union event *ev) +{ + (void)st; + + switch (ev->type) { + case EVENT_KEYDOWN: + switch (ev->key.key) { + case KEY_ESCAPE: + trace_hud_clear(); + break; + default: + tracef("keydown pressed: %d", ev->key.key); + break; + } + break; + case EVENT_CLICKDOWN: + tracef("click at %d,%d", ev->click.x, ev->click.y); + break; + case EVENT_QUIT: + game_quit(); + break; + default: + break; + } +} + +static void +update(struct state *st, unsigned int ticks) +{ + (void)st; + + trace_hud_update(ticks); +} + +static void +draw(struct state *st) +{ + (void)st; + + painter_set_color(0x4f8fbaff); + painter_clear(); + trace_hud_draw(); + painter_present(); +} + +static void +run(void) +{ + struct state state = { + .handle = handle, + .update = update, + .draw = draw + }; + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); +} + +static void +quit(void) +{ + window_finish(); + ui_finish(); + core_finish(); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-ui/example-ui.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,288 @@ +/* + * example-action.c -- example on how to use automatic actions + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <core/core.h> +#include <core/event.h> +#include <core/game.h> +#include <core/maths.h> +#include <core/panic.h> +#include <core/painter.h> +#include <core/state.h> +#include <core/sys.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/align.h> +#include <ui/button.h> +#include <ui/checkbox.h> +#include <ui/frame.h> +#include <ui/label.h> +#include <ui/theme.h> +#include <ui/ui.h> + +#define W (1280) +#define H (720) + +#define FRAME_ORIGIN_X (10) +#define FRAME_ORIGIN_Y (10) +#define FRAME_WIDTH (400) +#define FRAME_HEIGHT (200) + +#define HEADER_HEIGHT (32) + +#define ELEMENT_HEIGHT (20) + +/* + * We design a basic UI like this. + * + * FRAME_WIDTH + * +---------------------------------------------+-- + * | Title | | HEADER_HEIGHT + * +---------------------------------------------+-- + * | [x] Auto save | + * | | + * | | + * | [ Quit ] | + * +---------------------------------------------+ + */ +static struct { + struct { + int active; + int x; + int y; + } motion; + + struct { + struct frame frame; + } panel; + + struct { + struct label label; + } header; + + struct { + struct checkbox cb; + struct label label; + } autosave; + + struct { + struct button button; + } quit; +} ui = { + .panel = { + .frame = { + .x = FRAME_ORIGIN_X, + .y = FRAME_ORIGIN_Y, + .w = FRAME_WIDTH, + .h = FRAME_HEIGHT + } + }, + .header = { + .label = { + .text = "Preferences", + .x = FRAME_ORIGIN_X, + .y = FRAME_ORIGIN_Y, + .flags = LABEL_FLAGS_SHADOW, + } + }, + .autosave = { + .cb = { + .w = ELEMENT_HEIGHT, + .h = ELEMENT_HEIGHT + }, + .label = { + .text = "Auto save game", + .flags = LABEL_FLAGS_SHADOW, + } + }, + .quit = { + .button = { + .text = "Quit", + .h = ELEMENT_HEIGHT + } + } +}; + +static struct state *states[1]; + +static void +init(void) +{ + if (core_init("fr.malikania", "example-ui") < 0 || ui_init() < 0) + panic(); + if (window_open("Example - UI", W, H) < 0) + panic(); +} + +static void +resize_header(void) +{ + struct frame *f = &ui.panel.frame; + struct label *l = &ui.header.label; + unsigned int w, h; + + /* Header. */ + label_query(l, &w, &h); + align(ALIGN_LEFT, &l->x, &l->y, w, h, f->x, f->y, f->w, HEADER_HEIGHT); + + l->x += theme_default()->padding; +} + +static void +resize_autosave(void) +{ + unsigned int padding = theme_default()->padding; + struct frame *f = &ui.panel.frame; + struct checkbox *c = &ui.autosave.cb; + struct label *l = &ui.autosave.label; + + c->x = f->x + padding; + c->y = f->y + HEADER_HEIGHT + padding; + + l->x = c->x + c->w + padding; + l->y = c->y; +} + +static void +resize_button(void) +{ + unsigned int padding = theme_default()->padding; + struct frame *f = &ui.panel.frame; + struct button *b = &ui.quit.button; + + /* Button. */ + b->w = f->w / 4; + + align(ALIGN_BOTTOM_RIGHT, &b->x, &b->y, b->w, b->h, + f->x, f->y, f->w, f->h); + + b->x -= padding; + b->y -= padding; +} + +static void +resize(void) +{ + resize_header(); + resize_autosave(); + resize_button(); +} + +static int +headerclick(int x, int y) +{ + return maths_is_boxed( + ui.panel.frame.x, + ui.panel.frame.y, + ui.panel.frame.w, + HEADER_HEIGHT, + x, + y + ); +} + +static void +handle(struct state *st, const union event *ev) +{ + (void)st; + + switch (ev->type) { + case EVENT_QUIT: + game_quit(); + break; + case EVENT_MOUSE: + if (ui.motion.active) { + ui.panel.frame.x += ev->mouse.x - ui.motion.x; + ui.panel.frame.y += ev->mouse.y - ui.motion.y; + ui.motion.x = ev->mouse.x; + ui.motion.y = ev->mouse.y; + resize(); + } + break; + case EVENT_CLICKDOWN: + if (headerclick(ev->click.x, ev->click.y)) { + ui.motion.active = 1; + ui.motion.x = ev->click.x; + ui.motion.y = ev->click.y; + window_set_cursor(WINDOW_CURSOR_SIZE); + } + break; + case EVENT_CLICKUP: + ui.motion.active = 0; + window_set_cursor(WINDOW_CURSOR_ARROW); + break; + default: + break; + } + + checkbox_handle(&ui.autosave.cb, ev); + + if (button_handle(&ui.quit.button, ev)) + game_quit(); +} + +static void +draw(struct state *st) +{ + (void)st; + + painter_set_color(0xffffffff); + painter_clear(); + frame_draw(&ui.panel.frame); + label_draw(&ui.header.label); + checkbox_draw(&ui.autosave.cb); + label_draw(&ui.autosave.label); + button_draw(&ui.quit.button); + painter_present(); +} + +static void +run(void) +{ + struct state state = { + .handle = handle, + .draw = draw + }; + + resize(); + + game_init(states, UTIL_SIZE(states)); + game_push(&state); + game_loop(); +} + +static void +quit(void) +{ + window_finish(); + ui_finish(); + core_finish(); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tools/bcc/mlk-bcc.c Sun Oct 09 13:53:33 2022 +0200 @@ -0,0 +1,165 @@ +/* + * bcc.c -- binary to C/C++ arrays converter + * + * Copyright (c) 2020-2022 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 <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "arg.h" + +char *argv0; + +static const char *charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"; +static char findentchar = '\t'; +static int findent = 1, fconst, fnull, fstatic; + +static void +usage(void) +{ + fprintf(stderr, "usage: bcc [-0cs] [-I tab-indent] [-i space-indent] input variable\n"); + exit(1); +} + +static void +die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fputs("abort: ", stderr); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +static char * +mangle(char *variable) +{ + char *p; + size_t pos; + + /* Remove extension. */ + if ((p = strrchr(variable, '.'))) + *p = '\0'; + + /* Remove disallowed characters. */ + while ((pos = strspn(variable, charset)) != strlen(variable)) + variable[pos] = '_'; + + return variable; +} + +static void +indent(void) +{ + for (int i = 0; i < findent; ++i) + putchar(findentchar); +} + +static void +put(int ch) +{ + printf("0x%02hhx", (unsigned char)ch); +} + +static void +process(const char *input, const char *variable) +{ + FILE *fp; + int ch, col = 0; + + if (strcmp(input, "-") == 0) + fp = stdin; + else if (!(fp = fopen(input, "rb"))) + die("%s: %s\n", input, strerror(errno)); + + if (fstatic) + printf("static "); + if (fconst) + printf("const "); + + printf("unsigned char %s[] = {\n", variable); + + for (ch = fgetc(fp); ch != EOF; ) { + if (col == 0) + indent(); + + put(ch); + + if ((ch = fgetc(fp)) != EOF || fnull) + printf(",%s", col < 3 ? " " : ""); + + if (++col == 4) { + col = 0; + putchar('\n'); + } + + /* Add final '\0' if required. */ + if (ch == EOF && fnull) { + if (col++ == 0) + indent(); + + put(0); + } + } + + if (col != 0) + printf("\n"); + + puts("};"); + fclose(fp); +} + +int +main(int argc, char *argv[]) +{ +#if defined(__OpenBSD__) + if (pledge("rpath stdio", NULL) < 0) + die("abort: %s\n", strerror(errno)); +#endif + + ARGBEGIN { + case '0': + fnull = 1; + break; + case 'c': + fconst = 1; + break; + case 'I': + findentchar = '\t'; + findent = atoi(EARGF(usage())); + break; + case 'i': + findentchar = ' '; + findent = atoi(EARGF(usage())); + break; + case 's': + fstatic = 1; + break; + default: + usage(); + break; + } ARGEND + + if (argc < 2) + usage(); + + process(argv[0], mangle(argv[1])); +}