tuxanci2-engine
Game engine for tuxanci2
Log | Files | Refs | README | LICENSE
commit 028f51bbaefa32f45badb55861229511f4b02c8c
parent 2e13d882da334eafde4b7e2de431749f7793a2c0
Author: Connor Thomson <connor@gnufault.org>
Date:   Tue, 20 Oct 2026 16:31:57 -0700

Change code formatting

Diffstat:
Minclude/ta_api.h | 2+-
Minclude/ta_button.h | 27+++++++++++++--------------
Minclude/ta_fb.h | 8++++----
Minclude/ta_keyboard.h | 259+++++++++++++++++++++++++++++++++++++++----------------------------------------
Minclude/ta_screen.h | 7+++----
Minclude/ta_text.h | 3+--
Minclude/ta_types.h | 20++++++++++----------
Msrc/screens/ta_screen_loading.c | 103+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/screens/ta_screen_main_menu.c | 40++++++++++++++++++++--------------------
Msrc/ta_button.c | 309+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/ta_fb.c | 82++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/ta_image.c | 1058++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/ta_keyboard.c | 54+++++++++++++++++++++++++++---------------------------
Msrc/ta_main.c | 20++++++++++----------
Msrc/ta_screen.c | 50+++++++++++++++++++++++++-------------------------
Msrc/ta_text.c | 1870+++++++++++++++++++++++++++++++++++++++----------------------------------------
16 files changed, 1951 insertions(+), 1961 deletions(-)

