tuxanci2-game
Game code/assets for tuxanci2
Log | Files | Refs | README | LICENSE
commit 796de752826ecef1cfb09dfdc7bd9c9215209621
parent 8f5f2593ae6ea035d319513e9c68051c21cd616b
Author: Connor Thomson <connor@gnufault.org>
Date:   Wed,  4 Nov 2026 21:43:51 -0800

Add horrid credits screen and horrid music

Diffstat:
Afiles/music/credits.xm | 0
Afiles/music/theme.xm | 0
Asrc/button.c | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rsrc/ta_button.h -> src/button.h | 0
Msrc/main.c | 8+++++---
Asrc/screens.h | 10++++++++++
Asrc/screens/credits.c | 300+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/screens/credits.h | 8++++++++
Asrc/screens/loading.c | 45+++++++++++++++++++++++++++++++++++++++++++++
Rsrc/screens/ta_screen_loading.h -> src/screens/loading.h | 0
Asrc/screens/main_menu.c | 43+++++++++++++++++++++++++++++++++++++++++++
Rsrc/screens/ta_screen_main_menu.h -> src/screens/main_menu.h | 0
Dsrc/screens/ta_screen_loading.c | 45---------------------------------------------
Dsrc/screens/ta_screen_main_menu.c | 30------------------------------
Dsrc/ta_button.c | 163-------------------------------------------------------------------------------
Dsrc/ta_screens.h | 9---------
16 files changed, 574 insertions(+), 250 deletions(-)

