# HG changeset patch # User David Demelier # Date 1579783711 -3600 # Node ID d07acc6ee4d97eb1fcbe81a5493041558458fbb0 # Parent 8d34a12484db0bff5a4aa4aa1c1ae9deb3fc37b8 core: improve message diff -r 8d34a12484db -r d07acc6ee4d9 assets/images/message.png Binary file assets/images/message.png has changed diff -r 8d34a12484db -r d07acc6ee4d9 assets/images/message.xcf Binary file assets/images/message.xcf has changed diff -r 8d34a12484db -r d07acc6ee4d9 src/adventure/main.c --- a/src/adventure/main.c Wed Jan 22 12:12:25 2020 +0100 +++ b/src/adventure/main.c Thu Jan 23 13:48:31 2020 +0100 @@ -21,10 +21,13 @@ #include "clock.h" #include "error.h" #include "event.h" +#include "font.h" #include "game.h" #include "image.h" #include "map.h" #include "map_state.h" +#include "message.h" +#include "painter.h" #include "splashscreen_state.h" #include "sprite.h" #include "sys.h" @@ -51,8 +54,31 @@ { union event ev; struct clock clock; + struct font *font; + struct texture *frame; + + if (!(font = font_openf(sys_datapath("fonts/DejaVuSans.ttf"), 14))) + error_fatal(); + if (!(frame = image_openf(sys_datapath("images/message.png")))) + error_fatal(); + + struct message msg = { + .text = { + "Hello Molko.", + "This is your unique adventure, you must listen to me.", + "Do not give up, please be brave.", + "Feel free to come back if you need assistance.", + "But be sure to take a look at the manual pages.", + "And don't forget to update." + }, + .color = 0xd9caddff, + .font = font, + .frame = frame + }; + clock_start(&clock); + message_start(&msg); for (;;) { unsigned int elapsed = clock_elapsed(&clock); @@ -64,11 +90,20 @@ if (ev.type == EVENT_QUIT) return; - game_handle(&ev); + if (msg.state) + message_update(&msg, elapsed); + //game_handle(&ev); } + + painter_set_color(0xffffffff); + painter_clear(); - game_update(elapsed); - game_draw(); + if (msg.state) + message_draw(&msg); + //game_update(elapsed); + //game_draw(); + + painter_present(); if ((elapsed = clock_elapsed(&clock)) < 20) delay(20 - elapsed); diff -r 8d34a12484db -r d07acc6ee4d9 src/core/message.c --- a/src/core/message.c Wed Jan 22 12:12:25 2020 +0100 +++ b/src/core/message.c Thu Jan 23 13:48:31 2020 +0100 @@ -23,16 +23,47 @@ #include "painter.h" #include "sprite.h" #include "texture.h" +#include "window.h" #define MESSAGE_SPEED 1000 /* Time delay for animations */ #define MESSAGE_TIMEOUT 5000 /* Time for auto-closing */ +static unsigned int +average_height(const struct message *msg) +{ + unsigned int n = 0; + unsigned int total = 0; + + for (int i = 0; i < 6; ++i) { + if (msg->ttext[i]) { + n += 1; + total += texture_height(msg->ttext[i]); + } + } + + return n > 0 ? total / n : 0; +} + +static void +redraw(struct message *msg) +{ + /* Generate textures if not already done. */ + for (int i = 0; i < 6; ++i) { + if (!msg->text[i] || msg->ttext[i] || msg->stext[i]) + continue; + + msg->stext[i] = font_render(msg->font, msg->text[i], 0x000000ff); + msg->ttext[i] = font_render(msg->font, msg->text[i], msg->color); + } +} + void message_start(struct message *msg) { assert(msg); msg->elapsed = 0; + msg->alpha = 0; msg->state = MESSAGE_OPENING; } @@ -45,45 +76,65 @@ switch (msg->state) { case MESSAGE_OPENING: - if (msg->elapsed >= MESSAGE_SPEED) + msg->alpha += 255 * ticks / MESSAGE_SPEED; + + if (msg->alpha > 255) + msg->alpha = 255; + if (msg->elapsed >= MESSAGE_SPEED) { msg->state = MESSAGE_SHOWING; + msg->elapsed = 0; + } + break; case MESSAGE_SHOWING: /* Do automatically switch state if requested by the user. */ - if (msg->flags & MESSAGE_AUTOMATIC && msg->elapsed >= MESSAGE_TIMEOUT) + if (msg->flags & MESSAGE_AUTOMATIC && msg->elapsed >= MESSAGE_TIMEOUT) { msg->state = MESSAGE_HIDING; + msg->elapsed = 0; + } + + break; + case MESSAGE_HIDING: + if (msg->elapsed >= MESSAGE_SPEED) { + msg->state = MESSAGE_NONE; + msg->elapsed = 0; + } break; default: break; } - return msg->state == MESSAGE_HIDING && msg->elapsed >= MESSAGE_SPEED; + return msg->state == MESSAGE_NONE; } void message_draw(struct message *msg) { assert(msg); + assert(msg->frame); - /* TODO: draw states! */ - /* TODO: more constant variables. */ - struct texture *lines[3]; - int x = 160; - int y = 80; + const unsigned int w = texture_width(msg->frame); + const unsigned int h = texture_height(msg->frame); + const unsigned int x = (window_width() / 2) - (w / 2); + const unsigned int y = 80; + const unsigned int avgh = average_height(msg); + const unsigned int gapy = (h - (avgh * 6)) / 7; - painter_set_color(0xff0000ff); - painter_draw_rectangle(true, x, y, 960, 160); + /* TODO: handle state */ + redraw(msg); + texture_draw(msg->frame, x, y); - for (int i = 0; msg->text[i]; ++i) { - lines[i] = font_render(msg->font, msg->text[i], 0xffffffff); + for (int i = 0; i < 6; ++i) { + /* TODO: avatar handling */ + const int real_x = x + 20; + const int real_y = y + ((i + 1) * gapy) + (i * avgh); - if (!lines[i]) + if (!msg->ttext[i]) continue; - texture_draw(lines[i], x, y); - texture_close(lines[i]); - y += 53; + texture_draw(msg->stext[i], real_x + 2, real_y + 2); + texture_draw(msg->ttext[i], real_x, real_y); } } @@ -92,5 +143,23 @@ { assert(msg); + msg->state = MESSAGE_HIDING; msg->elapsed = 0; } + +void +message_close(struct message *msg) +{ + assert(msg); + + for (int i = 0; i < 6; ++i) { + if (msg->ttext[i]) { + texture_close(msg->ttext[i]); + msg->ttext[i] = NULL; + } + if (msg->stext[i]) { + texture_close(msg->stext[i]); + msg->stext[i] = NULL; + } + } +} diff -r 8d34a12484db -r d07acc6ee4d9 src/core/message.h --- a/src/core/message.h Wed Jan 22 12:12:25 2020 +0100 +++ b/src/core/message.h Thu Jan 23 13:48:31 2020 +0100 @@ -26,7 +26,7 @@ #include -struct sprite; +struct texture; struct font; /** @@ -40,6 +40,7 @@ * \brief Message state. */ enum message_state { + MESSAGE_NONE, /*!< Message hasn't start yet or is finished */ MESSAGE_OPENING, /*!< Message animation is opening */ MESSAGE_SHOWING, /*!< Message is displaying */ MESSAGE_HIDING /*!< Message animation for hiding */ @@ -47,15 +48,24 @@ /** * \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 { - const char *text[3]; /*!< (RW) lines of text to show */ - struct sprite *theme; /*!< (RW) sprite to use for the frame */ - struct texture *avatar; /*!< (RW) optional avatar */ - struct font *font; /*!< (RW) font to use */ - enum message_flags flags; /*!< (RW) message flags */ - enum message_state state; /*!< (RO) current state */ - unsigned int elapsed; /*!< (RW) elapsed time while displaying */ + const char *text[6]; /*!< (RW) Lines of text to show */ + struct texture *frame; /*!< (RW) Frame to use */ + struct texture *avatar; /*!< (RW) Optional avatar */ + struct font *font; /*!< (RW) Font to use */ + unsigned long color; /*!< (RW) Font color to use */ + enum message_flags flags; /*!< (RW) Message flags */ + enum message_state state; /*!< (RO) Current state */ + + /* PRIVATE */ + struct texture *ttext[6]; /*!< (RW) Textures for every lines */ + struct texture *stext[6]; /*!< (RW) Textures for every lines */ + unsigned int elapsed; /*!< (RW) Elapsed time while displaying */ + unsigned int alpha; /*!< (RO) Alpha progression */ }; /** @@ -99,4 +109,13 @@ void message_hide(struct message *msg); +/** + * Destroy owned resources. + * + * \pre msg != NULL + * \param msg the message + */ +void +message_finish(struct message *msg); + #endif /* !MOLKO_MESSAGE_H */