diff --git a/include/ta_api.h b/include/ta_api.h @@ -6,10 +6,10 @@ extern "C" { #endif #include "ta_config.h" -#include "ta_types.h" #include "ta_fb.h" #include "ta_keyboard.h" #include "ta_title.h" +#include "ta_types.h" // Must be called before ta_update() void ta_main_init(void); diff --git a/include/ta_button.h b/include/ta_button.h @@ -6,21 +6,21 @@ typedef void (*ta_button_callback)(void); typedef struct { - const char *label; - ta_button_callback callback; + const char *label; + ta_button_callback callback; } ta_button; typedef struct { - ta_button *buttons; - ta_size size; - ta_size selected; - ta_size animation_from; - ta_uint32 animation_frame; - ta_uint32 pulse_frame; - ta_bool animation_active; - ta_bool up_was_down; - ta_bool down_was_down; - ta_bool enter_was_down; + ta_button *buttons; + ta_size size; + ta_size selected; + ta_size animation_from; + ta_uint32 animation_frame; + ta_uint32 pulse_frame; + ta_bool animation_active; + ta_bool up_was_down; + ta_bool down_was_down; + ta_bool enter_was_down; } ta_button_lists; void ta_button_lists_init(ta_button_lists *list); @@ -29,4 +29,4 @@ ta_bool ta_button_lists_update(ta_button_lists *list); void ta_button_lists_draw(const ta_button_lists *list); void ta_button_lists_destroy(ta_button_lists *list); -#endif -\ No newline at end of file +#endif diff --git a/include/ta_fb.h b/include/ta_fb.h @@ -4,10 +4,10 @@ #include "ta_types.h" typedef struct { - ta_size width, height; - ta_size bpp; - ta_size size; - void *buffers[2]; + ta_size width, height; + ta_size bpp; + ta_size size; + void *buffers[2]; } ta_fbs; extern ta_fbs ta_fb; diff --git a/include/ta_keyboard.h b/include/ta_keyboard.h @@ -6,137 +6,137 @@ #define TA_KEYBOARD_MAX_KEYS_DOWN 5 typedef enum { - KEY_NONE = 0, - KEY_BACKSPACE = 8, - KEY_TAB = 9, - KEY_ENTER = 13, - KEY_ESCAPE = 27, - KEY_SPACE = 32, - KEY_EXCLAMATION_MARK = 33, - KEY_QUOTATION_MARK = 34, - KEY_HASH = 35, - KEY_DOLLAR_SIGN = 36, - KEY_PERCENT_SIGN = 37, - KEY_AMPERSAND = 38, - KEY_APOSTROPHE = 39, - KEY_LEFT_PARENTHESIS = 40, - KEY_RIGHT_PARENTHESIS = 41, - KEY_ASTERISK = 42, - KEY_PLUS = 43, - KEY_COMMA = 44, - KEY_MINUS = 45, - KEY_PERIOD = 46, - KEY_SLASH = 47, - KEY_0 = 48, - KEY_1 = 49, - KEY_2 = 50, - KEY_3 = 51, - KEY_4 = 52, - KEY_5 = 53, - KEY_6 = 54, - KEY_7 = 55, - KEY_8 = 56, - KEY_9 = 57, - KEY_COLON = 58, - KEY_SEMICOLON = 59, - KEY_LESS_THAN = 60, - KEY_EQUALS = 61, - KEY_GREATER_THAN = 62, - KEY_QUESTION_MARK = 63, - KEY_AT_SIGN = 64, - KEY_A = 97, - KEY_B = 98, - KEY_C = 99, - KEY_D = 100, - KEY_E = 101, - KEY_F = 102, - KEY_G = 103, - KEY_H = 104, - KEY_I = 105, - KEY_J = 106, - KEY_K = 107, - KEY_L = 108, - KEY_M = 109, - KEY_N = 110, - KEY_O = 111, - KEY_P = 112, - KEY_Q = 113, - KEY_R = 114, - KEY_S = 115, - KEY_T = 116, - KEY_U = 117, - KEY_V = 118, - KEY_W = 119, - KEY_X = 120, - KEY_Y = 121, - KEY_Z = 122, - KEY_LEFT_BRACKET = 91, - KEY_BACKSLASH = 92, - KEY_RIGHT_BRACKET = 93, - KEY_CARET = 94, - KEY_UNDERSCORE = 95, - KEY_GRAVE_ACCENT = 96, - KEY_LEFT_BRACE = 123, - KEY_PIPE = 124, - KEY_RIGHT_BRACE = 125, - KEY_TILDE = 126, - KEY_DELETE = 127, - KEY_UP = 128, - KEY_DOWN = 129, - KEY_LEFT = 130, - KEY_RIGHT = 131, - KEY_F1 = 132, - KEY_F2 = 133, - KEY_F3 = 134, - KEY_F4 = 135, - KEY_F5 = 136, - KEY_F6 = 137, - KEY_F7 = 138, - KEY_F8 = 139, - KEY_F9 = 140, - KEY_F10 = 141, - KEY_F11 = 142, - KEY_F12 = 143, - KEY_HOME = 144, - KEY_END = 145, - KEY_PAGE_UP = 146, - KEY_PAGE_DOWN = 147, - KEY_INSERT = 148, - KEY_CAPS_LOCK = 149, - KEY_NUM_LOCK = 150, - KEY_SCROLL_LOCK = 151, - KEY_PRINT_SCREEN = 152, - KEY_PAUSE = 153, - KEY_MENU = 154, - KEY_LEFT_SHIFT = 155, - KEY_RIGHT_SHIFT = 156, - KEY_LEFT_CTRL = 157, - KEY_RIGHT_CTRL = 158, - KEY_LEFT_ALT = 159, - KEY_RIGHT_ALT = 160, - KEY_LEFT_SUPER = 161, - KEY_RIGHT_SUPER = 162, - KEY_KP_0 = 163, - KEY_KP_1 = 164, - KEY_KP_2 = 165, - KEY_KP_3 = 166, - KEY_KP_4 = 167, - KEY_KP_5 = 168, - KEY_KP_6 = 169, - KEY_KP_7 = 170, - KEY_KP_8 = 171, - KEY_KP_9 = 172, - KEY_KP_DECIMAL = 173, - KEY_KP_DIVIDE = 174, - KEY_KP_MULTIPLY = 175, - KEY_KP_SUBTRACT = 176, - KEY_KP_ADD = 177, - KEY_KP_ENTER = 178, - KEY_KP_EQUALS = 179 + KEY_NONE = 0, + KEY_BACKSPACE = 8, + KEY_TAB = 9, + KEY_ENTER = 13, + KEY_ESCAPE = 27, + KEY_SPACE = 32, + KEY_EXCLAMATION_MARK = 33, + KEY_QUOTATION_MARK = 34, + KEY_HASH = 35, + KEY_DOLLAR_SIGN = 36, + KEY_PERCENT_SIGN = 37, + KEY_AMPERSAND = 38, + KEY_APOSTROPHE = 39, + KEY_LEFT_PARENTHESIS = 40, + KEY_RIGHT_PARENTHESIS = 41, + KEY_ASTERISK = 42, + KEY_PLUS = 43, + KEY_COMMA = 44, + KEY_MINUS = 45, + KEY_PERIOD = 46, + KEY_SLASH = 47, + KEY_0 = 48, + KEY_1 = 49, + KEY_2 = 50, + KEY_3 = 51, + KEY_4 = 52, + KEY_5 = 53, + KEY_6 = 54, + KEY_7 = 55, + KEY_8 = 56, + KEY_9 = 57, + KEY_COLON = 58, + KEY_SEMICOLON = 59, + KEY_LESS_THAN = 60, + KEY_EQUALS = 61, + KEY_GREATER_THAN = 62, + KEY_QUESTION_MARK = 63, + KEY_AT_SIGN = 64, + KEY_A = 97, + KEY_B = 98, + KEY_C = 99, + KEY_D = 100, + KEY_E = 101, + KEY_F = 102, + KEY_G = 103, + KEY_H = 104, + KEY_I = 105, + KEY_J = 106, + KEY_K = 107, + KEY_L = 108, + KEY_M = 109, + KEY_N = 110, + KEY_O = 111, + KEY_P = 112, + KEY_Q = 113, + KEY_R = 114, + KEY_S = 115, + KEY_T = 116, + KEY_U = 117, + KEY_V = 118, + KEY_W = 119, + KEY_X = 120, + KEY_Y = 121, + KEY_Z = 122, + KEY_LEFT_BRACKET = 91, + KEY_BACKSLASH = 92, + KEY_RIGHT_BRACKET = 93, + KEY_CARET = 94, + KEY_UNDERSCORE = 95, + KEY_GRAVE_ACCENT = 96, + KEY_LEFT_BRACE = 123, + KEY_PIPE = 124, + KEY_RIGHT_BRACE = 125, + KEY_TILDE = 126, + KEY_DELETE = 127, + KEY_UP = 128, + KEY_DOWN = 129, + KEY_LEFT = 130, + KEY_RIGHT = 131, + KEY_F1 = 132, + KEY_F2 = 133, + KEY_F3 = 134, + KEY_F4 = 135, + KEY_F5 = 136, + KEY_F6 = 137, + KEY_F7 = 138, + KEY_F8 = 139, + KEY_F9 = 140, + KEY_F10 = 141, + KEY_F11 = 142, + KEY_F12 = 143, + KEY_HOME = 144, + KEY_END = 145, + KEY_PAGE_UP = 146, + KEY_PAGE_DOWN = 147, + KEY_INSERT = 148, + KEY_CAPS_LOCK = 149, + KEY_NUM_LOCK = 150, + KEY_SCROLL_LOCK = 151, + KEY_PRINT_SCREEN = 152, + KEY_PAUSE = 153, + KEY_MENU = 154, + KEY_LEFT_SHIFT = 155, + KEY_RIGHT_SHIFT = 156, + KEY_LEFT_CTRL = 157, + KEY_RIGHT_CTRL = 158, + KEY_LEFT_ALT = 159, + KEY_RIGHT_ALT = 160, + KEY_LEFT_SUPER = 161, + KEY_RIGHT_SUPER = 162, + KEY_KP_0 = 163, + KEY_KP_1 = 164, + KEY_KP_2 = 165, + KEY_KP_3 = 166, + KEY_KP_4 = 167, + KEY_KP_5 = 168, + KEY_KP_6 = 169, + KEY_KP_7 = 170, + KEY_KP_8 = 171, + KEY_KP_9 = 172, + KEY_KP_DECIMAL = 173, + KEY_KP_DIVIDE = 174, + KEY_KP_MULTIPLY = 175, + KEY_KP_SUBTRACT = 176, + KEY_KP_ADD = 177, + KEY_KP_ENTER = 178, + KEY_KP_EQUALS = 179 } ta_keyboard_keys; typedef struct { - ta_uint8 keys_down[TA_KEYBOARD_MAX_KEYS_DOWN]; + ta_uint8 keys_down[TA_KEYBOARD_MAX_KEYS_DOWN]; } ta_keyboards; extern ta_keyboards ta_keyboard; @@ -146,4 +146,4 @@ void ta_keyboard_key_down(ta_keyboard_keys key); void ta_keyboard_key_up(ta_keyboard_keys key); void ta_keyboard_clear(void); -#endif // TA_KEYBOARD_H -\ No newline at end of file +#endif // TA_KEYBOARD_H diff --git a/include/ta_screen.h b/include/ta_screen.h @@ -4,8 +4,8 @@ #include "ta_types.h" typedef enum { - TA_SCREEN_LOADING, - TA_SCEEEN_MAIN_MENU + TA_SCREEN_LOADING, + TA_SCEEEN_MAIN_MENU } ta_screens; extern ta_screens ta_screen_current; @@ -14,4 +14,4 @@ void ta_screen_init(void); ta_bool ta_screen_update(void); void ta_screen_destroy(void); -#endif // TA_SCREEN_H -\ No newline at end of file +#endif // TA_SCREEN_H diff --git a/include/ta_text.h b/include/ta_text.h @@ -8,4 +8,4 @@ void ta_text_draw_outline(const char *text, ta_uint32 x, ta_uint32 y, ta_uint32 void ta_text_draw_size(const char *text, ta_uint32 x, ta_uint32 y, ta_uint32 size, ta_uint8 red, ta_uint8 green, ta_uint8 blue); void ta_text_measure(const char *text, ta_uint32 size, ta_uint32 *width, ta_uint32 *height); -#endif // TA_TEXT_H -\ No newline at end of file +#endif // TA_TEXT_H diff --git a/include/ta_types.h b/include/ta_types.h @@ -3,22 +3,22 @@ #include "ta_config.h" -typedef unsigned char ta_uint8; -typedef unsigned short ta_uint16; -typedef unsigned int ta_uint32; +typedef unsigned char ta_uint8; +typedef unsigned short ta_uint16; +typedef unsigned int ta_uint32; typedef unsigned long long ta_uint64; typedef signed char ta_int8; -typedef short ta_int16; -typedef int ta_int32; -typedef long long ta_int64; +typedef short ta_int16; +typedef int ta_int32; +typedef long long ta_int64; #if TA_BITS == 64 - typedef ta_uint64 ta_size; +typedef ta_uint64 ta_size; #elif TA_BITS == 32 - typedef ta_uint32 ta_size; +typedef ta_uint32 ta_size; #else - #error "TA_BITS is not set!" +#error "TA_BITS is not set!" #endif #ifdef __cplusplus @@ -27,7 +27,7 @@ typedef bool ta_bool; typedef _Bool ta_bool; #endif -#define ta_true 1 +#define ta_true 1 #define ta_false 0 typedef ta_uint32 ta_fixed; diff --git a/src/screens/ta_screen_loading.c b/src/screens/ta_screen_loading.c @@ -1,7 +1,7 @@ -#include "ta_screen.h" -#include "ta_files.h" #include "ta_fb.h" +#include "ta_files.h" #include "ta_image.h" +#include "ta_screen.h" #define TA_LOADING_LOGO_SIZE TA_FIXED(0.3) @@ -11,69 +11,68 @@ static ta_bool background_loaded; static ta_bool background_scaled; static void draw_loading_logo(void) { - ta_uint32 width; - ta_uint32 height; - - if (!ta_image_get_size(ta_file_loading_logo, ta_file_loading_logo_len, &width, &height)) { - return; - } - - ta_uint64 frame_width = ta_fb.width; - ta_uint64 frame_height = ta_fb.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 * (ta_uint64)height * frame_width) / ((ta_uint64)width * frame_height)); - } else { - draw_height = TA_LOADING_LOGO_SIZE; - draw_width = (ta_fixed)((TA_LOADING_LOGO_SIZE * (ta_uint64)width * frame_height) / ((ta_uint64)height * frame_width)); - } - - ta_fixed x = (TA_FIXED_ONE - draw_width) / 2; - ta_fixed y = (TA_FIXED_ONE - draw_height) / 2; - - ta_image_draw(ta_file_loading_logo, ta_file_loading_logo_len, x, y, draw_width, draw_height, 0); + ta_uint32 width; + ta_uint32 height; + + if (!ta_image_get_size(ta_file_loading_logo, ta_file_loading_logo_len, &width, &height)) { + return; + } + + ta_uint64 frame_width = ta_fb.width; + ta_uint64 frame_height = ta_fb.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 * (ta_uint64)height * frame_width) / ((ta_uint64)width * frame_height)); + } else { + draw_height = TA_LOADING_LOGO_SIZE; + draw_width = (ta_fixed)((TA_LOADING_LOGO_SIZE * (ta_uint64)width * frame_height) / ((ta_uint64)height * frame_width)); + } + + ta_fixed x = (TA_FIXED_ONE - draw_width) / 2; + ta_fixed y = (TA_FIXED_ONE - draw_height) / 2; + + ta_image_draw(ta_file_loading_logo, ta_file_loading_logo_len, x, y, draw_width, draw_height, 0); } void ta_screen_loading_init(void) { - logo_loaded = ta_false; - logo_shown = ta_false; - background_loaded = ta_false; - background_scaled = ta_false; + logo_loaded = ta_false; + logo_shown = ta_false; + background_loaded = ta_false; + background_scaled = ta_false; } ta_bool ta_screen_loading_update(void) { - ta_fb_clear(&ta_fb); + ta_fb_clear(&ta_fb); + + if (!logo_loaded) { + logo_loaded = ta_image_init(ta_file_loading_logo, ta_file_loading_logo_len); + return ta_true; + } - if (!logo_loaded) { - logo_loaded = ta_image_init(ta_file_loading_logo, ta_file_loading_logo_len); - return ta_true; - } + draw_loading_logo(); - draw_loading_logo(); - - if (!logo_shown) { - logo_shown = ta_true; - return ta_true; - } + if (!logo_shown) { + logo_shown = ta_true; + return ta_true; + } - if (!background_loaded) { - background_loaded = ta_image_init(ta_file_bg, ta_file_bg_len); - return ta_true; - } + if (!background_loaded) { + background_loaded = ta_image_init(ta_file_bg, ta_file_bg_len); + return ta_true; + } - if (!background_scaled) { - background_scaled = ta_image_prepare(ta_file_bg, ta_file_bg_len, TA_FIXED_ONE, TA_FIXED_ONE, 0); - return ta_true; - } + if (!background_scaled) { + background_scaled = ta_image_prepare(ta_file_bg, ta_file_bg_len, TA_FIXED_ONE, TA_FIXED_ONE, 0); + return ta_true; + } - ta_screen_current = TA_SCEEEN_MAIN_MENU; + ta_screen_current = TA_SCEEEN_MAIN_MENU; - return ta_true; + return ta_true; } 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,41 +1,41 @@ -#include "ta_screen.h" -#include "ta_files.h" -#include "ta_fb.h" #include "ta_button.h" +#include "ta_fb.h" +#include "ta_files.h" #include "ta_image.h" #include "ta_main.h" +#include "ta_screen.h" static ta_button_lists menu; static ta_bool needs_redraw; void ta_screen_main_menu_init(void) { - needs_redraw = ta_true; + needs_redraw = ta_true; - ta_button_lists_init(&menu); - ta_button_lists_add(&menu, "Play", 0); - ta_button_lists_add(&menu, "Quit", ta_main_destroy); + ta_button_lists_init(&menu); + ta_button_lists_add(&menu, "Play", 0); + ta_button_lists_add(&menu, "Quit", ta_main_destroy); } ta_bool ta_screen_main_menu_update(void) { - if (ta_button_lists_update(&menu)) { - needs_redraw = ta_true; - } + if (ta_button_lists_update(&menu)) { + needs_redraw = ta_true; + } - if (!needs_redraw) { - return ta_false; - } + if (!needs_redraw) { + return ta_false; + } - needs_redraw = ta_false; + needs_redraw = ta_false; - if (!ta_image_draw(ta_file_bg, ta_file_bg_len, 0, 0, TA_FIXED_ONE, TA_FIXED_ONE, 0)) { - ta_fb_clear(&ta_fb); - } + if (!ta_image_draw(ta_file_bg, ta_file_bg_len, 0, 0, TA_FIXED_ONE, TA_FIXED_ONE, 0)) { + ta_fb_clear(&ta_fb); + } - ta_button_lists_draw(&menu); + ta_button_lists_draw(&menu); - return ta_true; + return ta_true; } void ta_screen_main_menu_destroy(void) { - ta_button_lists_destroy(&menu); + ta_button_lists_destroy(&menu); } diff --git a/src/ta_button.c b/src/ta_button.c @@ -1,181 +1,181 @@ -#include "ta_api.h" #include "ta_button.h" +#include "ta_api.h" #include "ta_text.h" #define TA_BUTTON_ANIMATION_FRAMES 8 -#define TA_BUTTON_FONT_SIZE 32 -#define TA_BUTTON_SPACING 48 -#define TA_BUTTON_COLOR_IDLE 118 -#define TA_BUTTON_COLOR_SELECTED 255 +#define TA_BUTTON_FONT_SIZE 32 +#define TA_BUTTON_SPACING 48 +#define TA_BUTTON_COLOR_IDLE 118 +#define TA_BUTTON_COLOR_SELECTED 255 #define TA_BUTTON_COLOR_PULSE_BLUE_MIN 96 #define TA_BUTTON_PULSE_HALF_FRAMES 24 void ta_button_lists_init(ta_button_lists *list) { - if (list == 0) { - return; - } - - list->buttons = 0; - list->size = 0; - list->selected = 0; - list->animation_from = 0; - list->animation_frame = 0; - list->pulse_frame = 0; - list->animation_active = ta_false; - list->up_was_down = ta_false; - list->down_was_down = ta_false; - list->enter_was_down = ta_false; + if (list == 0) { + return; + } + + list->buttons = 0; + list->size = 0; + list->selected = 0; + list->animation_from = 0; + list->animation_frame = 0; + list->pulse_frame = 0; + list->animation_active = ta_false; + list->up_was_down = ta_false; + list->down_was_down = ta_false; + list->enter_was_down = ta_false; } ta_bool ta_button_lists_add(ta_button_lists *list, const char *label, ta_button_callback callback) { - if (list == 0 || label == 0 || list->size == (ta_size)-1 || list->size + 1 > (ta_size)-1 / sizeof(ta_button)) { - return ta_false; - } + if (list == 0 || label == 0 || list->size == (ta_size)-1 || list->size + 1 > (ta_size)-1 / sizeof(ta_button)) { + return ta_false; + } - ta_size new_size = list->size + 1; - ta_button *buttons = (ta_button *)ta_malloc(new_size * sizeof(ta_button)); - - if (buttons == 0) { - return ta_false; - } + ta_size new_size = list->size + 1; + ta_button *buttons = (ta_button *)ta_malloc(new_size * sizeof(ta_button)); - for (ta_size i = 0; i < list->size; i++) { - buttons[i] = list->buttons[i]; - } + if (buttons == 0) { + return ta_false; + } - buttons[list->size].label = label; - buttons[list->size].callback = callback; + for (ta_size i = 0; i < list->size; i++) { + buttons[i] = list->buttons[i]; + } - ta_free(list->buttons); + buttons[list->size].label = label; + buttons[list->size].callback = callback; - list->buttons = buttons; - list->size = new_size; + ta_free(list->buttons); - return ta_true; + list->buttons = buttons; + list->size = new_size; + + return ta_true; } ta_bool ta_button_lists_update(ta_button_lists *list) { - if (list == 0 || list->size == 0) { - return ta_false; - } - - list->pulse_frame = (list->pulse_frame + 1) % (TA_BUTTON_PULSE_HALF_FRAMES * 2); - - ta_bool up_down = ta_keyboard_is_down(KEY_UP); - ta_bool down_down = ta_keyboard_is_down(KEY_DOWN); - ta_bool enter_down = ta_keyboard_is_down(KEY_ENTER); - ta_bool up_pressed = up_down && !list->up_was_down; - ta_bool down_pressed = down_down && !list->down_was_down; - ta_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 (list->animation_active) { - list->animation_frame++; - - if (list->animation_frame >= TA_BUTTON_ANIMATION_FRAMES) { - list->animation_frame = TA_BUTTON_ANIMATION_FRAMES; - list->animation_active = ta_false; - } - - if (enter_pressed && list->buttons[list->selected].callback != 0) { - list->buttons[list->selected].callback(); - } - - return ta_true; - } - - if (down_pressed || up_pressed) { - list->animation_from = list->selected; - - if (down_pressed) { - list->selected = (list->selected + 1) % list->size; - } else { - list->selected = list->selected == 0 ? list->size - 1 : list->selected - 1; - } - - if (list->selected != list->animation_from) { - list->animation_frame = 0; - list->animation_active = ta_true; - } - } - - if (enter_pressed && list->buttons[list->selected].callback != 0) { - list->buttons[list->selected].callback(); - } - - return ta_true; + if (list == 0 || list->size == 0) { + return ta_false; + } + + list->pulse_frame = (list->pulse_frame + 1) % (TA_BUTTON_PULSE_HALF_FRAMES * 2); + + ta_bool up_down = ta_keyboard_is_down(KEY_UP); + ta_bool down_down = ta_keyboard_is_down(KEY_DOWN); + ta_bool enter_down = ta_keyboard_is_down(KEY_ENTER); + ta_bool up_pressed = up_down && !list->up_was_down; + ta_bool down_pressed = down_down && !list->down_was_down; + ta_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 (list->animation_active) { + list->animation_frame++; + + if (list->animation_frame >= TA_BUTTON_ANIMATION_FRAMES) { + list->animation_frame = TA_BUTTON_ANIMATION_FRAMES; + list->animation_active = ta_false; + } + + if (enter_pressed && list->buttons[list->selected].callback != 0) { + list->buttons[list->selected].callback(); + } + + return ta_true; + } + + if (down_pressed || up_pressed) { + list->animation_from = list->selected; + + if (down_pressed) { + list->selected = (list->selected + 1) % list->size; + } else { + list->selected = list->selected == 0 ? list->size - 1 : list->selected - 1; + } + + if (list->selected != list->animation_from) { + list->animation_frame = 0; + list->animation_active = ta_true; + } + } + + if (enter_pressed && list->buttons[list->selected].callback != 0) { + list->buttons[list->selected].callback(); + } + + return ta_true; } void ta_button_lists_draw(const ta_button_lists *list) { - if (list == 0 || list->size == 0) { - return; - } - - ta_uint32 numerator = (ta_uint32)ta_fb.width; - ta_uint32 denominator = 800; - - if ((ta_uint64)ta_fb.width * 600 >= (ta_uint64)ta_fb.height * 800) { - numerator = (ta_uint32)ta_fb.height; - denominator = 600; - } - - ta_uint32 font_size = (TA_BUTTON_FONT_SIZE * numerator * 2 + denominator) / (denominator * 2); - ta_int32 spacing = (ta_int32)((TA_BUTTON_SPACING * numerator * 2 + denominator) / (denominator * 2)); - - if (font_size == 0) { - font_size = 1; - } - - if (spacing == 0) { - spacing = 1; - } - - ta_int32 progress = 512; - if (list->animation_active) { - ta_int32 frame = (ta_int32)list->animation_frame; - progress = frame * frame * (24 - 2 * frame); - } - - ta_int32 center_y = (ta_int32)(ta_fb.height / 2); - ta_int32 selected_shift = (ta_int32)list->selected - (ta_int32)list->animation_from; - - for (ta_size i = 0; i < list->size; i++) { - ta_uint32 text_width = 0; - ta_uint32 text_height = 0; - - ta_text_measure(list->buttons[i].label, font_size, &text_width, &text_height); - - ta_int32 row_from = (ta_int32)i - (ta_int32)list->animation_from; - ta_int32 y = center_y + (row_from * spacing * 512 - selected_shift * spacing * progress) / 512 - (ta_int32)(text_height / 2); - - if (y < 0 || (ta_size)y >= ta_fb.height || text_width > ta_fb.width) { - continue; - } - - ta_int32 selection = i == list->animation_from ? 512 - progress : 0; - if (i == list->selected) { - selection += progress; - } - - ta_uint32 pulse_position = list->pulse_frame; - ta_uint32 pulse_distance = pulse_position <= TA_BUTTON_PULSE_HALF_FRAMES ? pulse_position : TA_BUTTON_PULSE_HALF_FRAMES * 2 - pulse_position; - ta_uint8 pulse_blue = (ta_uint8)(TA_BUTTON_COLOR_SELECTED - ((TA_BUTTON_COLOR_SELECTED - TA_BUTTON_COLOR_PULSE_BLUE_MIN) * pulse_distance / TA_BUTTON_PULSE_HALF_FRAMES)); - ta_uint8 red = (ta_uint8)((TA_BUTTON_COLOR_IDLE * 512 + (TA_BUTTON_COLOR_SELECTED - TA_BUTTON_COLOR_IDLE) * selection + 256) / 512); - ta_uint8 green = red; - ta_uint8 blue = (ta_uint8)((TA_BUTTON_COLOR_IDLE * 512 + ((ta_int32)pulse_blue - TA_BUTTON_COLOR_IDLE) * selection + 256) / 512); - ta_uint32 x = (ta_uint32)(ta_fb.width - text_width) / 2; - - ta_text_draw_outline(list->buttons[i].label, x, (ta_uint32)y, text_width, text_height, red, green, blue, 1, 0, 0, 0); - } + if (list == 0 || list->size == 0) { + return; + } + + ta_uint32 numerator = (ta_uint32)ta_fb.width; + ta_uint32 denominator = 800; + + if ((ta_uint64)ta_fb.width * 600 >= (ta_uint64)ta_fb.height * 800) { + numerator = (ta_uint32)ta_fb.height; + denominator = 600; + } + + ta_uint32 font_size = (TA_BUTTON_FONT_SIZE * numerator * 2 + denominator) / (denominator * 2); + ta_int32 spacing = (ta_int32)((TA_BUTTON_SPACING * numerator * 2 + denominator) / (denominator * 2)); + + if (font_size == 0) { + font_size = 1; + } + + if (spacing == 0) { + spacing = 1; + } + + ta_int32 progress = 512; + if (list->animation_active) { + ta_int32 frame = (ta_int32)list->animation_frame; + progress = frame * frame * (24 - 2 * frame); + } + + ta_int32 center_y = (ta_int32)(ta_fb.height / 2); + ta_int32 selected_shift = (ta_int32)list->selected - (ta_int32)list->animation_from; + + for (ta_size i = 0; i < list->size; i++) { + ta_uint32 text_width = 0; + ta_uint32 text_height = 0; + + ta_text_measure(list->buttons[i].label, font_size, &text_width, &text_height); + + ta_int32 row_from = (ta_int32)i - (ta_int32)list->animation_from; + ta_int32 y = center_y + (row_from * spacing * 512 - selected_shift * spacing * progress) / 512 - (ta_int32)(text_height / 2); + + if (y < 0 || (ta_size)y >= ta_fb.height || text_width > ta_fb.width) { + continue; + } + + ta_int32 selection = i == list->animation_from ? 512 - progress : 0; + if (i == list->selected) { + selection += progress; + } + + ta_uint32 pulse_position = list->pulse_frame; + ta_uint32 pulse_distance = pulse_position <= TA_BUTTON_PULSE_HALF_FRAMES ? pulse_position : TA_BUTTON_PULSE_HALF_FRAMES * 2 - pulse_position; + ta_uint8 pulse_blue = (ta_uint8)(TA_BUTTON_COLOR_SELECTED - ((TA_BUTTON_COLOR_SELECTED - TA_BUTTON_COLOR_PULSE_BLUE_MIN) * pulse_distance / TA_BUTTON_PULSE_HALF_FRAMES)); + ta_uint8 red = (ta_uint8)((TA_BUTTON_COLOR_IDLE * 512 + (TA_BUTTON_COLOR_SELECTED - TA_BUTTON_COLOR_IDLE) * selection + 256) / 512); + ta_uint8 green = red; + ta_uint8 blue = (ta_uint8)((TA_BUTTON_COLOR_IDLE * 512 + ((ta_int32)pulse_blue - TA_BUTTON_COLOR_IDLE) * selection + 256) / 512); + ta_uint32 x = (ta_uint32)(ta_fb.width - text_width) / 2; + + ta_text_draw_outline(list->buttons[i].label, x, (ta_uint32)y, text_width, text_height, red, green, blue, 1, 0, 0, 0); + } } void ta_button_lists_destroy(ta_button_lists *list) { - if (list == 0) { - return; - } + if (list == 0) { + return; + } - ta_free(list->buttons); - ta_button_lists_init(list); -} -\ No newline at end of file + ta_free(list->buttons); + ta_button_lists_init(list); +} diff --git a/src/ta_fb.c b/src/ta_fb.c @@ -3,51 +3,51 @@ ta_fbs ta_fb; ta_size ta_fb_init(ta_fbs *fb) { - if (fb == 0 || fb->width == 0 || fb->height == 0 || fb->bpp == 0 || fb->bpp % 8 != 0) { - return 0; - } - - ta_size bytes_per_pixel = fb->bpp / 8; - ta_size max_size = (ta_size)-1; - if (fb->width > max_size / bytes_per_pixel || fb->height > max_size / (fb->width * bytes_per_pixel)) { - return 0; - } - - ta_size size = fb->width * fb->height * bytes_per_pixel; - void *first = ta_malloc(size); - if (first == 0) { - return 0; - } - - void *second = ta_malloc(size); - if (second == 0) { - ta_free(first); - return 0; - } - - fb->size = size; - fb->buffers[0] = first; - fb->buffers[1] = second; - return size; + if (fb == 0 || fb->width == 0 || fb->height == 0 || fb->bpp == 0 || fb->bpp % 8 != 0) { + return 0; + } + + ta_size bytes_per_pixel = fb->bpp / 8; + ta_size max_size = (ta_size)-1; + if (fb->width > max_size / bytes_per_pixel || fb->height > max_size / (fb->width * bytes_per_pixel)) { + return 0; + } + + ta_size size = fb->width * fb->height * bytes_per_pixel; + void *first = ta_malloc(size); + if (first == 0) { + return 0; + } + + void *second = ta_malloc(size); + if (second == 0) { + ta_free(first); + return 0; + } + + fb->size = size; + fb->buffers[0] = first; + fb->buffers[1] = second; + return size; } void ta_fb_swap(ta_fbs *fb) { - void *temp = fb->buffers[0]; - fb->buffers[0] = fb->buffers[1]; - fb->buffers[1] = temp; + void *temp = fb->buffers[0]; + fb->buffers[0] = fb->buffers[1]; + fb->buffers[1] = temp; } void ta_fb_clear(ta_fbs *fb) { - ta_size *dest = (ta_size *)fb->buffers[1]; - ta_size num_words = fb->size / sizeof(ta_size); - - for (ta_size i = 0; i < num_words; i++) { - dest[i] = 0; - } - - unsigned char *byte_dest = (unsigned char *)fb->buffers[1]; - ta_size handled_bytes = num_words * sizeof(ta_size); - for (ta_size i = handled_bytes; i < fb->size; i++) { - byte_dest[i] = 0; - } + ta_size *dest = (ta_size *)fb->buffers[1]; + ta_size num_words = fb->size / sizeof(ta_size); + + for (ta_size i = 0; i < num_words; i++) { + dest[i] = 0; + } + + unsigned char *byte_dest = (unsigned char *)fb->buffers[1]; + ta_size handled_bytes = num_words * sizeof(ta_size); + for (ta_size i = handled_bytes; i < fb->size; i++) { + byte_dest[i] = 0; + } } diff --git a/src/ta_image.c b/src/ta_image.c @@ -1,628 +1,628 @@ #include "ta_api.h" -#define TAIF_FLAG_8BPP 0x01 +#define TAIF_FLAG_8BPP 0x01 #define TAIF_FLAG_TRANSPARENT 0x02 -#define TAIF_FLAG_ANIMATED 0x04 -#define TAIF_WINDOW_SIZE 4096 +#define TAIF_FLAG_ANIMATED 0x04 +#define TAIF_WINDOW_SIZE 4096 typedef struct { - ta_uint8 window[TAIF_WINDOW_SIZE]; - ta_uint32 stream_position; - ta_uint32 window_position; - ta_uint32 filled; - ta_uint32 match_distance; - ta_uint32 match_remaining; - ta_uint8 item_flags; - ta_uint8 flags_remaining; + ta_uint8 window[TAIF_WINDOW_SIZE]; + ta_uint32 stream_position; + ta_uint32 window_position; + ta_uint32 filled; + ta_uint32 match_distance; + ta_uint32 match_remaining; + ta_uint8 item_flags; + ta_uint8 flags_remaining; } ta_image_decoder; typedef struct ta_image_cache { - const ta_uint8 *data; - ta_uint32 length; - ta_uint32 width; - ta_uint32 height; - ta_uint32 stride; - ta_uint32 frame_size; - ta_uint16 frame_count; - ta_uint16 palette_entries; - ta_uint32 frames_decoded; - ta_uint8 flags; - ta_uint8 palette[256][3]; - const ta_uint8 *stream; - ta_uint32 stream_length; - ta_image_decoder decoder; - ta_uint8 *pixels; - ta_uint8 *scaled; - ta_uint32 scaled_width; - ta_uint32 scaled_height; - ta_uint8 scaled_bpp; - struct ta_image_cache *next; + const ta_uint8 *data; + ta_uint32 length; + ta_uint32 width; + ta_uint32 height; + ta_uint32 stride; + ta_uint32 frame_size; + ta_uint16 frame_count; + ta_uint16 palette_entries; + ta_uint32 frames_decoded; + ta_uint8 flags; + ta_uint8 palette[256][3]; + const ta_uint8 *stream; + ta_uint32 stream_length; + ta_image_decoder decoder; + ta_uint8 *pixels; + ta_uint8 *scaled; + ta_uint32 scaled_width; + ta_uint32 scaled_height; + ta_uint8 scaled_bpp; + struct ta_image_cache *next; } ta_image_cache; static ta_image_cache *image_cache; static ta_uint16 read_le16(const ta_uint8 *data) { - return (ta_uint16)((ta_uint16)data[0] | ((ta_uint16)data[1] << 8)); + return (ta_uint16)((ta_uint16)data[0] | ((ta_uint16)data[1] << 8)); } static ta_bool parse_image(const ta_uint8 *data, ta_uint32 length, ta_image_cache *image) { - if (data == 0 || length < 11 || data[0] != 'T' || data[1] != 'A' || data[2] != 'I' || data[3] != 'F' || data[4] != 1) { - return ta_false; - } - - ta_uint8 flags = data[5]; - if ((flags & 0xf8) != 0) { - return ta_false; - } - - ta_uint32 width = read_le16(data + 6); - ta_uint32 height = read_le16(data + 8); - ta_uint32 palette_entries = (ta_uint32)data[10] + 1; - ta_bool eight_bpp = (flags & TAIF_FLAG_8BPP) != 0; - ta_bool transparent = (flags & TAIF_FLAG_TRANSPARENT) != 0; - ta_uint32 max_entries = eight_bpp ? (transparent ? 255 : 256) : (transparent ? 15 : 16); - ta_uint32 header_size = 11; - ta_uint16 frame_count = 1; - - if (width == 0 || height == 0 || palette_entries > max_entries) { - return ta_false; - } - - if ((flags & TAIF_FLAG_ANIMATED) != 0) { - if (length < 14 || data[11] == 0) { - return ta_false; - } - - frame_count = read_le16(data + 12); - if (frame_count < 2) { - return ta_false; - } - - header_size = 14; - } - - ta_uint64 stride = eight_bpp ? width : (width + 1) / 2; - ta_uint64 frame_size = stride * height; - ta_uint64 max_size = (ta_uint64)(ta_size)-1; - ta_uint64 palette_size = (ta_uint64)palette_entries * 3; - - if (frame_size == 0 || frame_size > max_size || frame_size > 0xffffffffu || header_size + palette_size > length) { - return ta_false; - } - - const ta_uint8 *palette = data + header_size; - - image->pixels = (ta_uint8 *)ta_malloc((ta_size)frame_size); - if (image->pixels == 0) { - return ta_false; - } - - for (ta_uint32 i = 0; i < (ta_uint32)frame_size; i++) { - image->pixels[i] = 0; - } - - image->data = data; - image->length = length; - image->width = width; - image->height = height; - image->stride = (ta_uint32)stride; - image->frame_size = (ta_uint32)frame_size; - image->frame_count = frame_count; - image->palette_entries = (ta_uint16)palette_entries; - image->flags = flags; - image->stream = palette + palette_size; - image->stream_length = length - (ta_uint32)(header_size + palette_size); - - for (ta_uint32 i = 0; i < palette_entries; i++) { - for (ta_uint32 channel = 0; channel < 3; channel++) { - image->palette[i][channel] = palette[i * 3 + channel]; - } - } - - return ta_true; + if (data == 0 || length < 11 || data[0] != 'T' || data[1] != 'A' || data[2] != 'I' || data[3] != 'F' || data[4] != 1) { + return ta_false; + } + + ta_uint8 flags = data[5]; + if ((flags & 0xf8) != 0) { + return ta_false; + } + + ta_uint32 width = read_le16(data + 6); + ta_uint32 height = read_le16(data + 8); + ta_uint32 palette_entries = (ta_uint32)data[10] + 1; + ta_bool eight_bpp = (flags & TAIF_FLAG_8BPP) != 0; + ta_bool transparent = (flags & TAIF_FLAG_TRANSPARENT) != 0; + ta_uint32 max_entries = eight_bpp ? (transparent ? 255 : 256) : (transparent ? 15 : 16); + ta_uint32 header_size = 11; + ta_uint16 frame_count = 1; + + if (width == 0 || height == 0 || palette_entries > max_entries) { + return ta_false; + } + + if ((flags & TAIF_FLAG_ANIMATED) != 0) { + if (length < 14 || data[11] == 0) { + return ta_false; + } + + frame_count = read_le16(data + 12); + if (frame_count < 2) { + return ta_false; + } + + header_size = 14; + } + + ta_uint64 stride = eight_bpp ? width : (width + 1) / 2; + ta_uint64 frame_size = stride * height; + ta_uint64 max_size = (ta_uint64)(ta_size)-1; + ta_uint64 palette_size = (ta_uint64)palette_entries * 3; + + if (frame_size == 0 || frame_size > max_size || frame_size > 0xffffffffu || header_size + palette_size > length) { + return ta_false; + } + + const ta_uint8 *palette = data + header_size; + + image->pixels = (ta_uint8 *)ta_malloc((ta_size)frame_size); + if (image->pixels == 0) { + return ta_false; + } + + for (ta_uint32 i = 0; i < (ta_uint32)frame_size; i++) { + image->pixels[i] = 0; + } + + image->data = data; + image->length = length; + image->width = width; + image->height = height; + image->stride = (ta_uint32)stride; + image->frame_size = (ta_uint32)frame_size; + image->frame_count = frame_count; + image->palette_entries = (ta_uint16)palette_entries; + image->flags = flags; + image->stream = palette + palette_size; + image->stream_length = length - (ta_uint32)(header_size + palette_size); + + for (ta_uint32 i = 0; i < palette_entries; i++) { + for (ta_uint32 channel = 0; channel < 3; channel++) { + image->palette[i][channel] = palette[i * 3 + channel]; + } + } + + return ta_true; } static void decoder_reset(ta_image_cache *image) { - ta_image_decoder *decoder = &image->decoder; + ta_image_decoder *decoder = &image->decoder; - decoder->stream_position = 0; - decoder->window_position = 0; - decoder->filled = 0; - decoder->match_distance = 0; - decoder->match_remaining = 0; - decoder->item_flags = 0; - decoder->flags_remaining = 0; + decoder->stream_position = 0; + decoder->window_position = 0; + decoder->filled = 0; + decoder->match_distance = 0; + decoder->match_remaining = 0; + decoder->item_flags = 0; + decoder->flags_remaining = 0; - for (ta_uint32 i = 0; i < image->frame_size; i++) { - image->pixels[i] = 0; - } + for (ta_uint32 i = 0; i < image->frame_size; i++) { + image->pixels[i] = 0; + } - ta_free(image->scaled); + ta_free(image->scaled); - image->scaled = 0; - image->frames_decoded = 0; + image->scaled = 0; + image->frames_decoded = 0; } static ta_bool decode_next_frame(ta_image_cache *image) { - ta_image_decoder *decoder = &image->decoder; - const ta_uint8 *stream = image->stream; - ta_uint32 stream_length = image->stream_length; - ta_uint32 frame_size = image->frame_size; - ta_uint32 position = 0; - - while (position < frame_size) { - ta_uint8 value; - - if (decoder->match_remaining != 0) { - ta_uint32 source_position = (decoder->window_position + TAIF_WINDOW_SIZE - decoder->match_distance) & (TAIF_WINDOW_SIZE - 1); - - value = decoder->window[source_position]; - decoder->match_remaining--; - } else { - if (decoder->flags_remaining == 0) { - if (decoder->stream_position >= stream_length) { - return ta_false; - } - - decoder->item_flags = stream[decoder->stream_position++]; - decoder->flags_remaining = 8; - } - - ta_bool literal = (decoder->item_flags & 1) != 0; - - decoder->item_flags >>= 1; - decoder->flags_remaining--; - - if (literal) { - if (decoder->stream_position >= stream_length) { - return ta_false; - } - - value = stream[decoder->stream_position++]; - } else { - if (stream_length - decoder->stream_position < 2) { - return ta_false; - } - - ta_uint8 b0 = stream[decoder->stream_position++]; - ta_uint8 b1 = stream[decoder->stream_position++]; - - decoder->match_distance = ((((ta_uint32)b1 >> 4) << 8) | b0) + 1; - decoder->match_remaining = (b1 & 0x0f) + 3; - - if (decoder->match_distance > decoder->filled) { - return ta_false; - } - - continue; - } - } - - image->pixels[position++] ^= value; - decoder->window[decoder->window_position] = value; - decoder->window_position = (decoder->window_position + 1) & (TAIF_WINDOW_SIZE - 1); - - if (decoder->filled < TAIF_WINDOW_SIZE) { - decoder->filled++; - } - } - - ta_bool eight_bpp = (image->flags & TAIF_FLAG_8BPP) != 0; - ta_bool transparent = (image->flags & TAIF_FLAG_TRANSPARENT) != 0; - ta_uint32 max_index = transparent ? image->palette_entries : (ta_uint32)image->palette_entries - 1; - ta_uint32 full_bytes = eight_bpp ? image->width : image->width / 2; - ta_bool odd_column = !eight_bpp && (image->width & 1) != 0; - - for (ta_uint32 row = 0; row < image->height; row++) { - const ta_uint8 *line = image->pixels + (ta_size)row * image->stride; - - for (ta_uint32 i = 0; i < full_bytes; i++) { - if (eight_bpp) { - if (line[i] > max_index) { - return ta_false; - } - } else if ((ta_uint32)(line[i] >> 4) > max_index || (ta_uint32)(line[i] & 0x0f) > max_index) { - return ta_false; - } - } - - if (odd_column && (ta_uint32)(line[full_bytes] >> 4) > max_index) { - return ta_false; - } - } - - ta_free(image->scaled); - - image->scaled = 0; - image->frames_decoded++; - - return ta_true; + ta_image_decoder *decoder = &image->decoder; + const ta_uint8 *stream = image->stream; + ta_uint32 stream_length = image->stream_length; + ta_uint32 frame_size = image->frame_size; + ta_uint32 position = 0; + + while (position < frame_size) { + ta_uint8 value; + + if (decoder->match_remaining != 0) { + ta_uint32 source_position = (decoder->window_position + TAIF_WINDOW_SIZE - decoder->match_distance) & (TAIF_WINDOW_SIZE - 1); + + value = decoder->window[source_position]; + decoder->match_remaining--; + } else { + if (decoder->flags_remaining == 0) { + if (decoder->stream_position >= stream_length) { + return ta_false; + } + + decoder->item_flags = stream[decoder->stream_position++]; + decoder->flags_remaining = 8; + } + + ta_bool literal = (decoder->item_flags & 1) != 0; + + decoder->item_flags >>= 1; + decoder->flags_remaining--; + + if (literal) { + if (decoder->stream_position >= stream_length) { + return ta_false; + } + + value = stream[decoder->stream_position++]; + } else { + if (stream_length - decoder->stream_position < 2) { + return ta_false; + } + + ta_uint8 b0 = stream[decoder->stream_position++]; + ta_uint8 b1 = stream[decoder->stream_position++]; + + decoder->match_distance = ((((ta_uint32)b1 >> 4) << 8) | b0) + 1; + decoder->match_remaining = (b1 & 0x0f) + 3; + + if (decoder->match_distance > decoder->filled) { + return ta_false; + } + + continue; + } + } + + image->pixels[position++] ^= value; + decoder->window[decoder->window_position] = value; + decoder->window_position = (decoder->window_position + 1) & (TAIF_WINDOW_SIZE - 1); + + if (decoder->filled < TAIF_WINDOW_SIZE) { + decoder->filled++; + } + } + + ta_bool eight_bpp = (image->flags & TAIF_FLAG_8BPP) != 0; + ta_bool transparent = (image->flags & TAIF_FLAG_TRANSPARENT) != 0; + ta_uint32 max_index = transparent ? image->palette_entries : (ta_uint32)image->palette_entries - 1; + ta_uint32 full_bytes = eight_bpp ? image->width : image->width / 2; + ta_bool odd_column = !eight_bpp && (image->width & 1) != 0; + + for (ta_uint32 row = 0; row < image->height; row++) { + const ta_uint8 *line = image->pixels + (ta_size)row * image->stride; + + for (ta_uint32 i = 0; i < full_bytes; i++) { + if (eight_bpp) { + if (line[i] > max_index) { + return ta_false; + } + } else if ((ta_uint32)(line[i] >> 4) > max_index || (ta_uint32)(line[i] & 0x0f) > max_index) { + return ta_false; + } + } + + if (odd_column && (ta_uint32)(line[full_bytes] >> 4) > max_index) { + return ta_false; + } + } + + ta_free(image->scaled); + + image->scaled = 0; + image->frames_decoded++; + + return ta_true; } static ta_image_cache *find_image(const ta_uint8 *data, ta_uint32 length) { - for (ta_image_cache *image = image_cache; image != 0; image = image->next) { - if (image->data == data && image->length == length) { - return image; - } - } + for (ta_image_cache *image = image_cache; image != 0; image = image->next) { + if (image->data == data && image->length == length) { + return image; + } + } - return 0; + return 0; } ta_bool ta_image_init(const ta_uint8 *data, ta_uint32 length) { - if (find_image(data, length) != 0) { - return ta_true; - } - - ta_image_cache *image = (ta_image_cache *)ta_malloc(sizeof(*image)); - if (image == 0) { - return ta_false; - } - - *image = (ta_image_cache){0}; - - if (!parse_image(data, length, image)) { - ta_free(image); - return ta_false; - } - - if (!decode_next_frame(image)) { - ta_free(image->pixels); - ta_free(image); - return ta_false; - } - - image->next = image_cache; - image_cache = image; - return ta_true; + if (find_image(data, length) != 0) { + return ta_true; + } + + ta_image_cache *image = (ta_image_cache *)ta_malloc(sizeof(*image)); + if (image == 0) { + return ta_false; + } + + *image = (ta_image_cache){0}; + + if (!parse_image(data, length, image)) { + ta_free(image); + return ta_false; + } + + if (!decode_next_frame(image)) { + ta_free(image->pixels); + ta_free(image); + return ta_false; + } + + image->next = image_cache; + image_cache = image; + return ta_true; } ta_bool ta_image_get_size(const ta_uint8 *data, ta_uint32 length, ta_uint32 *width, ta_uint32 *height) { - ta_image_cache *image = find_image(data, length); - if (image == 0 || width == 0 || height == 0) { - return ta_false; - } - - *width = image->width; - *height = image->height; - - return ta_true; + ta_image_cache *image = find_image(data, length); + if (image == 0 || width == 0 || height == 0) { + return ta_false; + } + + *width = image->width; + *height = image->height; + + return ta_true; } static ta_image_cache *get_image(const ta_uint8 *data, ta_uint32 length, ta_uint16 frame) { - if (!ta_image_init(data, length)) { - return 0; - } + if (!ta_image_init(data, length)) { + return 0; + } - ta_image_cache *image = find_image(data, length); - if (frame >= image->frame_count) { - return 0; - } + ta_image_cache *image = find_image(data, length); + if (frame >= image->frame_count) { + return 0; + } - ta_uint32 wanted = (ta_uint32)frame + 1; + ta_uint32 wanted = (ta_uint32)frame + 1; - if (image->frames_decoded > wanted) { - decoder_reset(image); - } + if (image->frames_decoded > wanted) { + decoder_reset(image); + } - while (image->frames_decoded < wanted) { - if (!decode_next_frame(image)) { - decoder_reset(image); - return 0; - } - } + while (image->frames_decoded < wanted) { + if (!decode_next_frame(image)) { + decoder_reset(image); + return 0; + } + } - return image; + return image; } static ta_uint8 get_pixel_index(const ta_image_cache *image, ta_uint32 x, ta_uint32 y) { - if ((image->flags & TAIF_FLAG_8BPP) != 0) { - return image->pixels[y * image->stride + x]; - } + if ((image->flags & TAIF_FLAG_8BPP) != 0) { + return image->pixels[y * image->stride + x]; + } - ta_uint8 packed = image->pixels[y * image->stride + x / 2]; - return (x & 1) == 0 ? packed >> 4 : packed & 0x0f; + ta_uint8 packed = image->pixels[y * image->stride + x / 2]; + return (x & 1) == 0 ? packed >> 4 : packed & 0x0f; } typedef struct { - ta_uint16 first; - ta_uint16 second; - ta_uint8 fraction; + ta_uint16 first; + ta_uint16 second; + ta_uint8 fraction; } ta_image_axis; static ta_image_axis axis_position(ta_uint32 index, ta_uint32 count, ta_uint32 source_count) { - ta_image_axis axis; + ta_image_axis axis; #ifdef TA_DISABLE_BILINEAR_FILTERING - axis.first = (ta_uint16)((ta_uint64)index * source_count / count); - axis.second = axis.first; - axis.fraction = 0; + axis.first = (ta_uint16)((ta_uint64)index * source_count / count); + axis.second = axis.first; + axis.fraction = 0; #else - ta_uint64 position = ((ta_uint64)(2 * (ta_uint64)index + 1) * source_count * 128) / count; - - if (position <= 128) { - axis.first = 0; - axis.second = 0; - axis.fraction = 0; - } else { - position -= 128; - - ta_uint32 first = (ta_uint32)(position >> 8); - - if (first >= source_count - 1) { - axis.first = (ta_uint16)(source_count - 1); - axis.second = axis.first; - axis.fraction = 0; - } else { - axis.first = (ta_uint16)first; - axis.second = (ta_uint16)(first + 1); - axis.fraction = (ta_uint8)(position & 0xff); - } - } + ta_uint64 position = ((ta_uint64)(2 * (ta_uint64)index + 1) * source_count * 128) / count; + + if (position <= 128) { + axis.first = 0; + axis.second = 0; + axis.fraction = 0; + } else { + position -= 128; + + ta_uint32 first = (ta_uint32)(position >> 8); + + if (first >= source_count - 1) { + axis.first = (ta_uint16)(source_count - 1); + axis.second = axis.first; + axis.fraction = 0; + } else { + axis.first = (ta_uint16)first; + axis.second = (ta_uint16)(first + 1); + axis.fraction = (ta_uint8)(position & 0xff); + } + } #endif - return axis; + return axis; } static ta_uint32 sample_image(const ta_image_cache *image, ta_image_axis column, ta_image_axis row, ta_uint32 *red, ta_uint32 *green, ta_uint32 *blue) { - ta_uint32 weight_x0 = 256 - column.fraction; - ta_uint32 weight_y0 = 256 - row.fraction; - ta_bool transparent = (image->flags & TAIF_FLAG_TRANSPARENT) != 0; - - ta_uint32 weights[4] = { - weight_x0 * weight_y0, - column.fraction * weight_y0, - weight_x0 * row.fraction, - column.fraction * row.fraction - }; - - ta_uint8 indices[4] = { - get_pixel_index(image, column.first, row.first), - get_pixel_index(image, column.second, row.first), - get_pixel_index(image, column.first, row.second), - get_pixel_index(image, column.second, row.second) - }; - - ta_uint32 red_sum = 0; - ta_uint32 green_sum = 0; - ta_uint32 blue_sum = 0; - ta_uint32 alpha_sum = 0; - - for (ta_uint32 sample = 0; sample < 4; sample++) { - if (transparent && indices[sample] == 0) { - continue; - } - - ta_uint32 palette_index = indices[sample] - (transparent ? 1 : 0); - - red_sum += (ta_uint32)image->palette[palette_index][0] * weights[sample]; - green_sum += (ta_uint32)image->palette[palette_index][1] * weights[sample]; - blue_sum += (ta_uint32)image->palette[palette_index][2] * weights[sample]; - alpha_sum += weights[sample]; - } - - *red = red_sum; - *green = green_sum; - *blue = blue_sum; - - return alpha_sum; + ta_uint32 weight_x0 = 256 - column.fraction; + ta_uint32 weight_y0 = 256 - row.fraction; + ta_bool transparent = (image->flags & TAIF_FLAG_TRANSPARENT) != 0; + + ta_uint32 weights[4] = { + weight_x0 * weight_y0, + column.fraction * weight_y0, + weight_x0 * row.fraction, + column.fraction * row.fraction + }; + + ta_uint8 indices[4] = { + get_pixel_index(image, column.first, row.first), + get_pixel_index(image, column.second, row.first), + get_pixel_index(image, column.first, row.second), + get_pixel_index(image, column.second, row.second) + }; + + ta_uint32 red_sum = 0; + ta_uint32 green_sum = 0; + ta_uint32 blue_sum = 0; + ta_uint32 alpha_sum = 0; + + for (ta_uint32 sample = 0; sample < 4; sample++) { + if (transparent && indices[sample] == 0) { + continue; + } + + ta_uint32 palette_index = indices[sample] - (transparent ? 1 : 0); + + red_sum += (ta_uint32)image->palette[palette_index][0] * weights[sample]; + green_sum += (ta_uint32)image->palette[palette_index][1] * weights[sample]; + blue_sum += (ta_uint32)image->palette[palette_index][2] * weights[sample]; + alpha_sum += weights[sample]; + } + + *red = red_sum; + *green = green_sum; + *blue = blue_sum; + + return alpha_sum; } static void copy_bytes(ta_uint8 *destination, const ta_uint8 *source, ta_size count) { - if ((((ta_size)destination | (ta_size)source) & 3) == 0) { - ta_size words = count / 4; + if ((((ta_size)destination | (ta_size)source) & 3) == 0) { + ta_size words = count / 4; - for (ta_size i = 0; i < words; i++) { - ((ta_uint32 *)destination)[i] = ((const ta_uint32 *)source)[i]; - } + for (ta_size i = 0; i < words; i++) { + ((ta_uint32 *)destination)[i] = ((const ta_uint32 *)source)[i]; + } - destination += words * 4; - source += words * 4; - count &= 3; - } + destination += words * 4; + source += words * 4; + count &= 3; + } - while (count--) { - *destination++ = *source++; - } + while (count--) { + *destination++ = *source++; + } } static ta_bool prepare_scaled(ta_image_cache *image, ta_uint32 width, ta_uint32 height) { - if (image->scaled != 0 && image->scaled_width == width && image->scaled_height == height && image->scaled_bpp == ta_fb.bpp) { - return ta_true; - } + if (image->scaled != 0 && image->scaled_width == width && image->scaled_height == height && image->scaled_bpp == ta_fb.bpp) { + return ta_true; + } - ta_size bytes_per_pixel = ta_fb.bpp / 8; - ta_uint8 *scaled = (ta_uint8 *)ta_malloc((ta_size)width * height * bytes_per_pixel); - ta_image_axis *columns = (ta_image_axis *)ta_malloc((ta_size)width * sizeof(*columns)); + ta_size bytes_per_pixel = ta_fb.bpp / 8; + ta_uint8 *scaled = (ta_uint8 *)ta_malloc((ta_size)width * height * bytes_per_pixel); + ta_image_axis *columns = (ta_image_axis *)ta_malloc((ta_size)width * sizeof(*columns)); - if (scaled == 0 || columns == 0) { - ta_free(scaled); - ta_free(columns); + if (scaled == 0 || columns == 0) { + ta_free(scaled); + ta_free(columns); - return ta_false; - } + return ta_false; + } - for (ta_uint32 column = 0; column < width; column++) { - columns[column] = axis_position(column, width, image->width); - } + for (ta_uint32 column = 0; column < width; column++) { + columns[column] = axis_position(column, width, image->width); + } - ta_uint8 *output = scaled; + ta_uint8 *output = scaled; - for (ta_uint32 y = 0; y < height; y++) { - ta_image_axis row = axis_position(y, height, image->height); + for (ta_uint32 y = 0; y < height; y++) { + ta_image_axis row = axis_position(y, height, image->height); - for (ta_uint32 x = 0; x < width; x++) { - ta_uint32 red; - ta_uint32 green; - ta_uint32 blue; + for (ta_uint32 x = 0; x < width; x++) { + ta_uint32 red; + ta_uint32 green; + ta_uint32 blue; - sample_image(image, columns[x], row, &red, &green, &blue); + sample_image(image, columns[x], row, &red, &green, &blue); - red = (red + 32768) >> 16; - green = (green + 32768) >> 16; - blue = (blue + 32768) >> 16; + red = (red + 32768) >> 16; + green = (green + 32768) >> 16; + blue = (blue + 32768) >> 16; - if (ta_fb.bpp == 32) { - *(ta_uint32 *)output = (red << 16) | (green << 8) | blue; - output += 4; - } else { - *output++ = (ta_uint8)(((red >> 5) << 5) | ((green >> 5) << 2) | (blue >> 6)); - } - } - } + if (ta_fb.bpp == 32) { + *(ta_uint32 *)output = (red << 16) | (green << 8) | blue; + output += 4; + } else { + *output++ = (ta_uint8)(((red >> 5) << 5) | ((green >> 5) << 2) | (blue >> 6)); + } + } + } - ta_free(columns); - ta_free(image->scaled); + ta_free(columns); + ta_free(image->scaled); - image->scaled = scaled; - image->scaled_width = width; - image->scaled_height = height; - image->scaled_bpp = (ta_uint8)ta_fb.bpp; + image->scaled = scaled; + image->scaled_width = width; + image->scaled_height = height; + image->scaled_bpp = (ta_uint8)ta_fb.bpp; - return ta_true; + return ta_true; } ta_bool ta_image_prepare(const ta_uint8 *data, ta_uint32 length, ta_fixed width, ta_fixed height, ta_uint16 frame) { - if (data == 0 || length == 0 || width == 0 || height == 0 || width > TA_FIXED_ONE || height > TA_FIXED_ONE || ta_fb.buffers[1] == 0 || (ta_fb.bpp != 8 && ta_fb.bpp != 32)) { - return ta_false; - } + if (data == 0 || length == 0 || width == 0 || height == 0 || width > TA_FIXED_ONE || height > TA_FIXED_ONE || ta_fb.buffers[1] == 0 || (ta_fb.bpp != 8 && ta_fb.bpp != 32)) { + return ta_false; + } - ta_uint32 pixel_width = (ta_uint32)(((ta_uint64)width * ta_fb.width) >> 16); - ta_uint32 pixel_height = (ta_uint32)(((ta_uint64)height * ta_fb.height) >> 16); + ta_uint32 pixel_width = (ta_uint32)(((ta_uint64)width * ta_fb.width) >> 16); + ta_uint32 pixel_height = (ta_uint32)(((ta_uint64)height * ta_fb.height) >> 16); - if (pixel_width == 0 || pixel_height == 0) { - return ta_false; - } + if (pixel_width == 0 || pixel_height == 0) { + return ta_false; + } - ta_image_cache *image = get_image(data, length, frame); - if (image == 0) { - return ta_false; - } + ta_image_cache *image = get_image(data, length, frame); + if (image == 0) { + return ta_false; + } - if ((image->flags & TAIF_FLAG_TRANSPARENT) != 0) { - return ta_true; - } + if ((image->flags & TAIF_FLAG_TRANSPARENT) != 0) { + return ta_true; + } - return prepare_scaled(image, pixel_width, pixel_height); + return prepare_scaled(image, pixel_width, pixel_height); } ta_bool ta_image_draw(const ta_uint8 *data, ta_uint32 length, ta_fixed x, ta_fixed y, ta_fixed width, ta_fixed height, ta_uint16 frame) { - if (data == 0 || length == 0 || x > TA_FIXED_ONE || y > TA_FIXED_ONE || width == 0 || height == 0 || width > TA_FIXED_ONE || height > TA_FIXED_ONE || ta_fb.buffers[1] == 0 || (ta_fb.bpp != 8 && ta_fb.bpp != 32)) { - return ta_false; - } - - ta_uint32 pixel_x = (ta_uint32)(((ta_uint64)x * ta_fb.width) >> 16); - ta_uint32 pixel_y = (ta_uint32)(((ta_uint64)y * ta_fb.height) >> 16); - ta_uint32 pixel_width = (ta_uint32)(((ta_uint64)width * ta_fb.width) >> 16); - ta_uint32 pixel_height = (ta_uint32)(((ta_uint64)height * ta_fb.height) >> 16); - - if (pixel_width == 0 || pixel_height == 0) { - return ta_false; - } - - ta_image_cache *image = get_image(data, length, frame); - if (image == 0) { - return ta_false; - } - - ta_uint32 visible_width = 0; - ta_uint32 visible_height = 0; - - if (pixel_x < ta_fb.width) { - visible_width = pixel_width > ta_fb.width - pixel_x ? (ta_uint32)(ta_fb.width - pixel_x) : pixel_width; - } - - if (pixel_y < ta_fb.height) { - visible_height = pixel_height > ta_fb.height - pixel_y ? (ta_uint32)(ta_fb.height - pixel_y) : pixel_height; - } - - if (visible_width == 0 || visible_height == 0) { - return ta_true; - } - - ta_bool transparent = (image->flags & TAIF_FLAG_TRANSPARENT) != 0; - - if (!transparent && prepare_scaled(image, pixel_width, pixel_height)) { - ta_size bytes_per_pixel = ta_fb.bpp / 8; - - for (ta_uint32 image_y = 0; image_y < visible_height; image_y++) { - const ta_uint8 *source = image->scaled + (ta_size)image_y * pixel_width * bytes_per_pixel; - ta_uint8 *destination = (ta_uint8 *)ta_fb.buffers[1] + ((ta_size)(pixel_y + image_y) * ta_fb.width + pixel_x) * bytes_per_pixel; - - if (ta_fb.bpp == 8) { - copy_bytes(destination, source, visible_width); - } else { - const ta_uint32 *source32 = (const ta_uint32 *)source; - ta_uint32 *destination32 = (ta_uint32 *)destination; - - for (ta_uint32 image_x = 0; image_x < visible_width; image_x++) { - destination32[image_x] = (destination32[image_x] & 0xff000000u) | source32[image_x]; - } - } - } - - return ta_true; - } - - ta_image_axis *columns = (ta_image_axis *)ta_malloc((ta_size)visible_width * sizeof(*columns)); - if (columns == 0) { - return ta_false; - } - - for (ta_uint32 image_x = 0; image_x < visible_width; image_x++) { - columns[image_x] = axis_position(image_x, pixel_width, image->width); - } - - for (ta_uint32 image_y = 0; image_y < visible_height; image_y++) { - ta_image_axis row = axis_position(image_y, pixel_height, image->height); - ta_size row_start = (ta_size)(pixel_y + image_y) * ta_fb.width + pixel_x; - - for (ta_uint32 image_x = 0; image_x < visible_width; image_x++) { - ta_uint32 red; - ta_uint32 green; - ta_uint32 blue; - ta_uint32 alpha_sum = sample_image(image, columns[image_x], row, &red, &green, &blue); - - if (alpha_sum == 0) { - continue; - } - - ta_size destination_index = row_start + image_x; - ta_uint32 inverse_alpha = 65536 - alpha_sum; - - if (ta_fb.bpp == 32) { - ta_uint32 *pixels = (ta_uint32 *)ta_fb.buffers[1]; - ta_uint32 destination = pixels[destination_index]; - - red = (red + ((destination >> 16) & 0xff) * inverse_alpha + 32768) >> 16; - green = (green + ((destination >> 8) & 0xff) * inverse_alpha + 32768) >> 16; - blue = (blue + (destination & 0xff) * inverse_alpha + 32768) >> 16; - - pixels[destination_index] = (destination & 0xff000000u) | (red << 16) | (green << 8) | blue; - } else { - ta_uint8 *pixels = (ta_uint8 *)ta_fb.buffers[1]; - ta_uint32 destination = pixels[destination_index]; - - red = (red + (((destination >> 5) & 7) * 255 / 7) * inverse_alpha + 32768) >> 16; - green = (green + (((destination >> 2) & 7) * 255 / 7) * inverse_alpha + 32768) >> 16; - blue = (blue + ((destination & 3) * 255 / 3) * inverse_alpha + 32768) >> 16; - - pixels[destination_index] = (ta_uint8)(((red >> 5) << 5) | ((green >> 5) << 2) | (blue >> 6)); - } - } - } - - ta_free(columns); - - return ta_true; + if (data == 0 || length == 0 || x > TA_FIXED_ONE || y > TA_FIXED_ONE || width == 0 || height == 0 || width > TA_FIXED_ONE || height > TA_FIXED_ONE || ta_fb.buffers[1] == 0 || (ta_fb.bpp != 8 && ta_fb.bpp != 32)) { + return ta_false; + } + + ta_uint32 pixel_x = (ta_uint32)(((ta_uint64)x * ta_fb.width) >> 16); + ta_uint32 pixel_y = (ta_uint32)(((ta_uint64)y * ta_fb.height) >> 16); + ta_uint32 pixel_width = (ta_uint32)(((ta_uint64)width * ta_fb.width) >> 16); + ta_uint32 pixel_height = (ta_uint32)(((ta_uint64)height * ta_fb.height) >> 16); + + if (pixel_width == 0 || pixel_height == 0) { + return ta_false; + } + + ta_image_cache *image = get_image(data, length, frame); + if (image == 0) { + return ta_false; + } + + ta_uint32 visible_width = 0; + ta_uint32 visible_height = 0; + + if (pixel_x < ta_fb.width) { + visible_width = pixel_width > ta_fb.width - pixel_x ? (ta_uint32)(ta_fb.width - pixel_x) : pixel_width; + } + + if (pixel_y < ta_fb.height) { + visible_height = pixel_height > ta_fb.height - pixel_y ? (ta_uint32)(ta_fb.height - pixel_y) : pixel_height; + } + + if (visible_width == 0 || visible_height == 0) { + return ta_true; + } + + ta_bool transparent = (image->flags & TAIF_FLAG_TRANSPARENT) != 0; + + if (!transparent && prepare_scaled(image, pixel_width, pixel_height)) { + ta_size bytes_per_pixel = ta_fb.bpp / 8; + + for (ta_uint32 image_y = 0; image_y < visible_height; image_y++) { + const ta_uint8 *source = image->scaled + (ta_size)image_y * pixel_width * bytes_per_pixel; + ta_uint8 *destination = (ta_uint8 *)ta_fb.buffers[1] + ((ta_size)(pixel_y + image_y) * ta_fb.width + pixel_x) * bytes_per_pixel; + + if (ta_fb.bpp == 8) { + copy_bytes(destination, source, visible_width); + } else { + const ta_uint32 *source32 = (const ta_uint32 *)source; + ta_uint32 *destination32 = (ta_uint32 *)destination; + + for (ta_uint32 image_x = 0; image_x < visible_width; image_x++) { + destination32[image_x] = (destination32[image_x] & 0xff000000u) | source32[image_x]; + } + } + } + + return ta_true; + } + + ta_image_axis *columns = (ta_image_axis *)ta_malloc((ta_size)visible_width * sizeof(*columns)); + if (columns == 0) { + return ta_false; + } + + for (ta_uint32 image_x = 0; image_x < visible_width; image_x++) { + columns[image_x] = axis_position(image_x, pixel_width, image->width); + } + + for (ta_uint32 image_y = 0; image_y < visible_height; image_y++) { + ta_image_axis row = axis_position(image_y, pixel_height, image->height); + ta_size row_start = (ta_size)(pixel_y + image_y) * ta_fb.width + pixel_x; + + for (ta_uint32 image_x = 0; image_x < visible_width; image_x++) { + ta_uint32 red; + ta_uint32 green; + ta_uint32 blue; + ta_uint32 alpha_sum = sample_image(image, columns[image_x], row, &red, &green, &blue); + + if (alpha_sum == 0) { + continue; + } + + ta_size destination_index = row_start + image_x; + ta_uint32 inverse_alpha = 65536 - alpha_sum; + + if (ta_fb.bpp == 32) { + ta_uint32 *pixels = (ta_uint32 *)ta_fb.buffers[1]; + ta_uint32 destination = pixels[destination_index]; + + red = (red + ((destination >> 16) & 0xff) * inverse_alpha + 32768) >> 16; + green = (green + ((destination >> 8) & 0xff) * inverse_alpha + 32768) >> 16; + blue = (blue + (destination & 0xff) * inverse_alpha + 32768) >> 16; + + pixels[destination_index] = (destination & 0xff000000u) | (red << 16) | (green << 8) | blue; + } else { + ta_uint8 *pixels = (ta_uint8 *)ta_fb.buffers[1]; + ta_uint32 destination = pixels[destination_index]; + + red = (red + (((destination >> 5) & 7) * 255 / 7) * inverse_alpha + 32768) >> 16; + green = (green + (((destination >> 2) & 7) * 255 / 7) * inverse_alpha + 32768) >> 16; + blue = (blue + ((destination & 3) * 255 / 3) * inverse_alpha + 32768) >> 16; + + pixels[destination_index] = (ta_uint8)(((red >> 5) << 5) | ((green >> 5) << 2) | (blue >> 6)); + } + } + } + + ta_free(columns); + + return ta_true; } void ta_image_release(void) { - while (image_cache != 0) { - ta_image_cache *image = image_cache; - image_cache = image->next; - ta_free(image->pixels); - ta_free(image->scaled); - ta_free(image); - } + while (image_cache != 0) { + ta_image_cache *image = image_cache; + image_cache = image->next; + ta_free(image->pixels); + ta_free(image->scaled); + ta_free(image); + } } diff --git a/src/ta_keyboard.c b/src/ta_keyboard.c @@ -3,45 +3,45 @@ ta_keyboards ta_keyboard; ta_bool ta_keyboard_is_down(ta_keyboard_keys key) { - if (key == KEY_NONE) { - return ta_false; - } + if (key == KEY_NONE) { + return ta_false; + } - for (ta_size i = 0; i < TA_KEYBOARD_MAX_KEYS_DOWN; i++) { - if (ta_keyboard.keys_down[i] == (ta_uint8)key) { - return ta_true; - } - } + for (ta_size i = 0; i < TA_KEYBOARD_MAX_KEYS_DOWN; i++) { + if (ta_keyboard.keys_down[i] == (ta_uint8)key) { + return ta_true; + } + } - return ta_false; + return ta_false; } void ta_keyboard_key_down(ta_keyboard_keys key) { - if (key == KEY_NONE || ta_keyboard_is_down(key)) { - return; - } + if (key == KEY_NONE || ta_keyboard_is_down(key)) { + return; + } - for (ta_size i = 0; i < TA_KEYBOARD_MAX_KEYS_DOWN; i++) { - if (ta_keyboard.keys_down[i] == KEY_NONE) { - ta_keyboard.keys_down[i] = (ta_uint8)key; + for (ta_size i = 0; i < TA_KEYBOARD_MAX_KEYS_DOWN; i++) { + if (ta_keyboard.keys_down[i] == KEY_NONE) { + ta_keyboard.keys_down[i] = (ta_uint8)key; - return; - } - } + return; + } + } } void ta_keyboard_key_up(ta_keyboard_keys key) { - for (ta_size i = 0; i < TA_KEYBOARD_MAX_KEYS_DOWN; i++) { - if (ta_keyboard.keys_down[i] == (ta_uint8)key) { - ta_keyboard.keys_down[i] = KEY_NONE; + for (ta_size i = 0; i < TA_KEYBOARD_MAX_KEYS_DOWN; i++) { + if (ta_keyboard.keys_down[i] == (ta_uint8)key) { + ta_keyboard.keys_down[i] = KEY_NONE; - return; - } - } + return; + } + } } void ta_keyboard_clear(void) { - for (ta_size i = 0; i < TA_KEYBOARD_MAX_KEYS_DOWN; i++) { - ta_keyboard.keys_down[i] = KEY_NONE; - } + for (ta_size i = 0; i < TA_KEYBOARD_MAX_KEYS_DOWN; i++) { + ta_keyboard.keys_down[i] = KEY_NONE; + } } diff --git a/src/ta_main.c b/src/ta_main.c @@ -3,22 +3,22 @@ #include "ta_screen.h" void ta_main_init(void) { - ta_fb_init(&ta_fb); - ta_screen_init(); + ta_fb_init(&ta_fb); + ta_screen_init(); } ta_bool ta_main_update(void) { - if (!ta_screen_update()) { - return ta_false; - } + if (!ta_screen_update()) { + return ta_false; + } - ta_fb_swap(&ta_fb); + ta_fb_swap(&ta_fb); - return ta_true; + return ta_true; } void ta_main_destroy(void) { - ta_screen_destroy(); - - ta_exit(0); + ta_screen_destroy(); + + ta_exit(0); } diff --git a/src/ta_screen.c b/src/ta_screen.c @@ -1,6 +1,6 @@ #include "ta_screen.h" -#include "ta_types.h" #include "ta_image.h" +#include "ta_types.h" #include "screens/ta_screen_loading.h" #include "screens/ta_screen_main_menu.h" @@ -8,34 +8,34 @@ ta_screens ta_screen_current; void ta_screen_init(void) { - ta_screen_current = TA_SCREEN_LOADING; - ta_screen_loading_init(); + ta_screen_current = TA_SCREEN_LOADING; + ta_screen_loading_init(); } ta_bool ta_screen_update(void) { - switch (ta_screen_current) { - case TA_SCREEN_LOADING: { - ta_bool drawn = ta_screen_loading_update(); - if (ta_screen_current == TA_SCEEEN_MAIN_MENU) { - ta_screen_loading_destroy(); - ta_screen_main_menu_init(); - } - return drawn; - } - case TA_SCEEEN_MAIN_MENU: { - return ta_screen_main_menu_update(); - } - default: { - return ta_false; - } - } + switch (ta_screen_current) { + case TA_SCREEN_LOADING: { + ta_bool drawn = ta_screen_loading_update(); + if (ta_screen_current == TA_SCEEEN_MAIN_MENU) { + ta_screen_loading_destroy(); + ta_screen_main_menu_init(); + } + return drawn; + } + case TA_SCEEEN_MAIN_MENU: { + return ta_screen_main_menu_update(); + } + default: { + return ta_false; + } + } } void ta_screen_destroy(void) { - if (ta_screen_current == TA_SCREEN_LOADING) { - ta_screen_loading_destroy(); - } else if (ta_screen_current == TA_SCEEEN_MAIN_MENU) { - ta_screen_main_menu_destroy(); - } - ta_image_release(); + if (ta_screen_current == TA_SCREEN_LOADING) { + ta_screen_loading_destroy(); + } else if (ta_screen_current == TA_SCEEEN_MAIN_MENU) { + ta_screen_main_menu_destroy(); + } + ta_image_release(); } diff --git a/src/ta_text.c b/src/ta_text.c @@ -1,1220 +1,1216 @@ #include "ta_api.h" #include "ta_files.h" -#define ONE 65536 -#define MAX_COORD 16384 -#define MAX_SIZE 2048 +#define ONE 65536 +#define MAX_COORD 16384 +#define MAX_SIZE 2048 #define MAX_SEGMENTS 64 typedef struct { - ta_int32 x; - ta_int32 y; + ta_int32 x; + ta_int32 y; } ta_text_pt; typedef struct { - ta_int32 clip_x0; - ta_int32 clip_y0; - ta_int32 clip_x1; - ta_int32 clip_y1; - ta_int32 scale; - ta_uint8 red; - ta_uint8 green; - ta_uint8 blue; - ta_uint8 border_thickness; - ta_uint8 border_red; - ta_uint8 border_green; - ta_uint8 border_blue; - ta_uint8 *mask; - ta_int32 mask_x0; - ta_int32 mask_y0; - ta_int32 mask_stride; + ta_int32 clip_x0; + ta_int32 clip_y0; + ta_int32 clip_x1; + ta_int32 clip_y1; + ta_int32 scale; + ta_uint8 red; + ta_uint8 green; + ta_uint8 blue; + ta_uint8 border_thickness; + ta_uint8 border_red; + ta_uint8 border_green; + ta_uint8 border_blue; + ta_uint8 *mask; + ta_int32 mask_x0; + ta_int32 mask_y0; + ta_int32 mask_stride; } ta_text_ctx; typedef struct { - const ta_uint8 *glyf; - const ta_uint8 *loca; - const ta_uint8 *hmtx; - const ta_uint8 *cmap; - ta_uint32 glyf_length; - ta_uint32 cmap_length; - ta_uint32 units_per_em; - ta_uint32 horizontal_metric_count; - ta_uint32 glyph_count; - ta_bool long_loca; - ta_int32 ascent; - ta_int32 descent; - ta_int32 line_gap; + const ta_uint8 *glyf; + const ta_uint8 *loca; + const ta_uint8 *hmtx; + const ta_uint8 *cmap; + ta_uint32 glyf_length; + ta_uint32 cmap_length; + ta_uint32 units_per_em; + ta_uint32 horizontal_metric_count; + ta_uint32 glyph_count; + ta_bool long_loca; + ta_int32 ascent; + ta_int32 descent; + ta_int32 line_gap; } ta_text_font; static ta_text_font font; static int font_state; static ta_uint32 read_u16(const ta_uint8 *data) { - return ((ta_uint32)data[0] << 8) | data[1]; + return ((ta_uint32)data[0] << 8) | data[1]; } static ta_int32 read_s16(const ta_uint8 *data) { - ta_uint32 value = read_u16(data); + ta_uint32 value = read_u16(data); - if (value >= 0x8000) { - return (ta_int32)value - 0x10000; - } + if (value >= 0x8000) { + return (ta_int32)value - 0x10000; + } - return (ta_int32)value; + return (ta_int32)value; } static ta_uint32 read_u32(const ta_uint8 *data) { - return (read_u16(data) << 16) | read_u16(data + 2); + return (read_u16(data) << 16) | read_u16(data + 2); } static ta_uint64 unsigned_divide64(ta_uint64 numerator, ta_uint32 denominator) { #if TA_BITS == 64 - return numerator / denominator; + return numerator / denominator; #else - if ((numerator >> 32) == 0) { - return (ta_uint32)numerator / denominator; - } + if ((numerator >> 32) == 0) { + return (ta_uint32)numerator / denominator; + } - ta_uint64 quotient = 0; - ta_uint64 remainder = 0; + ta_uint64 quotient = 0; + ta_uint64 remainder = 0; - for (int bit = 63; bit >= 0; bit--) { - remainder = (remainder << 1) | ((numerator >> bit) & 1); + for (int bit = 63; bit >= 0; bit--) { + remainder = (remainder << 1) | ((numerator >> bit) & 1); - if (remainder >= denominator) { - remainder -= denominator; - quotient |= (ta_uint64)1 << bit; - } - } + if (remainder >= denominator) { + remainder -= denominator; + quotient |= (ta_uint64)1 << bit; + } + } - return quotient; + return quotient; #endif } static ta_int64 signed_divide64(ta_int64 numerator, ta_int32 denominator) { - ta_bool negative = ta_false; - ta_uint64 unsigned_numerator; - ta_uint32 unsigned_denominator; - - if (numerator < 0) { - negative = !negative; - unsigned_numerator = (ta_uint64)(-numerator); - } else { - unsigned_numerator = (ta_uint64)numerator; - } - - if (denominator < 0) { - negative = !negative; - unsigned_denominator = (ta_uint32)(-denominator); - } else { - unsigned_denominator = (ta_uint32)denominator; - } - - ta_int64 quotient = (ta_int64)unsigned_divide64(unsigned_numerator, unsigned_denominator); - - return negative ? -quotient : quotient; + ta_bool negative = ta_false; + ta_uint64 unsigned_numerator; + ta_uint32 unsigned_denominator; + + if (numerator < 0) { + negative = !negative; + unsigned_numerator = (ta_uint64)(-numerator); + } else { + unsigned_numerator = (ta_uint64)numerator; + } + + if (denominator < 0) { + negative = !negative; + unsigned_denominator = (ta_uint32)(-denominator); + } else { + unsigned_denominator = (ta_uint32)denominator; + } + + ta_int64 quotient = (ta_int64)unsigned_divide64(unsigned_numerator, unsigned_denominator); + + return negative ? -quotient : quotient; } static ta_int32 fixed_multiply(ta_int32 a, ta_int32 b) { - return (ta_int32)(((ta_int64)a * b) >> 16); + return (ta_int32)(((ta_int64)a * b) >> 16); } static const ta_uint8 *find_table(const ta_uint8 *data, ta_uint32 length, const char *tag, ta_uint32 *out_length) { - if (length < 12) { - return 0; - } + if (length < 12) { + return 0; + } - ta_uint32 table_count = read_u16(data + 4); + ta_uint32 table_count = read_u16(data + 4); - if (length < 12 + table_count * 16) { - return 0; - } + if (length < 12 + table_count * 16) { + return 0; + } - for (ta_uint32 i = 0; i < table_count; i++) { - const ta_uint8 *record = data + 12 + i * 16; + for (ta_uint32 i = 0; i < table_count; i++) { + const ta_uint8 *record = data + 12 + i * 16; - if (record[0] == (ta_uint8)tag[0] && record[1] == (ta_uint8)tag[1] && record[2] == (ta_uint8)tag[2] && record[3] == (ta_uint8)tag[3]) { - ta_uint32 offset = read_u32(record + 8); - ta_uint32 table_length = read_u32(record + 12); + if (record[0] == (ta_uint8)tag[0] && record[1] == (ta_uint8)tag[1] && record[2] == (ta_uint8)tag[2] && record[3] == (ta_uint8)tag[3]) { + ta_uint32 offset = read_u32(record + 8); + ta_uint32 table_length = read_u32(record + 12); - if (offset > length || table_length > length - offset) { - return 0; - } + if (offset > length || table_length > length - offset) { + return 0; + } - *out_length = table_length; + *out_length = table_length; - return data + offset; - } - } + return data + offset; + } + } - return 0; + return 0; } static ta_bool font_load(void) { - const ta_uint8 *font_data = ta_file_dejavu_sans; - ta_uint32 font_length = ta_file_dejavu_sans_len; - - ta_uint32 head_length; - ta_uint32 hhea_length; - ta_uint32 maxp_length; - ta_uint32 loca_length; - ta_uint32 hmtx_length; - ta_uint32 cmap_length; - - const ta_uint8 *head = find_table(font_data, font_length, "head", &head_length); - const ta_uint8 *hhea = find_table(font_data, font_length, "hhea", &hhea_length); - const ta_uint8 *maxp = find_table(font_data, font_length, "maxp", &maxp_length); - const ta_uint8 *cmap = find_table(font_data, font_length, "cmap", &cmap_length); - - font.loca = find_table(font_data, font_length, "loca", &loca_length); - font.hmtx = find_table(font_data, font_length, "hmtx", &hmtx_length); - font.glyf = find_table(font_data, font_length, "glyf", &font.glyf_length); - - if (!head || !hhea || !maxp || !font.loca || !font.hmtx || !font.glyf || !cmap) { - return ta_false; - } - - if (head_length < 54 || hhea_length < 36 || maxp_length < 6 || cmap_length < 4) { - return ta_false; - } - - font.units_per_em = read_u16(head + 18); - font.long_loca = read_s16(head + 50) != 0; - font.ascent = read_s16(hhea + 4); - font.descent = read_s16(hhea + 6); - font.line_gap = read_s16(hhea + 8); - font.horizontal_metric_count = read_u16(hhea + 34); - font.glyph_count = read_u16(maxp + 4); - - if (font.units_per_em == 0 || font.horizontal_metric_count == 0 || font.glyph_count == 0) { - return ta_false; - } - - if (font.ascent - font.descent + font.line_gap <= 0) { - return ta_false; - } - - if (loca_length < (font.glyph_count + 1) * (font.long_loca ? 4u : 2u)) { - return ta_false; - } - - if (hmtx_length < font.horizontal_metric_count * 4) { - return ta_false; - } - - const ta_uint8 *best_subtable = 0; - ta_uint32 best_length = 0; - ta_uint32 subtable_count = read_u16(cmap + 2); - - if (cmap_length < 4 + subtable_count * 8) { - return ta_false; - } - - for (ta_uint32 i = 0; i < subtable_count; i++) { - const ta_uint8 *record = cmap + 4 + i * 8; - ta_uint32 platform = read_u16(record); - ta_uint32 encoding = read_u16(record + 2); - ta_uint32 offset = read_u32(record + 4); - - if (offset > cmap_length || cmap_length - offset < 16) { - continue; - } - - if (read_u16(cmap + offset) != 4) { - continue; - } - - if (platform == 3 && encoding == 1) { - best_subtable = cmap + offset; - best_length = cmap_length - offset; - - break; - } - - if (platform == 0 && !best_subtable) { - best_subtable = cmap + offset; - best_length = cmap_length - offset; - } - } - - if (!best_subtable) { - return ta_false; - } - - ta_uint32 segment_count_x2 = read_u16(best_subtable + 6); - - if (best_length < 16 + segment_count_x2 * 4) { - return ta_false; - } - - font.cmap = best_subtable; - font.cmap_length = best_length; - - return ta_true; + const ta_uint8 *font_data = ta_file_dejavu_sans; + ta_uint32 font_length = ta_file_dejavu_sans_len; + + ta_uint32 head_length; + ta_uint32 hhea_length; + ta_uint32 maxp_length; + ta_uint32 loca_length; + ta_uint32 hmtx_length; + ta_uint32 cmap_length; + + const ta_uint8 *head = find_table(font_data, font_length, "head", &head_length); + const ta_uint8 *hhea = find_table(font_data, font_length, "hhea", &hhea_length); + const ta_uint8 *maxp = find_table(font_data, font_length, "maxp", &maxp_length); + const ta_uint8 *cmap = find_table(font_data, font_length, "cmap", &cmap_length); + + font.loca = find_table(font_data, font_length, "loca", &loca_length); + font.hmtx = find_table(font_data, font_length, "hmtx", &hmtx_length); + font.glyf = find_table(font_data, font_length, "glyf", &font.glyf_length); + + if (!head || !hhea || !maxp || !font.loca || !font.hmtx || !font.glyf || !cmap) { + return ta_false; + } + + if (head_length < 54 || hhea_length < 36 || maxp_length < 6 || cmap_length < 4) { + return ta_false; + } + + font.units_per_em = read_u16(head + 18); + font.long_loca = read_s16(head + 50) != 0; + font.ascent = read_s16(hhea + 4); + font.descent = read_s16(hhea + 6); + font.line_gap = read_s16(hhea + 8); + font.horizontal_metric_count = read_u16(hhea + 34); + font.glyph_count = read_u16(maxp + 4); + + if (font.units_per_em == 0 || font.horizontal_metric_count == 0 || font.glyph_count == 0) { + return ta_false; + } + + if (font.ascent - font.descent + font.line_gap <= 0) { + return ta_false; + } + + if (loca_length < (font.glyph_count + 1) * (font.long_loca ? 4u : 2u)) { + return ta_false; + } + + if (hmtx_length < font.horizontal_metric_count * 4) { + return ta_false; + } + + const ta_uint8 *best_subtable = 0; + ta_uint32 best_length = 0; + ta_uint32 subtable_count = read_u16(cmap + 2); + + if (cmap_length < 4 + subtable_count * 8) { + return ta_false; + } + + for (ta_uint32 i = 0; i < subtable_count; i++) { + const ta_uint8 *record = cmap + 4 + i * 8; + ta_uint32 platform = read_u16(record); + ta_uint32 encoding = read_u16(record + 2); + ta_uint32 offset = read_u32(record + 4); + + if (offset > cmap_length || cmap_length - offset < 16) { + continue; + } + + if (read_u16(cmap + offset) != 4) { + continue; + } + + if (platform == 3 && encoding == 1) { + best_subtable = cmap + offset; + best_length = cmap_length - offset; + + break; + } + + if (platform == 0 && !best_subtable) { + best_subtable = cmap + offset; + best_length = cmap_length - offset; + } + } + + if (!best_subtable) { + return ta_false; + } + + ta_uint32 segment_count_x2 = read_u16(best_subtable + 6); + + if (best_length < 16 + segment_count_x2 * 4) { + return ta_false; + } + + font.cmap = best_subtable; + font.cmap_length = best_length; + + return ta_true; } static ta_bool font_ready(void) { - if (font_state == 0) { - font_state = font_load() ? 1 : -1; - } + if (font_state == 0) { + font_state = font_load() ? 1 : -1; + } - return font_state == 1; + return font_state == 1; } static ta_uint32 glyph_for(ta_uint32 character) { - if (character > 0xFFFF) { - return 0; - } + if (character > 0xFFFF) { + return 0; + } - const ta_uint8 *table = font.cmap; - ta_uint32 segment_count_x2 = read_u16(table + 6); - const ta_uint8 *end_codes = table + 14; - const ta_uint8 *start_codes = table + 16 + segment_count_x2; - const ta_uint8 *deltas = table + 16 + segment_count_x2 * 2; - const ta_uint8 *range_offsets = table + 16 + segment_count_x2 * 3; + const ta_uint8 *table = font.cmap; + ta_uint32 segment_count_x2 = read_u16(table + 6); + const ta_uint8 *end_codes = table + 14; + const ta_uint8 *start_codes = table + 16 + segment_count_x2; + const ta_uint8 *deltas = table + 16 + segment_count_x2 * 2; + const ta_uint8 *range_offsets = table + 16 + segment_count_x2 * 3; - for (ta_uint32 i = 0; i < segment_count_x2 / 2; i++) { - if (character > read_u16(end_codes + i * 2)) { - continue; - } + for (ta_uint32 i = 0; i < segment_count_x2 / 2; i++) { + if (character > read_u16(end_codes + i * 2)) { + continue; + } - ta_uint32 start = read_u16(start_codes + i * 2); + ta_uint32 start = read_u16(start_codes + i * 2); - if (character < start) { - return 0; - } + if (character < start) { + return 0; + } - ta_uint32 delta = read_u16(deltas + i * 2); - ta_uint32 range_offset = read_u16(range_offsets + i * 2); + ta_uint32 delta = read_u16(deltas + i * 2); + ta_uint32 range_offset = read_u16(range_offsets + i * 2); - if (range_offset == 0) { - return (character + delta) & 0xFFFF; - } + if (range_offset == 0) { + return (character + delta) & 0xFFFF; + } - const ta_uint8 *entry = range_offsets + i * 2 + range_offset + (character - start) * 2; + const ta_uint8 *entry = range_offsets + i * 2 + range_offset + (character - start) * 2; - if ((ta_size)(entry + 2 - font.cmap) > font.cmap_length) { - return 0; - } + if ((ta_size)(entry + 2 - font.cmap) > font.cmap_length) { + return 0; + } - ta_uint32 glyph = read_u16(entry); + ta_uint32 glyph = read_u16(entry); - return glyph ? (glyph + delta) & 0xFFFF : 0; - } + return glyph ? (glyph + delta) & 0xFFFF : 0; + } - return 0; + return 0; } static ta_uint32 advance_of(ta_uint32 glyph_id) { - if (glyph_id >= font.horizontal_metric_count) { - glyph_id = font.horizontal_metric_count - 1; - } + if (glyph_id >= font.horizontal_metric_count) { + glyph_id = font.horizontal_metric_count - 1; + } - return read_u16(font.hmtx + glyph_id * 4); + return read_u16(font.hmtx + glyph_id * 4); } static const ta_uint8 *glyph_data(ta_uint32 glyph_id, ta_uint32 *length) { - if (glyph_id >= font.glyph_count) { - return 0; - } + if (glyph_id >= font.glyph_count) { + return 0; + } - ta_uint32 begin; - ta_uint32 end; + ta_uint32 begin; + ta_uint32 end; - if (font.long_loca) { - begin = read_u32(font.loca + glyph_id * 4); - end = read_u32(font.loca + glyph_id * 4 + 4); - } else { - begin = read_u16(font.loca + glyph_id * 2) * 2; - end = read_u16(font.loca + glyph_id * 2 + 2) * 2; - } + if (font.long_loca) { + begin = read_u32(font.loca + glyph_id * 4); + end = read_u32(font.loca + glyph_id * 4 + 4); + } else { + begin = read_u16(font.loca + glyph_id * 2) * 2; + end = read_u16(font.loca + glyph_id * 2 + 2) * 2; + } - if (end <= begin || end > font.glyf_length || end - begin < 10) { - return 0; - } + if (end <= begin || end > font.glyf_length || end - begin < 10) { + return 0; + } - *length = end - begin; + *length = end - begin; - return font.glyf + begin; + return font.glyf + begin; } -static void raster_line(ta_int32 *coverage, ta_int32 stride, ta_int32 width, ta_int32 height, - ta_int32 start_x, ta_int32 start_y, ta_int32 end_x, ta_int32 end_y) { - if (start_y == end_y) { - return; - } +static void raster_line(ta_int32 *coverage, ta_int32 stride, ta_int32 width, ta_int32 height, ta_int32 start_x, ta_int32 start_y, ta_int32 end_x, ta_int32 end_y) { + if (start_y == end_y) { + return; + } - ta_int32 direction = 1; + ta_int32 direction = 1; - if (start_y > end_y) { - ta_int32 temp; + if (start_y > end_y) { + ta_int32 temp; - direction = -1; + direction = -1; - temp = start_x; - start_x = end_x; - end_x = temp; + temp = start_x; + start_x = end_x; + end_x = temp; - temp = start_y; - start_y = end_y; - end_y = temp; - } + temp = start_y; + start_y = end_y; + end_y = temp; + } - if (end_y <= 0 || start_y >= height * ONE) { - return; - } + if (end_y <= 0 || start_y >= height * ONE) { + return; + } - ta_int32 delta_x = end_x - start_x; - ta_int32 delta_y_total = end_y - start_y; - ta_int32 first_row = start_y < 0 ? 0 : (start_y >> 16); - ta_int32 last_row = (end_y + (ONE - 1)) >> 16; + ta_int32 delta_x = end_x - start_x; + ta_int32 delta_y_total = end_y - start_y; + ta_int32 first_row = start_y < 0 ? 0 : (start_y >> 16); + ta_int32 last_row = (end_y + (ONE - 1)) >> 16; - if (last_row > height) { - last_row = height; - } + if (last_row > height) { + last_row = height; + } - ta_int32 current_x = start_x; + ta_int32 current_x = start_x; - if (start_y < 0) { - current_x = start_x + (ta_int32)signed_divide64((ta_int64)delta_x * (0 - start_y), delta_y_total); - } + if (start_y < 0) { + current_x = start_x + (ta_int32)signed_divide64((ta_int64)delta_x * (0 - start_y), delta_y_total); + } - ta_int32 max_x = width * ONE; + ta_int32 max_x = width * ONE; - for (ta_int32 row_index = first_row; row_index < last_row; row_index++) { - ta_int32 row_top = row_index * ONE; - ta_int32 row_bottom = row_top + ONE; - ta_int32 segment_top = start_y > row_top ? start_y : row_top; - ta_int32 segment_bottom = end_y < row_bottom ? end_y : row_bottom; - ta_int32 segment_height = segment_bottom - segment_top; - ta_int32 next_x; + for (ta_int32 row_index = first_row; row_index < last_row; row_index++) { + ta_int32 row_top = row_index * ONE; + ta_int32 row_bottom = row_top + ONE; + ta_int32 segment_top = start_y > row_top ? start_y : row_top; + ta_int32 segment_bottom = end_y < row_bottom ? end_y : row_bottom; + ta_int32 segment_height = segment_bottom - segment_top; + ta_int32 next_x; - if (segment_bottom == end_y) { - next_x = end_x; - } else { - next_x = start_x + (ta_int32)signed_divide64((ta_int64)delta_x * (segment_bottom - start_y), delta_y_total); - } + if (segment_bottom == end_y) { + next_x = end_x; + } else { + next_x = start_x + (ta_int32)signed_divide64((ta_int64)delta_x * (segment_bottom - start_y), delta_y_total); + } - ta_int32 signed_height = segment_height * direction; - ta_int32 left_x = current_x < next_x ? current_x : next_x; - ta_int32 right_x = current_x < next_x ? next_x : current_x; + ta_int32 signed_height = segment_height * direction; + ta_int32 left_x = current_x < next_x ? current_x : next_x; + ta_int32 right_x = current_x < next_x ? next_x : current_x; - if (left_x < 0) { - left_x = 0; - } + if (left_x < 0) { + left_x = 0; + } - if (right_x < 0) { - right_x = 0; - } + if (right_x < 0) { + right_x = 0; + } - if (left_x > max_x) { - left_x = max_x; - } + if (left_x > max_x) { + left_x = max_x; + } - if (right_x > max_x) { - right_x = max_x; - } + if (right_x > max_x) { + right_x = max_x; + } - ta_int32 first_cell = left_x >> 16; - ta_int32 last_cell = (right_x + (ONE - 1)) >> 16; - ta_int32 *row = coverage + row_index * stride; + ta_int32 first_cell = left_x >> 16; + ta_int32 last_cell = (right_x + (ONE - 1)) >> 16; + ta_int32 *row = coverage + row_index * stride; - if (last_cell <= first_cell + 1) { - ta_int32 middle_offset = ((left_x + right_x) >> 1) - (first_cell << 16); + if (last_cell <= first_cell + 1) { + ta_int32 middle_offset = ((left_x + right_x) >> 1) - (first_cell << 16); - row[first_cell] += signed_height - fixed_multiply(signed_height, middle_offset); - row[first_cell + 1] += fixed_multiply(signed_height, middle_offset); - } else { - ta_int32 span = right_x - left_x; - ta_int32 first_fraction = left_x - (first_cell << 16); - ta_int32 first_remaining = ONE - first_fraction; - ta_int32 last_fraction = right_x - ((last_cell - 1) << 16); - ta_int32 first_area = (ta_int32)unsigned_divide64((ta_uint64)first_remaining * (ta_uint64)first_remaining, (ta_uint32)span * 2); - ta_int32 last_area = (ta_int32)unsigned_divide64((ta_uint64)last_fraction * (ta_uint64)last_fraction, (ta_uint32)span * 2); + row[first_cell] += signed_height - fixed_multiply(signed_height, middle_offset); + row[first_cell + 1] += fixed_multiply(signed_height, middle_offset); + } else { + ta_int32 span = right_x - left_x; + ta_int32 first_fraction = left_x - (first_cell << 16); + ta_int32 first_remaining = ONE - first_fraction; + ta_int32 last_fraction = right_x - ((last_cell - 1) << 16); + ta_int32 first_area = (ta_int32)unsigned_divide64((ta_uint64)first_remaining * (ta_uint64)first_remaining, (ta_uint32)span * 2); + ta_int32 last_area = (ta_int32)unsigned_divide64((ta_uint64)last_fraction * (ta_uint64)last_fraction, (ta_uint32)span * 2); - row[first_cell] += fixed_multiply(signed_height, first_area); + row[first_cell] += fixed_multiply(signed_height, first_area); - if (last_cell == first_cell + 2) { - row[first_cell + 1] += fixed_multiply(signed_height, ONE - first_area - last_area); - } else { - ta_int32 slope_step = (ta_int32)unsigned_divide64((ta_uint64)ONE << 16, (ta_uint32)span); - ta_int32 second_area = (ta_int32)unsigned_divide64((ta_uint64)(ONE + ONE / 2 - first_fraction) << 16, (ta_uint32)span); + if (last_cell == first_cell + 2) { + row[first_cell + 1] += fixed_multiply(signed_height, ONE - first_area - last_area); + } else { + ta_int32 slope_step = (ta_int32)unsigned_divide64((ta_uint64)ONE << 16, (ta_uint32)span); + ta_int32 second_area = (ta_int32)unsigned_divide64((ta_uint64)(ONE + ONE / 2 - first_fraction) << 16, (ta_uint32)span); - row[first_cell + 1] += fixed_multiply(signed_height, second_area - first_area); + row[first_cell + 1] += fixed_multiply(signed_height, second_area - first_area); - for (ta_int32 cell = first_cell + 2; cell < last_cell - 1; cell++) { - row[cell] += fixed_multiply(signed_height, slope_step); - } + for (ta_int32 cell = first_cell + 2; cell < last_cell - 1; cell++) { + row[cell] += fixed_multiply(signed_height, slope_step); + } - ta_int32 final_area = second_area + (last_cell - first_cell - 3) * slope_step; + ta_int32 final_area = second_area + (last_cell - first_cell - 3) * slope_step; - row[last_cell - 1] += fixed_multiply(signed_height, ONE - final_area - last_area); - } + row[last_cell - 1] += fixed_multiply(signed_height, ONE - final_area - last_area); + } - row[last_cell] += fixed_multiply(signed_height, last_area); - } + row[last_cell] += fixed_multiply(signed_height, last_area); + } - current_x = next_x; - } + current_x = next_x; + } } static void raster_quad(ta_int32 *coverage, ta_int32 stride, ta_int32 width, ta_int32 height, ta_text_pt start, ta_text_pt control, ta_text_pt end) { - ta_int32 second_diff_x = start.x - 2 * control.x + end.x; - ta_int32 second_diff_y = start.y - 2 * control.y + end.y; + ta_int32 second_diff_x = start.x - 2 * control.x + end.x; + ta_int32 second_diff_y = start.y - 2 * control.y + end.y; - if (second_diff_x < 0) { - second_diff_x = -second_diff_x; - } + if (second_diff_x < 0) { + second_diff_x = -second_diff_x; + } - if (second_diff_y < 0) { - second_diff_y = -second_diff_y; - } + if (second_diff_y < 0) { + second_diff_y = -second_diff_y; + } - ta_int32 deviation = (second_diff_x + second_diff_y) >> 2; - ta_int32 segment_count = 1; + ta_int32 deviation = (second_diff_x + second_diff_y) >> 2; + ta_int32 segment_count = 1; - while (segment_count < MAX_SEGMENTS && deviation > (ONE / 16) * segment_count * segment_count) { - segment_count++; - } + while (segment_count < MAX_SEGMENTS && deviation > (ONE / 16) * segment_count * segment_count) { + segment_count++; + } - ta_text_pt previous = start; + ta_text_pt previous = start; - for (ta_int32 i = 1; i <= segment_count; i++) { - ta_text_pt current; + for (ta_int32 i = 1; i <= segment_count; i++) { + ta_text_pt current; - if (i == segment_count) { - current = end; - } else { - ta_int32 t = (ta_int32)((ta_uint32)i * ONE / (ta_uint32)segment_count); - ta_int32 one_minus_t = ONE - t; - ta_int64 weight_start = (ta_int64)one_minus_t * one_minus_t; - ta_int64 weight_ctrl = (ta_int64)2 * one_minus_t * t; - ta_int64 weight_end = (ta_int64)t * t; + if (i == segment_count) { + current = end; + } else { + ta_int32 t = (ta_int32)((ta_uint32)i * ONE / (ta_uint32)segment_count); + ta_int32 one_minus_t = ONE - t; + ta_int64 weight_start = (ta_int64)one_minus_t * one_minus_t; + ta_int64 weight_ctrl = (ta_int64)2 * one_minus_t * t; + ta_int64 weight_end = (ta_int64)t * t; - current.x = (ta_int32)((weight_start * start.x + weight_ctrl * control.x + weight_end * end.x) >> 32); - current.y = (ta_int32)((weight_start * start.y + weight_ctrl * control.y + weight_end * end.y) >> 32); - } + current.x = (ta_int32)((weight_start * start.x + weight_ctrl * control.x + weight_end * end.x) >> 32); + current.y = (ta_int32)((weight_start * start.y + weight_ctrl * control.y + weight_end * end.y) >> 32); + } - raster_line(coverage, stride, width, height, previous.x, previous.y, current.x, current.y); - previous = current; - } + raster_line(coverage, stride, width, height, previous.x, previous.y, current.x, current.y); + previous = current; + } } #define DIV255(t) ((((t) + 128) + (((t) + 128) >> 8)) >> 8) static ta_uint32 blend_channel(ta_uint32 destination, ta_uint32 source, ta_uint32 alpha) { - ta_uint32 total = destination * (255 - alpha) + source * alpha; + ta_uint32 total = destination * (255 - alpha) + source * alpha; - return DIV255(total); + return DIV255(total); } static void put_pixel(const ta_text_ctx *ctx, ta_int32 pixel_x, ta_int32 pixel_y, ta_uint32 alpha) { - ta_size index = (ta_size)pixel_y * ta_fb.width + (ta_size)pixel_x; - - if (ta_fb.bpp == 32) { - ta_uint32 *pixel = (ta_uint32 *)ta_fb.buffers[1] + index; - ta_uint32 destination = *pixel; - ta_uint32 red = blend_channel((destination >> 16) & 255, ctx->red, alpha); - ta_uint32 green = blend_channel((destination >> 8) & 255, ctx->green, alpha); - ta_uint32 blue = blend_channel(destination & 255, ctx->blue, alpha); - - *pixel = (destination & 0xFF000000u) | (red << 16) | (green << 8) | blue; - } else { - ta_uint8 *pixel = (ta_uint8 *)ta_fb.buffers[1] + index; - ta_uint32 destination = *pixel; - ta_uint32 dest_red = (destination >> 5) & 7; - ta_uint32 dest_green = (destination >> 2) & 7; - ta_uint32 dest_blue = destination & 3; - - dest_red = (dest_red << 5) | (dest_red << 2) | (dest_red >> 1); - dest_green = (dest_green << 5) | (dest_green << 2) | (dest_green >> 1); - dest_blue = dest_blue * 85; - - ta_uint32 red = blend_channel(dest_red, ctx->red, alpha); - ta_uint32 green = blend_channel(dest_green, ctx->green, alpha); - ta_uint32 blue = blend_channel(dest_blue, ctx->blue, alpha); - - *pixel = (ta_uint8)(((red >> 5) << 5) | ((green >> 5) << 2) | (blue >> 6)); - } + ta_size index = (ta_size)pixel_y * ta_fb.width + (ta_size)pixel_x; + + if (ta_fb.bpp == 32) { + ta_uint32 *pixel = (ta_uint32 *)ta_fb.buffers[1] + index; + ta_uint32 destination = *pixel; + ta_uint32 red = blend_channel((destination >> 16) & 255, ctx->red, alpha); + ta_uint32 green = blend_channel((destination >> 8) & 255, ctx->green, alpha); + ta_uint32 blue = blend_channel(destination & 255, ctx->blue, alpha); + + *pixel = (destination & 0xFF000000u) | (red << 16) | (green << 8) | blue; + } else { + ta_uint8 *pixel = (ta_uint8 *)ta_fb.buffers[1] + index; + ta_uint32 destination = *pixel; + ta_uint32 dest_red = (destination >> 5) & 7; + ta_uint32 dest_green = (destination >> 2) & 7; + ta_uint32 dest_blue = destination & 3; + + dest_red = (dest_red << 5) | (dest_red << 2) | (dest_red >> 1); + dest_green = (dest_green << 5) | (dest_green << 2) | (dest_green >> 1); + dest_blue = dest_blue * 85; + + ta_uint32 red = blend_channel(dest_red, ctx->red, alpha); + ta_uint32 green = blend_channel(dest_green, ctx->green, alpha); + ta_uint32 blue = blend_channel(dest_blue, ctx->blue, alpha); + + *pixel = (ta_uint8)(((red >> 5) << 5) | ((green >> 5) << 2) | (blue >> 6)); + } } static void emit_pixel(const ta_text_ctx *ctx, ta_int32 pixel_x, ta_int32 pixel_y, ta_uint32 alpha) { - if (ctx->mask != 0) { - ta_uint8 *target = ctx->mask + (ta_size)(pixel_y - ctx->mask_y0) * (ta_size)ctx->mask_stride + (ta_size)(pixel_x - ctx->mask_x0); - ta_uint32 old = *target; + if (ctx->mask != 0) { + ta_uint8 *target = ctx->mask + (ta_size)(pixel_y - ctx->mask_y0) * (ta_size)ctx->mask_stride + (ta_size)(pixel_x - ctx->mask_x0); + ta_uint32 old = *target; - *target = (ta_uint8)(old + alpha - DIV255(old * alpha)); + *target = (ta_uint8)(old + alpha - DIV255(old * alpha)); - return; - } + return; + } - put_pixel(ctx, pixel_x, pixel_y, alpha); + put_pixel(ctx, pixel_x, pixel_y, alpha); } static ta_text_pt transform_point(ta_int32 font_x, ta_int32 font_y, ta_int32 origin_x, ta_int32 origin_y, ta_int32 scale) { - ta_text_pt point; + ta_text_pt point; - point.x = origin_x + (ta_int32)((ta_int64)font_x * scale); - point.y = origin_y - (ta_int32)((ta_int64)font_y * scale); + point.x = origin_x + (ta_int32)((ta_int64)font_x * scale); + point.y = origin_y - (ta_int32)((ta_int64)font_y * scale); - return point; + return point; } static void draw_glyph(const ta_text_ctx *ctx, ta_uint32 glyph_id, ta_int32 pen_x, ta_int32 baseline_y) { - ta_uint32 glyph_length; - const ta_uint8 *glyph = glyph_data(glyph_id, &glyph_length); + ta_uint32 glyph_length; + const ta_uint8 *glyph = glyph_data(glyph_id, &glyph_length); - if (!glyph) { - return; - } + if (!glyph) { + return; + } - ta_int32 contour_count = read_s16(glyph); - - if (contour_count <= 0) { - return; - } + ta_int32 contour_count = read_s16(glyph); + + if (contour_count <= 0) { + return; + } - ta_int32 scale = ctx->scale; - ta_int32 glyph_left = pen_x + (ta_int32)((ta_int64)read_s16(glyph + 2) * scale); - ta_int32 glyph_right = pen_x + (ta_int32)((ta_int64)read_s16(glyph + 6) * scale); - ta_int32 glyph_top = baseline_y - (ta_int32)((ta_int64)read_s16(glyph + 8) * scale); - ta_int32 glyph_bottom = baseline_y - (ta_int32)((ta_int64)read_s16(glyph + 4) * scale); - ta_int32 region_x0 = glyph_left >> 16; - ta_int32 region_x1 = (glyph_right + (ONE - 1)) >> 16; - ta_int32 region_y0 = glyph_top >> 16; - ta_int32 region_y1 = (glyph_bottom + (ONE - 1)) >> 16; + ta_int32 scale = ctx->scale; + ta_int32 glyph_left = pen_x + (ta_int32)((ta_int64)read_s16(glyph + 2) * scale); + ta_int32 glyph_right = pen_x + (ta_int32)((ta_int64)read_s16(glyph + 6) * scale); + ta_int32 glyph_top = baseline_y - (ta_int32)((ta_int64)read_s16(glyph + 8) * scale); + ta_int32 glyph_bottom = baseline_y - (ta_int32)((ta_int64)read_s16(glyph + 4) * scale); + ta_int32 region_x0 = glyph_left >> 16; + ta_int32 region_x1 = (glyph_right + (ONE - 1)) >> 16; + ta_int32 region_y0 = glyph_top >> 16; + ta_int32 region_y1 = (glyph_bottom + (ONE - 1)) >> 16; - if (region_x0 < ctx->clip_x0) { - region_x0 = ctx->clip_x0; - } + if (region_x0 < ctx->clip_x0) { + region_x0 = ctx->clip_x0; + } - if (region_y0 < ctx->clip_y0) { - region_y0 = ctx->clip_y0; - } + if (region_y0 < ctx->clip_y0) { + region_y0 = ctx->clip_y0; + } - if (region_x1 > ctx->clip_x1) { - region_x1 = ctx->clip_x1; - } + if (region_x1 > ctx->clip_x1) { + region_x1 = ctx->clip_x1; + } - if (region_y1 > ctx->clip_y1) { - region_y1 = ctx->clip_y1; - } + if (region_y1 > ctx->clip_y1) { + region_y1 = ctx->clip_y1; + } - if (region_x0 >= region_x1 || region_y0 >= region_y1) { - return; - } + if (region_x0 >= region_x1 || region_y0 >= region_y1) { + return; + } - ta_int32 region_width = region_x1 - region_x0; - ta_int32 region_height = region_y1 - region_y0; - ta_int32 stride = region_width + 2; - ta_size coverage_bytes = (ta_size)stride * (ta_size)region_height * sizeof(ta_int32); - const ta_uint8 *end = glyph + glyph_length; - const ta_uint8 *cursor = glyph + 10; + ta_int32 region_width = region_x1 - region_x0; + ta_int32 region_height = region_y1 - region_y0; + ta_int32 stride = region_width + 2; + ta_size coverage_bytes = (ta_size)stride * (ta_size)region_height * sizeof(ta_int32); + const ta_uint8 *end = glyph + glyph_length; + const ta_uint8 *cursor = glyph + 10; - if ((ta_size)(end - cursor) < (ta_size)contour_count * 2 + 2) { - return; - } + if ((ta_size)(end - cursor) < (ta_size)contour_count * 2 + 2) { + return; + } - ta_uint32 point_count = read_u16(cursor + (contour_count - 1) * 2) + 1; - const ta_uint8 *contour_ends = cursor; + ta_uint32 point_count = read_u16(cursor + (contour_count - 1) * 2) + 1; + const ta_uint8 *contour_ends = cursor; - cursor += contour_count * 2; - cursor += 2 + read_u16(cursor); + cursor += contour_count * 2; + cursor += 2 + read_u16(cursor); - if (cursor > end || point_count > 4096) { - return; - } + if (cursor > end || point_count > 4096) { + return; + } - ta_size points_bytes = (ta_size)point_count * 5; - void *memory = ta_malloc(points_bytes + coverage_bytes + 8); + ta_size points_bytes = (ta_size)point_count * 5; + void *memory = ta_malloc(points_bytes + coverage_bytes + 8); - if (!memory) { - return; - } + if (!memory) { + return; + } - ta_int16 *point_x = (ta_int16 *)memory; - ta_int16 *point_y = point_x + point_count; - ta_uint8 *flags = (ta_uint8 *)(point_y + point_count); - ta_int32 *coverage = (ta_int32 *)(((ta_size)(flags + point_count) + 7) & ~(ta_size)7); - ta_bool parse_ok = ta_true; + ta_int16 *point_x = (ta_int16 *)memory; + ta_int16 *point_y = point_x + point_count; + ta_uint8 *flags = (ta_uint8 *)(point_y + point_count); + ta_int32 *coverage = (ta_int32 *)(((ta_size)(flags + point_count) + 7) & ~(ta_size)7); + ta_bool parse_ok = ta_true; - for (ta_uint32 i = 0; i < point_count && parse_ok;) { - if (cursor >= end) { - parse_ok = ta_false; + for (ta_uint32 i = 0; i < point_count && parse_ok;) { + if (cursor >= end) { + parse_ok = ta_false; - break; - } + break; + } - ta_uint8 flag = *cursor++; + ta_uint8 flag = *cursor++; - flags[i++] = flag; + flags[i++] = flag; - if (flag & 8) { - if (cursor >= end) { - parse_ok = ta_false; + if (flag & 8) { + if (cursor >= end) { + parse_ok = ta_false; - break; - } + break; + } - ta_uint32 repeat_count = *cursor++; + ta_uint32 repeat_count = *cursor++; - while (repeat_count > 0 && i < point_count) { - flags[i++] = flag; - repeat_count--; - } - } - } + while (repeat_count > 0 && i < point_count) { + flags[i++] = flag; + repeat_count--; + } + } + } - for (ta_uint32 pass = 0; pass < 2 && parse_ok; pass++) { - ta_int16 *output = pass ? point_y : point_x; - ta_uint8 short_bit = pass ? 4 : 2; - ta_uint8 same_bit = pass ? 32 : 16; - ta_int32 value = 0; + for (ta_uint32 pass = 0; pass < 2 && parse_ok; pass++) { + ta_int16 *output = pass ? point_y : point_x; + ta_uint8 short_bit = pass ? 4 : 2; + ta_uint8 same_bit = pass ? 32 : 16; + ta_int32 value = 0; - for (ta_uint32 i = 0; i < point_count; i++) { - ta_uint8 flag = flags[i]; + for (ta_uint32 i = 0; i < point_count; i++) { + ta_uint8 flag = flags[i]; - if (flag & short_bit) { - if (cursor >= end) { - parse_ok = ta_false; + if (flag & short_bit) { + if (cursor >= end) { + parse_ok = ta_false; - break; - } + break; + } - ta_int32 delta = *cursor++; + ta_int32 delta = *cursor++; - value += (flag & same_bit) ? delta : -delta; - } else if (!(flag & same_bit)) { - if (end - cursor < 2) { - parse_ok = ta_false; + value += (flag & same_bit) ? delta : -delta; + } else if (!(flag & same_bit)) { + if (end - cursor < 2) { + parse_ok = ta_false; - break; - } + break; + } - value += read_s16(cursor); - cursor += 2; - } + value += read_s16(cursor); + cursor += 2; + } - output[i] = (ta_int16)value; - } - } + output[i] = (ta_int16)value; + } + } - if (!parse_ok) { - ta_free(memory); + if (!parse_ok) { + ta_free(memory); - return; - } + return; + } - for (ta_size i = 0; i < coverage_bytes / sizeof(ta_int32); i++) { - coverage[i] = 0; - } + for (ta_size i = 0; i < coverage_bytes / sizeof(ta_int32); i++) { + coverage[i] = 0; + } - ta_int32 origin_x = pen_x - region_x0 * ONE; - ta_int32 origin_y = baseline_y - region_y0 * ONE; + ta_int32 origin_x = pen_x - region_x0 * ONE; + ta_int32 origin_y = baseline_y - region_y0 * ONE; #define POINT(index) transform_point((ta_int32)point_x[index], (ta_int32)point_y[index], origin_x, origin_y, scale) - ta_uint32 contour_first = 0; - - for (ta_int32 contour = 0; contour < contour_count; contour++) { - ta_uint32 contour_last = read_u16(contour_ends + contour * 2); - ta_uint32 contour_start = contour_first; - - contour_first = contour_last + 1; - - if (contour_last < contour_start || contour_last >= point_count || contour_last - contour_start < 1) { - continue; - } - - ta_uint32 contour_points = contour_last - contour_start + 1; - - ta_text_pt start_point; - ta_uint32 begin; - ta_uint32 count; - - if (flags[contour_start] & 1) { - start_point = POINT(contour_start); - begin = contour_start + 1; - count = contour_points - 1; - } else if (flags[contour_last] & 1) { - start_point = POINT(contour_last); - begin = contour_start; - count = contour_points - 1; - } else { - ta_text_pt first_point = POINT(contour_start); - ta_text_pt last_point = POINT(contour_last); - start_point.x = (first_point.x >> 1) + (last_point.x >> 1); - start_point.y = (first_point.y >> 1) + (last_point.y >> 1); - begin = contour_start; - count = contour_points; - } - - ta_text_pt current = start_point; - ta_text_pt control = start_point; - ta_bool has_control = ta_false; - - for (ta_uint32 k = 0; k < count; k++) { - ta_uint32 index = begin + k; - ta_text_pt point = POINT(index); - - if (flags[index] & 1) { - if (has_control) { - raster_quad(coverage, stride, region_width, region_height, current, control, point); - } else { - raster_line(coverage, stride, region_width, region_height, current.x, current.y, point.x, point.y); - } - - current = point; - has_control = ta_false; - } else if (has_control) { - ta_text_pt midpoint; - - midpoint.x = (control.x >> 1) + (point.x >> 1); - midpoint.y = (control.y >> 1) + (point.y >> 1); - - raster_quad(coverage, stride, region_width, region_height, current, control, midpoint); - - current = midpoint; - control = point; - } else { - control = point; - has_control = ta_true; - } - } - - if (has_control) { - raster_quad(coverage, stride, region_width, region_height, current, control, start_point); - } else { - raster_line(coverage, stride, region_width, region_height, current.x, current.y, start_point.x, start_point.y); - } - } + ta_uint32 contour_first = 0; + + for (ta_int32 contour = 0; contour < contour_count; contour++) { + ta_uint32 contour_last = read_u16(contour_ends + contour * 2); + ta_uint32 contour_start = contour_first; + + contour_first = contour_last + 1; + + if (contour_last < contour_start || contour_last >= point_count || contour_last - contour_start < 1) { + continue; + } + + ta_uint32 contour_points = contour_last - contour_start + 1; + + ta_text_pt start_point; + ta_uint32 begin; + ta_uint32 count; + + if (flags[contour_start] & 1) { + start_point = POINT(contour_start); + begin = contour_start + 1; + count = contour_points - 1; + } else if (flags[contour_last] & 1) { + start_point = POINT(contour_last); + begin = contour_start; + count = contour_points - 1; + } else { + ta_text_pt first_point = POINT(contour_start); + ta_text_pt last_point = POINT(contour_last); + start_point.x = (first_point.x >> 1) + (last_point.x >> 1); + start_point.y = (first_point.y >> 1) + (last_point.y >> 1); + begin = contour_start; + count = contour_points; + } + + ta_text_pt current = start_point; + ta_text_pt control = start_point; + ta_bool has_control = ta_false; + + for (ta_uint32 k = 0; k < count; k++) { + ta_uint32 index = begin + k; + ta_text_pt point = POINT(index); + + if (flags[index] & 1) { + if (has_control) { + raster_quad(coverage, stride, region_width, region_height, current, control, point); + } else { + raster_line(coverage, stride, region_width, region_height, current.x, current.y, point.x, point.y); + } + + current = point; + has_control = ta_false; + } else if (has_control) { + ta_text_pt midpoint; + + midpoint.x = (control.x >> 1) + (point.x >> 1); + midpoint.y = (control.y >> 1) + (point.y >> 1); + + raster_quad(coverage, stride, region_width, region_height, current, control, midpoint); + + current = midpoint; + control = point; + } else { + control = point; + has_control = ta_true; + } + } + + if (has_control) { + raster_quad(coverage, stride, region_width, region_height, current, control, start_point); + } else { + raster_line(coverage, stride, region_width, region_height, current.x, current.y, start_point.x, start_point.y); + } + } #undef POINT - for (ta_int32 row_index = 0; row_index < region_height; row_index++) { - ta_int32 running_sum = 0; - const ta_int32 *row = coverage + row_index * stride; + for (ta_int32 row_index = 0; row_index < region_height; row_index++) { + ta_int32 running_sum = 0; + const ta_int32 *row = coverage + row_index * stride; - for (ta_int32 column = 0; column < region_width; column++) { - running_sum += row[column]; + for (ta_int32 column = 0; column < region_width; column++) { + running_sum += row[column]; - ta_int32 amount = running_sum < 0 ? -running_sum : running_sum; + ta_int32 amount = running_sum < 0 ? -running_sum : running_sum; - if (amount > ONE) { - amount = ONE; - } + if (amount > ONE) { + amount = ONE; + } - ta_uint32 alpha = ((ta_uint32)amount * 255 + 0x8000) >> 16; + ta_uint32 alpha = ((ta_uint32)amount * 255 + 0x8000) >> 16; - if (alpha) { - emit_pixel(ctx, region_x0 + column, region_y0 + row_index, alpha); - } - } - } + if (alpha) { + emit_pixel(ctx, region_x0 + column, region_y0 + row_index, alpha); + } + } + } - ta_free(memory); + ta_free(memory); } static ta_bool printable(ta_uint32 character) { - return character >= 32 && character != 127; + return character >= 32 && character != 127; } static ta_uint32 line_height_units(void) { - return (ta_uint32)(font.ascent - font.descent + font.line_gap); + return (ta_uint32)(font.ascent - font.descent + font.line_gap); } static void measure_units(const char *text, ta_uint32 *max_width, ta_uint32 *lines) { - ta_uint32 current_width = 0; - ta_uint32 best_width = 0; - ta_uint32 line_count = 1; - - for (; *text; text++) { - ta_uint32 character = (ta_uint8)*text; - - if (character == '\n') { - if (current_width > best_width) { - best_width = current_width; - } - - current_width = 0; - line_count++; - } else if (printable(character)) { - current_width += advance_of(glyph_for(character)); - } - } - - if (current_width > best_width) { - best_width = current_width; - } - - *max_width = best_width; - *lines = line_count; + ta_uint32 current_width = 0; + ta_uint32 best_width = 0; + ta_uint32 line_count = 1; + + for (; *text; text++) { + ta_uint32 character = (ta_uint8)*text; + + if (character == '\n') { + if (current_width > best_width) { + best_width = current_width; + } + + current_width = 0; + line_count++; + } else if (printable(character)) { + current_width += advance_of(glyph_for(character)); + } + } + + if (current_width > best_width) { + best_width = current_width; + } + + *max_width = best_width; + *lines = line_count; } static ta_bool fb_usable(void) { - return ta_fb.buffers[1] != 0 && (ta_fb.bpp == 32 || ta_fb.bpp == 8); + return ta_fb.buffers[1] != 0 && (ta_fb.bpp == 32 || ta_fb.bpp == 8); } static ta_int32 fb_limit(ta_size value) { - return value > MAX_COORD ? MAX_COORD : (ta_int32)value; + return value > MAX_COORD ? MAX_COORD : (ta_int32)value; } static void draw_text_pass(const char *text, ta_int32 x, ta_int32 y, const ta_text_ctx *ctx) { - ta_int32 scale = ctx->scale; - ta_int32 ascent = (ta_int32)((ta_int64)font.ascent * scale); - ta_int32 line_height = (ta_int32)((ta_int64)line_height_units() * scale); - ta_int32 pen_x = x * ONE; - ta_int32 baseline_y = y * ONE + ascent; + ta_int32 scale = ctx->scale; + ta_int32 ascent = (ta_int32)((ta_int64)font.ascent * scale); + ta_int32 line_height = (ta_int32)((ta_int64)line_height_units() * scale); + ta_int32 pen_x = x * ONE; + ta_int32 baseline_y = y * ONE + ascent; - for (; *text; text++) { - ta_uint32 character = (ta_uint8)*text; + for (; *text; text++) { + ta_uint32 character = (ta_uint8)*text; - if (character == '\n') { - pen_x = x * ONE; - baseline_y += line_height; + if (character == '\n') { + pen_x = x * ONE; + baseline_y += line_height; - if (baseline_y - ascent >= ctx->clip_y1 * ONE) { - break; - } + if (baseline_y - ascent >= ctx->clip_y1 * ONE) { + break; + } - continue; - } + continue; + } - if (!printable(character) || pen_x >= ctx->clip_x1 * ONE) { - continue; - } + if (!printable(character) || pen_x >= ctx->clip_x1 * ONE) { + continue; + } - ta_uint32 glyph_id = glyph_for(character); + ta_uint32 glyph_id = glyph_for(character); - draw_glyph(ctx, glyph_id, pen_x, baseline_y); - pen_x += (ta_int32)((ta_int64)advance_of(glyph_id) * scale); - } + draw_glyph(ctx, glyph_id, pen_x, baseline_y); + pen_x += (ta_int32)((ta_int64)advance_of(glyph_id) * scale); + } } static void draw_text_direct(const char *text, ta_int32 x, ta_int32 y, const ta_text_ctx *ctx) { - if (ctx->border_thickness != 0) { - ta_text_ctx border_ctx = *ctx; - - border_ctx.red = ctx->border_red; - border_ctx.green = ctx->border_green; - border_ctx.blue = ctx->border_blue; - ta_int32 thickness = ctx->border_thickness; - - for (ta_int32 offset_y = -thickness; offset_y <= thickness; offset_y++) { - for (ta_int32 offset_x = -thickness; offset_x <= thickness; offset_x++) { - if (offset_x == 0 && offset_y == 0) { - continue; - } - - draw_text_pass(text, x + offset_x, y + offset_y, &border_ctx); - } - } - } - - draw_text_pass(text, x, y, ctx); + if (ctx->border_thickness != 0) { + ta_text_ctx border_ctx = *ctx; + + border_ctx.red = ctx->border_red; + border_ctx.green = ctx->border_green; + border_ctx.blue = ctx->border_blue; + ta_int32 thickness = ctx->border_thickness; + + for (ta_int32 offset_y = -thickness; offset_y <= thickness; offset_y++) { + for (ta_int32 offset_x = -thickness; offset_x <= thickness; offset_x++) { + if (offset_x == 0 && offset_y == 0) { + continue; + } + + draw_text_pass(text, x + offset_x, y + offset_y, &border_ctx); + } + } + } + + draw_text_pass(text, x, y, ctx); } -#define TEXT_CACHE_ENTRIES 8 +#define TEXT_CACHE_ENTRIES 8 #define TEXT_CACHE_MAX_TEXT 64 #define TEXT_CACHE_MAX_MASK 262144 typedef struct { - char text[TEXT_CACHE_MAX_TEXT + 1]; - ta_int32 scale; - ta_int32 x0; - ta_int32 y0; - ta_int32 width; - ta_int32 height; - ta_uint8 *mask; + char text[TEXT_CACHE_MAX_TEXT + 1]; + ta_int32 scale; + ta_int32 x0; + ta_int32 y0; + ta_int32 width; + ta_int32 height; + ta_uint8 *mask; } ta_text_entry; static ta_text_entry text_cache[TEXT_CACHE_ENTRIES]; static ta_uint32 text_cache_next; static ta_bool same_text(const char *a, const char *b) { - while (*a && *a == *b) { - a++; - b++; - } + while (*a && *a == *b) { + a++; + b++; + } - return *a == *b; + return *a == *b; } static ta_text_entry *text_cache_build(const char *text, ta_int32 scale) { - ta_uint32 length = 0; - - while (text[length]) { - if (++length > TEXT_CACHE_MAX_TEXT) { - return 0; - } - } - - ta_uint32 units; - ta_uint32 lines; - - measure_units(text, &units, &lines); - - ta_int32 padding = (ta_int32)(((ta_uint64)font.units_per_em * (ta_uint64)scale) >> 16) / 2 + 2; - ta_int32 text_width = (ta_int32)(((ta_uint64)units * (ta_uint64)scale + (ONE - 1)) >> 16); - ta_int32 text_height = (ta_int32)(((ta_uint64)lines * line_height_units() * (ta_uint64)scale + (ONE - 1)) >> 16); - ta_int32 width = text_width + padding * 2; - ta_int32 height = text_height + padding * 2; - - if (width <= 0 || height <= 0 || (ta_uint64)width * (ta_uint64)height > TEXT_CACHE_MAX_MASK) { - return 0; - } - - ta_size mask_size = (ta_size)width * (ta_size)height; - ta_uint8 *mask = (ta_uint8 *)ta_malloc(mask_size); - - if (mask == 0) { - return 0; - } - - for (ta_size i = 0; i < mask_size; i++) { - mask[i] = 0; - } - - ta_text_ctx ctx; - - ctx.scale = scale; - ctx.clip_x0 = -padding; - ctx.clip_y0 = -padding; - ctx.clip_x1 = -padding + width; - ctx.clip_y1 = -padding + height; - ctx.red = 0; - ctx.green = 0; - ctx.blue = 0; - ctx.border_thickness = 0; - ctx.border_red = 0; - ctx.border_green = 0; - ctx.border_blue = 0; - ctx.mask = mask; - ctx.mask_x0 = -padding; - ctx.mask_y0 = -padding; - ctx.mask_stride = width; - - draw_text_pass(text, 0, 0, &ctx); - - ta_text_entry *entry = &text_cache[text_cache_next]; - - text_cache_next = (text_cache_next + 1) % TEXT_CACHE_ENTRIES; - - ta_free(entry->mask); - - for (ta_uint32 i = 0; i <= length; i++) { - entry->text[i] = text[i]; - } - - entry->scale = scale; - entry->x0 = -padding; - entry->y0 = -padding; - entry->width = width; - entry->height = height; - entry->mask = mask; - - return entry; + ta_uint32 length = 0; + + while (text[length]) { + if (++length > TEXT_CACHE_MAX_TEXT) { + return 0; + } + } + + ta_uint32 units; + ta_uint32 lines; + + measure_units(text, &units, &lines); + + ta_int32 padding = (ta_int32)(((ta_uint64)font.units_per_em * (ta_uint64)scale) >> 16) / 2 + 2; + ta_int32 text_width = (ta_int32)(((ta_uint64)units * (ta_uint64)scale + (ONE - 1)) >> 16); + ta_int32 text_height = (ta_int32)(((ta_uint64)lines * line_height_units() * (ta_uint64)scale + (ONE - 1)) >> 16); + ta_int32 width = text_width + padding * 2; + ta_int32 height = text_height + padding * 2; + + if (width <= 0 || height <= 0 || (ta_uint64)width * (ta_uint64)height > TEXT_CACHE_MAX_MASK) { + return 0; + } + + ta_size mask_size = (ta_size)width * (ta_size)height; + ta_uint8 *mask = (ta_uint8 *)ta_malloc(mask_size); + + if (mask == 0) { + return 0; + } + + for (ta_size i = 0; i < mask_size; i++) { + mask[i] = 0; + } + + ta_text_ctx ctx; + + ctx.scale = scale; + ctx.clip_x0 = -padding; + ctx.clip_y0 = -padding; + ctx.clip_x1 = -padding + width; + ctx.clip_y1 = -padding + height; + ctx.red = 0; + ctx.green = 0; + ctx.blue = 0; + ctx.border_thickness = 0; + ctx.border_red = 0; + ctx.border_green = 0; + ctx.border_blue = 0; + ctx.mask = mask; + ctx.mask_x0 = -padding; + ctx.mask_y0 = -padding; + ctx.mask_stride = width; + + draw_text_pass(text, 0, 0, &ctx); + + ta_text_entry *entry = &text_cache[text_cache_next]; + + text_cache_next = (text_cache_next + 1) % TEXT_CACHE_ENTRIES; + + ta_free(entry->mask); + + for (ta_uint32 i = 0; i <= length; i++) { + entry->text[i] = text[i]; + } + + entry->scale = scale; + entry->x0 = -padding; + entry->y0 = -padding; + entry->width = width; + entry->height = height; + entry->mask = mask; + + return entry; } static ta_text_entry *text_cache_get(const char *text, ta_int32 scale) { - for (ta_uint32 i = 0; i < TEXT_CACHE_ENTRIES; i++) { - if (text_cache[i].mask != 0 && text_cache[i].scale == scale && same_text(text_cache[i].text, text)) { - return &text_cache[i]; - } - } + for (ta_uint32 i = 0; i < TEXT_CACHE_ENTRIES; i++) { + if (text_cache[i].mask != 0 && text_cache[i].scale == scale && same_text(text_cache[i].text, text)) { + return &text_cache[i]; + } + } - return text_cache_build(text, scale); + return text_cache_build(text, scale); } static void composite_mask(const ta_text_entry *entry, const ta_text_ctx *ctx, ta_int32 x, ta_int32 y) { - ta_int32 destination_x = x + entry->x0; - ta_int32 destination_y = y + entry->y0; - ta_int32 column_start = ctx->clip_x0 - destination_x; - ta_int32 column_end = ctx->clip_x1 - destination_x; - ta_int32 row_start = ctx->clip_y0 - destination_y; - ta_int32 row_end = ctx->clip_y1 - destination_y; - - if (column_start < 0) { - column_start = 0; - } - - if (row_start < 0) { - row_start = 0; - } - - if (column_end > entry->width) { - column_end = entry->width; - } - - if (row_end > entry->height) { - row_end = entry->height; - } - - for (ta_int32 row = row_start; row < row_end; row++) { - const ta_uint8 *source = entry->mask + (ta_size)row * (ta_size)entry->width; - - for (ta_int32 column = column_start; column < column_end; column++) { - if (source[column] != 0) { - put_pixel(ctx, destination_x + column, destination_y + row, source[column]); - } - } - } + ta_int32 destination_x = x + entry->x0; + ta_int32 destination_y = y + entry->y0; + ta_int32 column_start = ctx->clip_x0 - destination_x; + ta_int32 column_end = ctx->clip_x1 - destination_x; + ta_int32 row_start = ctx->clip_y0 - destination_y; + ta_int32 row_end = ctx->clip_y1 - destination_y; + + if (column_start < 0) { + column_start = 0; + } + + if (row_start < 0) { + row_start = 0; + } + + if (column_end > entry->width) { + column_end = entry->width; + } + + if (row_end > entry->height) { + row_end = entry->height; + } + + for (ta_int32 row = row_start; row < row_end; row++) { + const ta_uint8 *source = entry->mask + (ta_size)row * (ta_size)entry->width; + + for (ta_int32 column = column_start; column < column_end; column++) { + if (source[column] != 0) { + put_pixel(ctx, destination_x + column, destination_y + row, source[column]); + } + } + } } static void draw_text(const char *text, ta_int32 x, ta_int32 y, const ta_text_ctx *ctx) { - const ta_text_entry *entry = text_cache_get(text, ctx->scale); + const ta_text_entry *entry = text_cache_get(text, ctx->scale); - if (entry == 0) { - draw_text_direct(text, x, y, ctx); + if (entry == 0) { + draw_text_direct(text, x, y, ctx); - return; - } + return; + } - if (ctx->border_thickness != 0) { - ta_text_ctx border_ctx = *ctx; + if (ctx->border_thickness != 0) { + ta_text_ctx border_ctx = *ctx; - border_ctx.red = ctx->border_red; - border_ctx.green = ctx->border_green; - border_ctx.blue = ctx->border_blue; - ta_int32 thickness = ctx->border_thickness; + border_ctx.red = ctx->border_red; + border_ctx.green = ctx->border_green; + border_ctx.blue = ctx->border_blue; + ta_int32 thickness = ctx->border_thickness; - for (ta_int32 offset_y = -thickness; offset_y <= thickness; offset_y++) { - for (ta_int32 offset_x = -thickness; offset_x <= thickness; offset_x++) { - if (offset_x == 0 && offset_y == 0) { - continue; - } + for (ta_int32 offset_y = -thickness; offset_y <= thickness; offset_y++) { + for (ta_int32 offset_x = -thickness; offset_x <= thickness; offset_x++) { + if (offset_x == 0 && offset_y == 0) { + continue; + } - composite_mask(entry, &border_ctx, x + offset_x, y + offset_y); - } - } - } + composite_mask(entry, &border_ctx, x + offset_x, y + offset_y); + } + } + } - composite_mask(entry, ctx, x, y); + composite_mask(entry, ctx, x, y); } static void draw_text_fitted(const char *text, ta_uint32 x, ta_uint32 y, ta_uint32 width, ta_uint32 height, ta_uint8 red, ta_uint8 green, ta_uint8 blue, ta_uint8 border_thickness, ta_uint8 border_red, ta_uint8 border_green, ta_uint8 border_blue) { - if (!text || width == 0 || height == 0 || !fb_usable() || !font_ready()) { - return; - } - - ta_int32 frame_width = fb_limit(ta_fb.width); - ta_int32 frame_height = fb_limit(ta_fb.height); - - if (x >= (ta_uint32)frame_width || y >= (ta_uint32)frame_height) { - return; - } - - ta_uint32 text_width; - ta_uint32 lines; - - measure_units(text, &text_width, &lines); - - if (text_width == 0) { - return; - } - - ta_uint64 scale_by_height = unsigned_divide64((ta_uint64)height << 16, lines * line_height_units()); - ta_uint64 scale_by_width = unsigned_divide64((ta_uint64)width << 16, text_width); - ta_uint64 scale_cap = unsigned_divide64((ta_uint64)MAX_SIZE << 16, font.units_per_em); - ta_uint64 scale = scale_by_height < scale_by_width ? scale_by_height : scale_by_width; - - if (scale > scale_cap) { - scale = scale_cap; - } - - if (scale == 0) { - return; - } - - ta_text_ctx ctx; - - ctx.scale = (ta_int32)scale; - ctx.clip_x0 = (ta_int32)x; - ctx.clip_y0 = (ta_int32)y; - ctx.clip_x1 = width > (ta_uint32)frame_width - x ? frame_width : (ta_int32)(x + width); - ctx.clip_y1 = height > (ta_uint32)frame_height - y ? frame_height : (ta_int32)(y + height); - ctx.red = red; - ctx.green = green; - ctx.blue = blue; - ctx.border_thickness = border_thickness; - ctx.border_red = border_red; - ctx.border_green = border_green; - ctx.border_blue = border_blue; - ctx.mask = 0; - - draw_text(text, (ta_int32)x, (ta_int32)y, &ctx); + if (!text || width == 0 || height == 0 || !fb_usable() || !font_ready()) { + return; + } + + ta_int32 frame_width = fb_limit(ta_fb.width); + ta_int32 frame_height = fb_limit(ta_fb.height); + + if (x >= (ta_uint32)frame_width || y >= (ta_uint32)frame_height) { + return; + } + + ta_uint32 text_width; + ta_uint32 lines; + + measure_units(text, &text_width, &lines); + + if (text_width == 0) { + return; + } + + ta_uint64 scale_by_height = unsigned_divide64((ta_uint64)height << 16, lines * line_height_units()); + ta_uint64 scale_by_width = unsigned_divide64((ta_uint64)width << 16, text_width); + ta_uint64 scale_cap = unsigned_divide64((ta_uint64)MAX_SIZE << 16, font.units_per_em); + ta_uint64 scale = scale_by_height < scale_by_width ? scale_by_height : scale_by_width; + + if (scale > scale_cap) { + scale = scale_cap; + } + + if (scale == 0) { + return; + } + + ta_text_ctx ctx; + + ctx.scale = (ta_int32)scale; + ctx.clip_x0 = (ta_int32)x; + ctx.clip_y0 = (ta_int32)y; + ctx.clip_x1 = width > (ta_uint32)frame_width - x ? frame_width : (ta_int32)(x + width); + ctx.clip_y1 = height > (ta_uint32)frame_height - y ? frame_height : (ta_int32)(y + height); + ctx.red = red; + ctx.green = green; + ctx.blue = blue; + ctx.border_thickness = border_thickness; + ctx.border_red = border_red; + ctx.border_green = border_green; + ctx.border_blue = border_blue; + ctx.mask = 0; + + draw_text(text, (ta_int32)x, (ta_int32)y, &ctx); } void ta_text_draw(const char *text, ta_uint32 x, ta_uint32 y, ta_uint32 width, ta_uint32 height, ta_uint8 red, ta_uint8 green, ta_uint8 blue) { - draw_text_fitted(text, x, y, width, height, red, green, blue, 0, 0, 0, 0); + draw_text_fitted(text, x, y, width, height, red, green, blue, 0, 0, 0, 0); } -void ta_text_draw_outline(const char *text, ta_uint32 x, ta_uint32 y, ta_uint32 width, ta_uint32 height, - ta_uint8 red, ta_uint8 green, ta_uint8 blue, ta_uint8 border_thickness, - ta_uint8 border_red, ta_uint8 border_green, ta_uint8 border_blue) { - draw_text_fitted(text, x, y, width, height, red, green, blue, - border_thickness, border_red, border_green, border_blue); +void ta_text_draw_outline(const char *text, ta_uint32 x, ta_uint32 y, ta_uint32 width, ta_uint32 height, ta_uint8 red, ta_uint8 green, ta_uint8 blue, ta_uint8 border_thickness, ta_uint8 border_red, ta_uint8 border_green, ta_uint8 border_blue) { + draw_text_fitted(text, x, y, width, height, red, green, blue, border_thickness, border_red, border_green, border_blue); } void ta_text_draw_size(const char *text, ta_uint32 x, ta_uint32 y, ta_uint32 size, ta_uint8 red, ta_uint8 green, ta_uint8 blue) { - if (!text || size == 0 || !fb_usable() || !font_ready()) { - return; - } - - if (size > MAX_SIZE) { - size = MAX_SIZE; - } - - ta_int32 frame_width = fb_limit(ta_fb.width); - ta_int32 frame_height = fb_limit(ta_fb.height); - - if (x >= (ta_uint32)frame_width || y >= (ta_uint32)frame_height) { - return; - } - - ta_text_ctx ctx; - - ctx.scale = (ta_int32)unsigned_divide64((ta_uint64)size << 16, font.units_per_em); - ctx.clip_x0 = (ta_int32)x; - ctx.clip_y0 = (ta_int32)y; - ctx.clip_x1 = frame_width; - ctx.clip_y1 = frame_height; - ctx.red = red; - ctx.green = green; - ctx.blue = blue; - ctx.border_thickness = 0; - ctx.border_red = 0; - ctx.border_green = 0; - ctx.border_blue = 0; - ctx.mask = 0; - - draw_text(text, (ta_int32)x, (ta_int32)y, &ctx); + if (!text || size == 0 || !fb_usable() || !font_ready()) { + return; + } + + if (size > MAX_SIZE) { + size = MAX_SIZE; + } + + ta_int32 frame_width = fb_limit(ta_fb.width); + ta_int32 frame_height = fb_limit(ta_fb.height); + + if (x >= (ta_uint32)frame_width || y >= (ta_uint32)frame_height) { + return; + } + + ta_text_ctx ctx; + + ctx.scale = (ta_int32)unsigned_divide64((ta_uint64)size << 16, font.units_per_em); + ctx.clip_x0 = (ta_int32)x; + ctx.clip_y0 = (ta_int32)y; + ctx.clip_x1 = frame_width; + ctx.clip_y1 = frame_height; + ctx.red = red; + ctx.green = green; + ctx.blue = blue; + ctx.border_thickness = 0; + ctx.border_red = 0; + ctx.border_green = 0; + ctx.border_blue = 0; + ctx.mask = 0; + + draw_text(text, (ta_int32)x, (ta_int32)y, &ctx); } void ta_text_measure(const char *text, ta_uint32 size, ta_uint32 *width, ta_uint32 *height) { - ta_uint32 measured_width = 0; - ta_uint32 measured_height = 0; + ta_uint32 measured_width = 0; + ta_uint32 measured_height = 0; - if (text && font_ready()) { - if (size > MAX_SIZE) { - size = MAX_SIZE; - } + if (text && font_ready()) { + if (size > MAX_SIZE) { + size = MAX_SIZE; + } - ta_uint32 units; - ta_uint32 lines; - ta_uint64 scale = unsigned_divide64((ta_uint64)size << 16, font.units_per_em); + ta_uint32 units; + ta_uint32 lines; + ta_uint64 scale = unsigned_divide64((ta_uint64)size << 16, font.units_per_em); - measure_units(text, &units, &lines); + measure_units(text, &units, &lines); - measured_width = (ta_uint32)(((ta_uint64)units * scale + (ONE - 1)) >> 16); - measured_height = (ta_uint32)(((ta_uint64)lines * line_height_units() * scale + (ONE - 1)) >> 16); - } + measured_width = (ta_uint32)(((ta_uint64)units * scale + (ONE - 1)) >> 16); + measured_height = (ta_uint32)(((ta_uint64)lines * line_height_units() * scale + (ONE - 1)) >> 16); + } - if (width) { - *width = measured_width; - } + if (width) { + *width = measured_width; + } - if (height) { - *height = measured_height; - } + if (height) { + *height = measured_height; + } }