diff --git a/files/music/credits.xm b/files/music/credits.xm Binary files differ. diff --git a/files/music/theme.xm b/files/music/theme.xm Binary files differ. diff --git a/src/button.c b/src/button.c @@ -0,0 +1,163 @@ +#include "button.h" +#include <tuxanci2/text.h> +#include <tuxanci2/display.h> +#include <tuxanci2/keyboard.h> +#include <stdint.h> +#include <stdlib.h> +#include <stddef.h> + +#define TA_BUTTON_FONT_SIZE 32 +#define TA_BUTTON_FONT_SIZE_MAX 255 +#define TA_BUTTON_SPACING 48 +#define TA_BUTTON_COLOR_IDLE 118 +#define TA_BUTTON_COLOR_SELECTED 255 +#define TA_BUTTON_REFERENCE_WIDTH 800 +#define TA_BUTTON_REFERENCE_HEIGHT 600 + +static uint32_t scale_to_display(uint32_t value) { + uint32_t display_width = ta_display_width(); + uint32_t display_height = ta_display_height(); + uint32_t numerator = display_width; + uint32_t denominator = TA_BUTTON_REFERENCE_WIDTH; + + if ((uint32_t)display_width * TA_BUTTON_REFERENCE_HEIGHT >= (uint32_t)display_height * TA_BUTTON_REFERENCE_WIDTH) { + numerator = display_height; + denominator = TA_BUTTON_REFERENCE_HEIGHT; + } + + uint32_t scaled = (value * numerator * 2 + denominator) / (denominator * 2); + + return scaled == 0 ? 1 : scaled; +} + +void ta_button_lists_init(ta_button_lists *list) { + if (list == NULL) { + return; + } + + list->buttons = NULL; + list->buttons_size = 0; + list->size = 0; + list->selected = 0; + list->up_was_down = false; + list->down_was_down = false; + list->enter_was_down = false; +} + +bool ta_button_lists_add(ta_button_lists *list, const char *label, ta_button_callback callback) { + if (list == NULL || label == NULL) { + return false; + } + + if (list->size >= list->buttons_size) { + size_t new_capacity = list->buttons_size + 1; + + ta_button *temp = (ta_button *)realloc(list->buttons, new_capacity * sizeof(ta_button)); + + if (temp == NULL) { + return false; + } + + list->buttons = temp; + list->buttons_size = new_capacity; + } + + uint32_t font_size = scale_to_display(TA_BUTTON_FONT_SIZE); + + if (font_size > TA_BUTTON_FONT_SIZE_MAX) { + font_size = TA_BUTTON_FONT_SIZE_MAX; + } + + ta_text text_idle = ta_text_create(label, font_size, TA_DISPLAY_RGB(TA_BUTTON_COLOR_IDLE, TA_BUTTON_COLOR_IDLE, TA_BUTTON_COLOR_IDLE), 1, TA_DISPLAY_RGB(0, 0, 0)); + ta_text text_selected = ta_text_create(label, font_size, TA_DISPLAY_RGB(TA_BUTTON_COLOR_SELECTED, TA_BUTTON_COLOR_SELECTED, TA_BUTTON_COLOR_SELECTED), 1, TA_DISPLAY_RGB(0, 0, 0)); + + if (text_idle == 0 || text_selected == 0) { + ta_text_destroy(text_idle); + ta_text_destroy(text_selected); + return false; + } + + ta_button *button = &list->buttons[list->size]; + + button->label = label; + button->callback = callback; + button->text_idle = text_idle; + button->text_selected = text_selected; + button->text_width = ta_text_width(text_idle); + button->text_height = ta_text_height(text_idle); + + list->size++; + + return true; +} + +void ta_button_lists_update(ta_button_lists *list) { + if (list == NULL || list->size == 0) { + return; + } + + bool up_down = ta_keyboard_is_down(KEY_UP); + bool down_down = ta_keyboard_is_down(KEY_DOWN); + bool enter_down = ta_keyboard_is_down(KEY_ENTER); + bool up_pressed = up_down && !list->up_was_down; + bool down_pressed = down_down && !list->down_was_down; + bool enter_pressed = enter_down && !list->enter_was_down; + + list->up_was_down = up_down; + list->down_was_down = down_down; + list->enter_was_down = enter_down; + + if (down_pressed || up_pressed) { + if (down_pressed) { + list->selected = (list->selected + 1) % list->size; + } else { + list->selected = list->selected == 0 ? list->size - 1 : list->selected - 1; + } + } + + if (enter_pressed && list->buttons[list->selected].callback != NULL) { + list->buttons[list->selected].callback(); + } +} + +void ta_button_lists_draw(const ta_button_lists *list) { + if (list == NULL || list->size == 0) { + return; + } + + uint32_t display_width = ta_display_width(); + uint32_t display_height = ta_display_height(); + int32_t spacing = (int32_t)scale_to_display(TA_BUTTON_SPACING); + int32_t center_y = (int32_t)(display_height / 2); + int32_t total_span = (int32_t)(list->size - 1) * spacing; + int32_t start_y = center_y - (total_span / 2); + + for (size_t i = 0; i < list->size; i++) { + const ta_button *button = &list->buttons[i]; + ta_text text = i == list->selected ? button->text_selected : button->text_idle; + int32_t y = start_y + (int32_t)i * spacing - (int32_t)(button->text_height / 2); + + if (y < 0 || (size_t)y >= display_height || button->text_width > display_width) { + continue; + } + + ta_text_draw(text, (display_width - button->text_width) / 2, (uint32_t)y); + } +} + +void ta_button_lists_destroy(ta_button_lists *list) { + if (list == NULL) { + return; + } + + for (size_t i = 0; i < list->size; i++) { + ta_text_destroy(list->buttons[i].text_idle); + ta_text_destroy(list->buttons[i].text_selected); + } + + if (list->buttons != NULL) { + free(list->buttons); + } + + ta_button_lists_init(list); +} diff --git a/src/ta_button.h b/src/button.h diff --git a/src/main.c b/src/main.c @@ -1,11 +1,13 @@ #include <tuxanci2/screen.h> -#include "ta_screens.h" -#include "screens/ta_screen_loading.h" -#include "screens/ta_screen_main_menu.h" +#include "screens.h" +#include "screens/loading.h" +#include "screens/main_menu.h" +#include "screens/credits.h" int main(void) { ta_screen_register(TA_SCREEN_LOADING, ta_screen_loading_init, ta_screen_loading_update, ta_screen_loading_destroy); ta_screen_register(TA_SCREEN_MAIN_MENU, ta_screen_main_menu_init, ta_screen_main_menu_update, ta_screen_main_menu_destroy); + ta_screen_register(TA_SCREEN_CREDITS, ta_screen_credits_init, ta_screen_credits_update, ta_screen_credits_destroy); ta_screen_switch(TA_SCREEN_LOADING); diff --git a/src/screens.h b/src/screens.h @@ -0,0 +1,10 @@ +#ifndef TA_SCREENS_H +#define TA_SCREENS_H + +typedef enum { + TA_SCREEN_LOADING, + TA_SCREEN_MAIN_MENU, + TA_SCREEN_CREDITS +} ta_screens; + +#endif // TA_SCREENS_H diff --git a/src/screens/credits.c b/src/screens/credits.c @@ -0,0 +1,300 @@ +#include <tuxanci2/display.h> +#include <tuxanci2/shapes.h> +#include <tuxanci2/text.h> +#include <tuxanci2/screen.h> +#include <tuxanci2/ft2.h> +#include "screens.h" +#include <stdint.h> +#include "credits.h" +#include "ta_files.h" + +#define TA_CREDITS_STAR_COUNT 512 +#define TA_CREDITS_TEXT_HOLD_FRAMES 128 +#define TA_CREDITS_ACCELERATION_FRAMES 512 +#define TA_CREDITS_FULL_SPEED 512 +#define TA_CREDITS_Z_ONE 65536 +#define TA_CREDITS_Z_NEAR 1638 + +#define TA_CREDITS_TEXT_MAX_SIZE 128 +#define TA_CREDITS_TEXT_IN_FRAMES 32 +#define TA_CREDITS_TEXT_OUT_FRAMES 32 + +#define TA_CREDITS_TEXT_WIDTH_MARGIN 90 +#define TA_CREDITS_TEXT_HEIGHT_MARGIN 80 + +typedef struct { + int32_t x; + int32_t y; + int32_t z; +} ta_credits_star; + +static const char *strings[] = { + "Tuxánci", + "2", + "", + "Version", + "0.30.0", + "Credits", + "", + "Current Developers", + "", + "Main Developer", + "Connor Thomson (GNUfault)\n<connor@gnufault.org>", + "", + "Original Tuxánci Developers", + "", + "Former Main Developer", + "Dušan Ďurech (Oroborus)\n<dusan.d@centrum.sk>", + "", + "Former Project manager, coordinator of the development, and website maintainer", + "Michal Zima (xHire)\n<xhire@mujmalysvet.cz>", + "", + "Former graphic designer and creator of arenas", + "Jiří Helebrant (helb)\n<helb@helb.cz>", + "", + "Former programmer of server, some network stuff and other significant optimizations", + "Tomáš Jedrzejek (ZeXx86)\n<zexx86@gmail.com>", + "", + "Former build system writer and ebuild maintainer", + "Tomáš Chvátal (scarabeus)\n<tomas.chvatal@gmail.com>", + "", + "Former OpenGL rendering programming", + "Petr Sýkora (Glubo)\n<petr.sykora@gmail.com>", + "", + "Former keyboard improver", + "Karel Podvolecký (kapo)\n<karel.podvolecky@gmail.com>", + "", + "Former porter", + "Petr L. (Timoo)\n<daac@post.cz>", + "", + "Former composer", + "Roman Kabelka (CJ Neti)\n<neti@cjneti.net>", + "", + NULL +}; + +static ta_credits_star stars[TA_CREDITS_STAR_COUNT]; +static uint32_t frame; +static uint32_t random_state; +static uint32_t credit_index; +static uint32_t credit_frame; +static ta_text credit_text; +static uint32_t credit_text_color; +static uint32_t credit_text_width; +static uint32_t credit_text_height; +static int32_t credit_text_x; +static int32_t credit_text_y; + +static uint32_t random_next(void) { + random_state ^= random_state << 13; + random_state ^= random_state >> 17; + random_state ^= random_state << 5; + return random_state; +} + +static int32_t random_coordinate(void) { + return (int32_t)(random_next() & 0xffffu) - 32768; +} + +static int32_t random_depth(void) { + return 49152 + (int32_t)((random_next() & 0xffffu) * 16384u / 65535u); +} + +static void star_reset(ta_credits_star *star, int32_t depth) { + star->x = random_coordinate(); + star->y = random_coordinate(); + star->z = depth; +} + +static void credit_advance(void) { + if (credit_text != 0) { + ta_text_destroy(credit_text); + credit_text = 0; + } + + credit_index++; + credit_frame = 0; +} + +static uint32_t credit_find_size(const char *string) { + uint32_t size; + uint32_t width; + uint32_t height; + ta_text text; + + for (size = TA_CREDITS_TEXT_MAX_SIZE; size > 0; size--) { + text = ta_text_create(string, size, 0xffffff, 0, 0); + + if (text == 0) { + return size; + } + + width = ta_text_width(text); + height = ta_text_height(text); + + ta_text_destroy(text); + + if (width <= ta_display_width() * TA_CREDITS_TEXT_WIDTH_MARGIN / 100 && height <= ta_display_height() * TA_CREDITS_TEXT_HEIGHT_MARGIN / 100) { + return size; + } + } + + return 1; +} + +static void credit_draw(void) { + uint32_t brightness; + uint32_t color; + + if (strings[credit_index] == NULL) { + ta_screen_switch(TA_SCREEN_MAIN_MENU); + return; + } + + if (strings[credit_index][0] == '\0') { + if (credit_frame >= TA_CREDITS_TEXT_HOLD_FRAMES) { + credit_advance(); + return; + } + + credit_frame++; + return; + } + + if (credit_frame < TA_CREDITS_TEXT_IN_FRAMES) { + brightness = credit_frame * 255u / (TA_CREDITS_TEXT_IN_FRAMES - 1); + } else if (credit_frame < TA_CREDITS_TEXT_IN_FRAMES + TA_CREDITS_TEXT_HOLD_FRAMES) { + brightness = 255; + } else { + uint32_t phase = credit_frame - TA_CREDITS_TEXT_IN_FRAMES - TA_CREDITS_TEXT_HOLD_FRAMES; + + if (phase >= TA_CREDITS_TEXT_OUT_FRAMES) { + credit_advance(); + return; + } + + brightness = (TA_CREDITS_TEXT_OUT_FRAMES - 1 - phase) * 255u / (TA_CREDITS_TEXT_OUT_FRAMES - 1); + } + + color = (brightness << 16) | (brightness << 8) | brightness; + + if (credit_text != 0 && credit_text_color != color) { + ta_text_destroy(credit_text); + credit_text = 0; + } + + if (credit_text == 0) { + credit_text = ta_text_create(strings[credit_index], credit_find_size(strings[credit_index]), color, 0, 0); + + if (credit_text == 0) { + credit_frame++; + return; + } + + credit_text_color = color; + credit_text_width = ta_text_width(credit_text); + credit_text_height = ta_text_height(credit_text); + + credit_text_x = ((int32_t)ta_display_width() - (int32_t)credit_text_width) / 2; + credit_text_y = ((int32_t)ta_display_height() - (int32_t)credit_text_height) / 2; + + if (credit_text_x < 0) { + credit_text_x = 0; + } + + if (credit_text_y < 0) { + credit_text_y = 0; + } + } + + ta_text_draw(credit_text, (uint32_t)credit_text_x, (uint32_t)credit_text_y); + + credit_frame++; +} + +void ta_screen_credits_init(void) { + uint32_t i; + + if (ta_ft2_load(ta_file_credits, ta_file_credits_len)) { + ta_ft2_play(); + } + + random_state = 0x6d2b79f5u; + frame = 0; + credit_index = 0; + credit_frame = 0; + credit_text = 0; + credit_text_color = 0; + + for (i = 0; i < TA_CREDITS_STAR_COUNT; i++) { + star_reset(&stars[i], random_depth()); + } +} + +void ta_screen_credits_update(void) { + int32_t width = (int32_t)ta_display_width(); + int32_t height = (int32_t)ta_display_height(); + int32_t center_x = width / 2; + int32_t center_y = height / 2; + int32_t shortest = width < height ? width : height; + int32_t scale = shortest * 48 / 100; + int32_t speed; + uint32_t i; + + if (frame < TA_CREDITS_ACCELERATION_FRAMES) { + speed = TA_CREDITS_FULL_SPEED * (int32_t)frame / TA_CREDITS_ACCELERATION_FRAMES; + } else { + speed = TA_CREDITS_FULL_SPEED; + } + + ta_shapes_draw_pixel((uint32_t)width, (uint32_t)height, 0); + + for (i = 0; i < TA_CREDITS_STAR_COUNT; i++) { + ta_credits_star *star = &stars[i]; + int32_t x; + int32_t y; + int32_t brightness; + uint32_t color; + + star->z -= speed; + + if (star->z <= TA_CREDITS_Z_NEAR) { + star_reset(star, TA_CREDITS_Z_ONE); + } + + x = center_x + (star->x * scale * 2) / star->z; + y = center_y + (star->y * scale * 2) / star->z; + + if (x < 0 || y < 0 || x >= width || y >= height) { + star_reset(star, TA_CREDITS_Z_ONE); + continue; + } + + brightness = ((TA_CREDITS_Z_ONE - star->z) * 255) / (TA_CREDITS_Z_ONE - TA_CREDITS_Z_NEAR); + + if (brightness < 0) { + brightness = 0; + } + + if (brightness > 255) { + brightness = 255; + } + + color = ((uint32_t)brightness << 16) | ((uint32_t)brightness << 8) | (uint32_t)brightness; + + ta_shapes_draw_pixel((uint32_t)x, (uint32_t)y, color); + } + + if (frame >= TA_CREDITS_ACCELERATION_FRAMES) { + credit_draw(); + } + + frame++; +} + +void ta_screen_credits_destroy(void) { + if (credit_text != 0) { + ta_text_destroy(credit_text); + credit_text = 0; + } +} diff --git a/src/screens/credits.h b/src/screens/credits.h @@ -0,0 +1,8 @@ +#ifndef TA_SCREEN_CREDITS_H +#define TA_SCREEN_CREDITS_H + +void ta_screen_credits_init(void); +void ta_screen_credits_update(void); +void ta_screen_credits_destroy(void); + +#endif // TA_SCREEN_CREDITS_H diff --git a/src/screens/loading.c b/src/screens/loading.c @@ -0,0 +1,45 @@ +#include <tuxanci2/screen.h> +#include <tuxanci2/display.h> +#include <tuxanci2/image.h> +#include <ta_files.h> +#include <stdint.h> +#include "loading.h" +#include "../screens.h" + +#define TA_LOADING_LOGO_SIZE TA_FIXED(0.3) + +void ta_screen_loading_init(void) { + ta_image_init(ta_file_loading_logo); +} + +void ta_screen_loading_update(void) { + uint32_t width; + uint32_t height; + + if (!ta_image_get_size(ta_file_loading_logo, &width, &height)) { + return; + } + + uint32_t frame_width = ta_display_width(); + uint32_t frame_height = ta_display_height(); + ta_fixed draw_width; + ta_fixed draw_height; + + if (frame_width * height <= frame_height * width) { + draw_width = TA_LOADING_LOGO_SIZE; + draw_height = (ta_fixed)((TA_LOADING_LOGO_SIZE * (uint32_t)height * frame_width) / ((uint32_t)width * frame_height)); + } else { + draw_height = TA_LOADING_LOGO_SIZE; + draw_width = (ta_fixed)((TA_LOADING_LOGO_SIZE * (uint32_t)width * frame_height) / ((uint32_t)height * frame_width)); + } + + ta_fixed x = (TA_FIXED(1.0) - draw_width) / 2; + ta_fixed y = (TA_FIXED(1.0) - draw_height) / 2; + + ta_image_draw(ta_file_loading_logo, x, y, draw_width, draw_height, 0); + + ta_screen_switch(TA_SCREEN_MAIN_MENU); +} + +void ta_screen_loading_destroy(void) { +} diff --git a/src/screens/ta_screen_loading.h b/src/screens/loading.h diff --git a/src/screens/main_menu.c b/src/screens/main_menu.c @@ -0,0 +1,43 @@ +#include <stdlib.h> +#include <tuxanci2/image.h> +#include <tuxanci2/screen.h> +#include <tuxanci2/ft2.h> +#include <ta_files.h> +#include "screens.h" +#include "main_menu.h" +#include "../button.h" + +static ta_button_lists menu; + +static void quit(void) { + exit(0); +} + +static void credits(void) { + ta_screen_switch(TA_SCREEN_CREDITS); +} + +void ta_screen_main_menu_init(void) { + ta_image_init(ta_file_bg); + + if (ta_ft2_load(ta_file_theme, ta_file_theme_len)) { + ta_ft2_play(); + } + + ta_button_lists_init(&menu); + ta_button_lists_add(&menu, "Play", NULL); + ta_button_lists_add(&menu, "Credits", credits); + ta_button_lists_add(&menu, "Quit", quit); +} + +void ta_screen_main_menu_update(void) { + ta_button_lists_update(&menu); + + ta_image_draw(ta_file_bg, 0, 0, TA_FIXED(1.0), TA_FIXED(1.0), 0); + ta_button_lists_draw(&menu); +} + +void ta_screen_main_menu_destroy(void) { + ta_ft2_stop(); + ta_button_lists_destroy(&menu); +} diff --git a/src/screens/ta_screen_main_menu.h b/src/screens/main_menu.h diff --git a/src/screens/ta_screen_loading.c b/src/screens/ta_screen_loading.c @@ -1,45 +0,0 @@ -#include <tuxanci2/screen.h> -#include <tuxanci2/display.h> -#include <tuxanci2/image.h> -#include <ta_files.h> -#include <stdint.h> -#include "ta_screen_loading.h" -#include "../ta_screens.h" - -#define TA_LOADING_LOGO_SIZE TA_FIXED(0.3) - -void ta_screen_loading_init(void) { - ta_image_init(ta_file_loading_logo); -} - -void ta_screen_loading_update(void) { - uint32_t width; - uint32_t height; - - if (!ta_image_get_size(ta_file_loading_logo, &width, &height)) { - return; - } - - uint32_t frame_width = ta_display_width(); - uint32_t frame_height = ta_display_height(); - ta_fixed draw_width; - ta_fixed draw_height; - - if (frame_width * height <= frame_height * width) { - draw_width = TA_LOADING_LOGO_SIZE; - draw_height = (ta_fixed)((TA_LOADING_LOGO_SIZE * (uint32_t)height * frame_width) / ((uint32_t)width * frame_height)); - } else { - draw_height = TA_LOADING_LOGO_SIZE; - draw_width = (ta_fixed)((TA_LOADING_LOGO_SIZE * (uint32_t)width * frame_height) / ((uint32_t)height * frame_width)); - } - - ta_fixed x = (TA_FIXED(1.0) - draw_width) / 2; - ta_fixed y = (TA_FIXED(1.0) - draw_height) / 2; - - ta_image_draw(ta_file_loading_logo, x, y, draw_width, draw_height, 0); - - ta_screen_switch(TA_SCREEN_MAIN_MENU); -} - -void ta_screen_loading_destroy(void) { -} diff --git a/src/screens/ta_screen_main_menu.c b/src/screens/ta_screen_main_menu.c @@ -1,30 +0,0 @@ -#include <stdlib.h> -#include <tuxanci2/image.h> -#include <ta_files.h> -#include "ta_screen_main_menu.h" -#include "../ta_button.h" - -static ta_button_lists menu; - -static void quit(void) { - exit(0); -} - -void ta_screen_main_menu_init(void) { - ta_image_init(ta_file_bg); - - ta_button_lists_init(&menu); - ta_button_lists_add(&menu, "Play", NULL); - ta_button_lists_add(&menu, "Quit", quit); -} - -void ta_screen_main_menu_update(void) { - ta_button_lists_update(&menu); - - ta_image_draw(ta_file_bg, 0, 0, TA_FIXED(1.0), TA_FIXED(1.0), 0); - ta_button_lists_draw(&menu); -} - -void ta_screen_main_menu_destroy(void) { - ta_button_lists_destroy(&menu); -} diff --git a/src/ta_button.c b/src/ta_button.c @@ -1,163 +0,0 @@ -#include "ta_button.h" -#include <tuxanci2/text.h> -#include <tuxanci2/display.h> -#include <tuxanci2/keyboard.h> -#include <stdint.h> -#include <stdlib.h> -#include <stddef.h> - -#define TA_BUTTON_FONT_SIZE 32 -#define TA_BUTTON_FONT_SIZE_MAX 255 -#define TA_BUTTON_SPACING 48 -#define TA_BUTTON_COLOR_IDLE 118 -#define TA_BUTTON_COLOR_SELECTED 255 -#define TA_BUTTON_REFERENCE_WIDTH 800 -#define TA_BUTTON_REFERENCE_HEIGHT 600 - -static uint32_t scale_to_display(uint32_t value) { - uint32_t display_width = ta_display_width(); - uint32_t display_height = ta_display_height(); - uint32_t numerator = display_width; - uint32_t denominator = TA_BUTTON_REFERENCE_WIDTH; - - if ((uint32_t)display_width * TA_BUTTON_REFERENCE_HEIGHT >= (uint32_t)display_height * TA_BUTTON_REFERENCE_WIDTH) { - numerator = display_height; - denominator = TA_BUTTON_REFERENCE_HEIGHT; - } - - uint32_t scaled = (value * numerator * 2 + denominator) / (denominator * 2); - - return scaled == 0 ? 1 : scaled; -} - -void ta_button_lists_init(ta_button_lists *list) { - if (list == NULL) { - return; - } - - list->buttons = NULL; - list->buttons_size = 0; - list->size = 0; - list->selected = 0; - list->up_was_down = false; - list->down_was_down = false; - list->enter_was_down = false; -} - -bool ta_button_lists_add(ta_button_lists *list, const char *label, ta_button_callback callback) { - if (list == NULL || label == NULL) { - return false; - } - - if (list->size >= list->buttons_size) { - size_t new_capacity = list->buttons_size + 1; - - ta_button *temp = (ta_button *)realloc(list->buttons, new_capacity * sizeof(ta_button)); - - if (temp == NULL) { - return false; - } - - list->buttons = temp; - list->buttons_size = new_capacity; - } - - uint32_t font_size = scale_to_display(TA_BUTTON_FONT_SIZE); - - if (font_size > TA_BUTTON_FONT_SIZE_MAX) { - font_size = TA_BUTTON_FONT_SIZE_MAX; - } - - ta_text text_idle = ta_text_create(label, font_size, TA_DISPLAY_RGB(TA_BUTTON_COLOR_IDLE, TA_BUTTON_COLOR_IDLE, TA_BUTTON_COLOR_IDLE), 1, TA_DISPLAY_RGB(0, 0, 0)); - ta_text text_selected = ta_text_create(label, font_size, TA_DISPLAY_RGB(TA_BUTTON_COLOR_SELECTED, TA_BUTTON_COLOR_SELECTED, TA_BUTTON_COLOR_SELECTED), 1, TA_DISPLAY_RGB(0, 0, 0)); - - if (text_idle == 0 || text_selected == 0) { - ta_text_destroy(text_idle); - ta_text_destroy(text_selected); - return false; - } - - ta_button *button = &list->buttons[list->size]; - - button->label = label; - button->callback = callback; - button->text_idle = text_idle; - button->text_selected = text_selected; - button->text_width = ta_text_width(text_idle); - button->text_height = ta_text_height(text_idle); - - list->size++; - - return true; -} - -void ta_button_lists_update(ta_button_lists *list) { - if (list == NULL || list->size == 0) { - return; - } - - bool up_down = ta_keyboard_is_down(KEY_UP); - bool down_down = ta_keyboard_is_down(KEY_DOWN); - bool enter_down = ta_keyboard_is_down(KEY_ENTER); - bool up_pressed = up_down && !list->up_was_down; - bool down_pressed = down_down && !list->down_was_down; - bool enter_pressed = enter_down && !list->enter_was_down; - - list->up_was_down = up_down; - list->down_was_down = down_down; - list->enter_was_down = enter_down; - - if (down_pressed || up_pressed) { - if (down_pressed) { - list->selected = (list->selected + 1) % list->size; - } else { - list->selected = list->selected == 0 ? list->size - 1 : list->selected - 1; - } - } - - if (enter_pressed && list->buttons[list->selected].callback != NULL) { - list->buttons[list->selected].callback(); - } -} - -void ta_button_lists_draw(const ta_button_lists *list) { - if (list == NULL || list->size == 0) { - return; - } - - uint32_t display_width = ta_display_width(); - uint32_t display_height = ta_display_height(); - int32_t spacing = (int32_t)scale_to_display(TA_BUTTON_SPACING); - int32_t center_y = (int32_t)(display_height / 2); - int32_t total_span = (int32_t)(list->size - 1) * spacing; - int32_t start_y = center_y - (total_span / 2); - - for (size_t i = 0; i < list->size; i++) { - const ta_button *button = &list->buttons[i]; - ta_text text = i == list->selected ? button->text_selected : button->text_idle; - int32_t y = start_y + (int32_t)i * spacing - (int32_t)(button->text_height / 2); - - if (y < 0 || (size_t)y >= display_height || button->text_width > display_width) { - continue; - } - - ta_text_draw(text, (display_width - button->text_width) / 2, (uint32_t)y); - } -} - -void ta_button_lists_destroy(ta_button_lists *list) { - if (list == NULL) { - return; - } - - for (size_t i = 0; i < list->size; i++) { - ta_text_destroy(list->buttons[i].text_idle); - ta_text_destroy(list->buttons[i].text_selected); - } - - if (list->buttons != NULL) { - free(list->buttons); - } - - ta_button_lists_init(list); -} diff --git a/src/ta_screens.h b/src/ta_screens.h @@ -1,9 +0,0 @@ -#ifndef TA_SCREENS_H -#define TA_SCREENS_H - -typedef enum { - TA_SCREEN_LOADING, - TA_SCREEN_MAIN_MENU -} ta_screens; - -#endif // TA_SCREENS_H