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:
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;
+ }
}