DJUI Text improvements and bug fixes (#1131)

- Drastically improve and optimize display list usage for text
- Add text alignment with and without interpolation, and color codes, new lines and tabs are now handled properly
- Restored alpha color code (`#RGBA` or `#RRGGBBAA`) for `djui_print_text` functions (regular DJUI text allows alpha color codes, but ignores the alpha component)
- Add constants for common text alignment and rotation pivot values
- Fix interpolation issues with all `djui_hud` elements
- A few autogen fixes (missing `number` type for constants, missing return values for some functions)
- Fix recolorable hud font offsets on `e`, `i` and `o` letters
This commit is contained in:
PeachyPeach 2026-03-10 23:38:24 +01:00 committed by GitHub
parent dd838ad979
commit 3b53952767
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 1133 additions and 534 deletions

View file

@ -535,6 +535,8 @@ def def_constant(fname, processed_constant, skip_constant):
continue
if '"' in c[1]:
s += '\n--- @type string\n'
elif "." in c[1]:
s += '\n--- @type number\n'
else:
s += '\n--- @type integer\n'
s += '%s = %s\n' % (c[0], c[1])

View file

@ -1342,7 +1342,7 @@ def doc_function(fname, function):
s += '- None\n'
s += '\n### Returns\n'
if rtype != None:
if len(rvalues) > 0:
for _, ptype, plink in rvalues:
if plink:
s += '- [%s](%s)\n' % (ptype, plink)

View file

@ -2760,6 +2760,42 @@ CONSOLE_MESSAGE_ERROR = 2 --- @type ConsoleMessageLevel
--- | `CONSOLE_MESSAGE_WARNING`
--- | `CONSOLE_MESSAGE_ERROR`
--- @type number
ROTATION_PIVOT_X_LEFT = 0.0
--- @type number
ROTATION_PIVOT_X_CENTER = 0.5
--- @type number
ROTATION_PIVOT_X_RIGHT = 1.0
--- @type number
ROTATION_PIVOT_Y_TOP = 0.0
--- @type number
ROTATION_PIVOT_Y_CENTER = 0.5
--- @type number
ROTATION_PIVOT_Y_BOTTOM = 1.0
--- @type number
TEXT_HALIGN_LEFT = 0.0
--- @type number
TEXT_HALIGN_CENTER = 0.5
--- @type number
TEXT_HALIGN_RIGHT = 1.0
--- @type number
TEXT_VALIGN_TOP = 0.0
--- @type number
TEXT_VALIGN_CENTER = 0.5
--- @type number
TEXT_VALIGN_BOTTOM = 1.0
RESOLUTION_DJUI = 0 --- @type HudUtilsResolution
RESOLUTION_N64 = 1 --- @type HudUtilsResolution
RESOLUTION_COUNT = 2 --- @type HudUtilsResolution
@ -2778,16 +2814,18 @@ FILTER_COUNT = 2 --- @type HudUtilsFilter
--- | `FILTER_LINEAR`
--- | `FILTER_COUNT`
FONT_NORMAL = 0 --- @type DjuiFontType
FONT_MENU = 1 --- @type DjuiFontType
FONT_HUD = 2 --- @type DjuiFontType
FONT_ALIASED = 3 --- @type DjuiFontType
FONT_CUSTOM_HUD = 4 --- @type DjuiFontType
FONT_RECOLOR_HUD = 5 --- @type DjuiFontType
FONT_SPECIAL = 6 --- @type DjuiFontType
FONT_COUNT = 7 --- @type DjuiFontType
FONT_LEGACY = -1 --- @type DjuiFontType
FONT_NORMAL = 0 --- @type DjuiFontType
FONT_MENU = 1 --- @type DjuiFontType
FONT_HUD = 2 --- @type DjuiFontType
FONT_ALIASED = 3 --- @type DjuiFontType
FONT_CUSTOM_HUD = 4 --- @type DjuiFontType
FONT_RECOLOR_HUD = 5 --- @type DjuiFontType
FONT_SPECIAL = 6 --- @type DjuiFontType
FONT_COUNT = 7 --- @type DjuiFontType
--- @alias DjuiFontType
--- | `FONT_LEGACY`
--- | `FONT_NORMAL`
--- | `FONT_MENU`
--- | `FONT_HUD`

View file

@ -3856,7 +3856,9 @@ function djui_hud_reset_color()
-- ...
end
--- @return HudUtilsRotation
--- @return integer rotation
--- @return number pivotX
--- @return number pivotY
--- Gets the current DJUI HUD rotation
function djui_hud_get_rotation()
-- ...
@ -3881,6 +3883,29 @@ function djui_hud_set_rotation_interpolated(prevRotation, prevPivotX, prevPivotY
-- ...
end
--- @return number textHAlign
--- @return number textVAlign
--- Gets the current DJUI HUD text alignment
function djui_hud_get_text_alignment()
-- ...
end
--- @param textHAlign number
--- @param textVAlign number
--- Sets the current DJUI HUD text alignment
function djui_hud_set_text_alignment(textHAlign, textVAlign)
-- ...
end
--- @param prevTextHAlign number
--- @param prevTextVAlign number
--- @param textHAlign number
--- @param textVAlign number
--- Sets the current DJUI HUD text alignment interpolated
function djui_hud_set_text_alignment_interpolated(prevTextHAlign, prevTextVAlign, textHAlign, textVAlign)
-- ...
end
--- @return integer
--- Gets the screen width in the current DJUI HUD resolution
function djui_hud_get_screen_width()

View file

@ -955,14 +955,6 @@
--- @field public translation Vec3s
--- @field public rotation Vec3s
--- @class HudUtilsRotation
--- @field public rotation number
--- @field public rotationDiff number
--- @field public prevPivotX number
--- @field public prevPivotY number
--- @field public pivotX number
--- @field public pivotY number
--- @class InstantWarp
--- @field public id integer
--- @field public area integer

View file

@ -1149,6 +1149,18 @@
<br />
## [djui_hud_utils.h](#djui_hud_utils.h)
- ROTATION_PIVOT_X_LEFT
- ROTATION_PIVOT_X_CENTER
- ROTATION_PIVOT_X_RIGHT
- ROTATION_PIVOT_Y_TOP
- ROTATION_PIVOT_Y_CENTER
- ROTATION_PIVOT_Y_BOTTOM
- TEXT_HALIGN_LEFT
- TEXT_HALIGN_CENTER
- TEXT_HALIGN_RIGHT
- TEXT_VALIGN_TOP
- TEXT_VALIGN_CENTER
- TEXT_VALIGN_BOTTOM
### [enum HudUtilsResolution](#HudUtilsResolution)
| Identifier | Value |
@ -1167,6 +1179,7 @@
### [enum DjuiFontType](#DjuiFontType)
| Identifier | Value |
| :--------- | :---- |
| FONT_LEGACY | -1 |
| FONT_NORMAL | 0 |
| FONT_MENU | 1 |
| FONT_HUD | 2 |

View file

@ -1312,7 +1312,8 @@ Calculates and returns the pitch and yaw angles from one 3D position (`from`) to
| to | [Vec3f](structs.md#Vec3f) |
### Returns
- None
- `integer`
- `integer`
### C Prototype
`void calculate_angles(Vec3f from, Vec3f to, RET s16 *pitch, RET s16 *yaw);`
@ -1585,7 +1586,7 @@ Applies a roll-based shake effect to the camera. Simulates rotational disturbanc
| roll | `integer` |
### Returns
- None
- `integer`
### C Prototype
`void shake_camera_roll(INOUT s16 *roll);`
@ -2825,7 +2826,7 @@ Gets the current DJUI HUD font
- `integer`
### C Prototype
`u8 djui_hud_get_font(void);`
`s8 djui_hud_get_font(void);`
[:arrow_up_small:](#)
@ -2928,16 +2929,18 @@ Resets the current DJUI HUD color
Gets the current DJUI HUD rotation
### Lua Example
`local hudUtilsRotationValue = djui_hud_get_rotation()`
`local rotation, pivotX, pivotY = djui_hud_get_rotation()`
### Parameters
- None
### Returns
- [HudUtilsRotation](structs.md#HudUtilsRotation)
- `integer`
- `number`
- `number`
### C Prototype
`struct HudUtilsRotation* djui_hud_get_rotation(void);`
`void djui_hud_get_rotation(RET s16 *rotation, RET f32 *pivotX, RET f32 *pivotY);`
[:arrow_up_small:](#)
@ -2990,7 +2993,79 @@ Sets the current DJUI HUD rotation interpolated
- None
### C Prototype
`void djui_hud_set_rotation_interpolated(s32 prevRotation, f32 prevPivotX, f32 prevPivotY, s32 rotation, f32 pivotX, f32 pivotY);`
`void djui_hud_set_rotation_interpolated(s16 prevRotation, f32 prevPivotX, f32 prevPivotY, s16 rotation, f32 pivotX, f32 pivotY);`
[:arrow_up_small:](#)
<br />
## [djui_hud_get_text_alignment](#djui_hud_get_text_alignment)
### Description
Gets the current DJUI HUD text alignment
### Lua Example
`local textHAlign, textVAlign = djui_hud_get_text_alignment()`
### Parameters
- None
### Returns
- `number`
- `number`
### C Prototype
`void djui_hud_get_text_alignment(RET f32 *textHAlign, RET f32 *textVAlign);`
[:arrow_up_small:](#)
<br />
## [djui_hud_set_text_alignment](#djui_hud_set_text_alignment)
### Description
Sets the current DJUI HUD text alignment
### Lua Example
`djui_hud_set_text_alignment(textHAlign, textVAlign)`
### Parameters
| Field | Type |
| ----- | ---- |
| textHAlign | `number` |
| textVAlign | `number` |
### Returns
- None
### C Prototype
`void djui_hud_set_text_alignment(f32 textHAlign, f32 textVAlign);`
[:arrow_up_small:](#)
<br />
## [djui_hud_set_text_alignment_interpolated](#djui_hud_set_text_alignment_interpolated)
### Description
Sets the current DJUI HUD text alignment interpolated
### Lua Example
`djui_hud_set_text_alignment_interpolated(prevTextHAlign, prevTextVAlign, textHAlign, textVAlign)`
### Parameters
| Field | Type |
| ----- | ---- |
| prevTextHAlign | `number` |
| prevTextVAlign | `number` |
| textHAlign | `number` |
| textVAlign | `number` |
### Returns
- None
### C Prototype
`void djui_hud_set_text_alignment_interpolated(f32 prevTextHAlign, f32 prevTextVAlign, f32 textHAlign, f32 textVAlign);`
[:arrow_up_small:](#)

View file

@ -5134,7 +5134,9 @@ Calculates the distance between two points in 3D space (`from` and `to`), as wel
| to | [Vec3f](structs.md#Vec3f) |
### Returns
- None
- `number`
- `integer`
- `integer`
### C Prototype
`void vec3f_get_dist_and_angle(Vec3f from, Vec3f to, RET f32 *dist, RET s16 *pitch, RET s16 *yaw);`

View file

@ -2945,7 +2945,7 @@ Determines an object's forward speed multiplier.
| floor_nY | `number` |
### Returns
- None
- `number`
### C Prototype
`void calc_obj_friction(RET f32 *objFriction, f32 floor_nY);`
@ -4419,7 +4419,7 @@ Begin by increasing the current object's scale by `scaleVel`, and slowly decreas
| blinkLength | `integer` |
### Returns
- None
- `integer`
### C Prototype
`void obj_update_blinking(INOUT s32 *blinkTimer, s16 baseCycleLength, s16 cycleLengthRange, s16 blinkLength);`
@ -4743,7 +4743,8 @@ Treats far home as Mario. Returns the distance and angle to the nearest player
| threshold | `number` |
### Returns
- None
- `integer`
- `integer`
### C Prototype
`void treat_far_home_as_mario(f32 threshold, RET s32* distanceToPlayer, RET s32* angleToPlayer);`

View file

@ -1963,7 +1963,7 @@ Marks an object to be unloaded at the end of the frame
| dragStrength | `number` |
### Returns
- None
- `number`
### C Prototype
`void apply_drag_to_value(INOUT f32 *value, f32 dragStrength);`

View file

@ -763,6 +763,9 @@
- [djui_hud_get_rotation](functions-3.md#djui_hud_get_rotation)
- [djui_hud_set_rotation](functions-3.md#djui_hud_set_rotation)
- [djui_hud_set_rotation_interpolated](functions-3.md#djui_hud_set_rotation_interpolated)
- [djui_hud_get_text_alignment](functions-3.md#djui_hud_get_text_alignment)
- [djui_hud_set_text_alignment](functions-3.md#djui_hud_set_text_alignment)
- [djui_hud_set_text_alignment_interpolated](functions-3.md#djui_hud_set_text_alignment_interpolated)
- [djui_hud_get_screen_width](functions-3.md#djui_hud_get_screen_width)
- [djui_hud_get_screen_height](functions-3.md#djui_hud_get_screen_height)
- [djui_hud_get_mouse_x](functions-3.md#djui_hud_get_mouse_x)

View file

@ -53,7 +53,6 @@
- [GraphNodeSwitchCase](#GraphNodeSwitchCase)
- [GraphNodeTranslation](#GraphNodeTranslation)
- [GraphNodeTranslationRotation](#GraphNodeTranslationRotation)
- [HudUtilsRotation](#HudUtilsRotation)
- [InstantWarp](#InstantWarp)
- [LakituState](#LakituState)
- [LevelValues](#LevelValues)
@ -1427,21 +1426,6 @@
<br />
## [HudUtilsRotation](#HudUtilsRotation)
| Field | Type | Access |
| ----- | ---- | ------ |
| rotation | `number` | |
| rotationDiff | `number` | |
| prevPivotX | `number` | |
| prevPivotY | `number` | |
| pivotX | `number` | |
| pivotY | `number` | |
[:arrow_up_small:](#)
<br />
## [InstantWarp](#InstantWarp)
| Field | Type | Access |

View file

@ -235,6 +235,8 @@ static void crash_handler_produce_one_frame_callback(void) {
// render the line
f32 addX = 0;
char* c = text->s;
font->render_begin();
while (*c != '\0') {
f32 charWidth = 0.4f;
@ -253,6 +255,7 @@ static void crash_handler_produce_one_frame_callback(void) {
create_dl_translation_matrix(DJUI_MTX_NOPUSH, charWidth, 0, 0);
c = djui_unicode_next_char(c);
}
font->render_end();
// pop
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);

View file

@ -122,11 +122,9 @@ void discord_activity_update(void) {
// HACK: give the detail population more space than the Discord details can fit so it gets truncated without cutting off the largest strings
char details[512] = { 0 };
discord_populate_details(details, 512);
char* detailsNoColor = str_remove_color_codes(details);
snprintf(sCurActivity.details, 128, "%s", detailsNoColor);
free(detailsNoColor);
discord_populate_details(details, ARRAY_COUNT(details));
djui_text_remove_colors(details);
snprintf(sCurActivity.details, 128, "%s", details);
if (!app.activities) {
LOG_INFO("no activities");

View file

@ -168,7 +168,8 @@ void djui_lua_error_clear(void) {
void djui_reset_hud_params(void) {
djui_hud_set_resolution(RESOLUTION_DJUI);
djui_hud_set_font(FONT_NORMAL);
djui_hud_set_rotation(0, 0, 0);
djui_hud_set_rotation(0, ROTATION_PIVOT_X_LEFT, ROTATION_PIVOT_Y_TOP);
djui_hud_set_text_alignment(TEXT_HALIGN_LEFT, TEXT_VALIGN_TOP);
djui_hud_reset_color();
djui_hud_set_filter(FILTER_NEAREST);
djui_hud_reset_viewport();

View file

@ -7,7 +7,7 @@
// font 0 (built-in normal font) //
///////////////////////////////////
static void djui_font_normal_render_char(char* c) {
static void djui_font_normal_render_char(const char* c) {
// replace undisplayable characters
if (*c == ' ') { return; }
@ -18,16 +18,16 @@ static void djui_font_normal_render_char(char* c) {
u32 tx = index % 64;
u32 ty = index / 64;
extern ALIGNED8 const Texture texture_font_jp[];
djui_gfx_render_texture_tile(texture_font_jp, 512, 1024, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 8, ty * 16, 8, 16, false, true);
djui_gfx_render_texture_tile_font(texture_font_jp, 512, 1024, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 8, ty * 16, 8, 16);
} else {
u32 tx = index % 32;
u32 ty = index / 32;
extern ALIGNED8 const Texture texture_font_normal[];
djui_gfx_render_texture_tile(texture_font_normal, 256, 128, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 8, ty * 16, 8, 16, false, true);
djui_gfx_render_texture_tile_font(texture_font_normal, 256, 128, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 8, ty * 16, 8, 16);
}
}
static f32 djui_font_normal_char_width(char* c) {
static f32 djui_font_normal_char_width(const char* c) {
if (*c == ' ') { return configExCoopTheme ? 6 / 32.0f : 0.30f; }
extern const f32 font_normal_widths[];
return djui_unicode_get_sprite_width(c, font_normal_widths, 32.0f);
@ -41,7 +41,9 @@ static const struct DjuiFont sDjuiFontNormal = {
.yOffset = 0.0f,
.defaultFontScale = 32.0f,
.textBeginDisplayList = NULL,
.render_begin = djui_gfx_render_texture_tile_font_begin,
.render_char = djui_font_normal_render_char,
.render_end = djui_gfx_render_texture_tile_font_end,
.char_width = djui_font_normal_char_width,
};
@ -49,7 +51,7 @@ static const struct DjuiFont sDjuiFontNormal = {
// font 1 (custom title font) //
////////////////////////////////
static void djui_font_title_render_char(char* c) {
static void djui_font_title_render_char(const char* c) {
// replace undisplayable characters
if (*c == ' ') { return; }
@ -64,10 +66,10 @@ static void djui_font_title_render_char(char* c) {
u32 ty = index / 16;
extern ALIGNED8 const Texture texture_font_title[];
djui_gfx_render_texture_tile(texture_font_title, 1024, 512, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 64, ty * 64, 64, 64, false, true);
djui_gfx_render_texture_tile_font(texture_font_title, 1024, 512, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 64, ty * 64, 64, 64);
}
static f32 djui_font_title_char_width(char* text) {
static f32 djui_font_title_char_width(const char* text) {
char c = *text;
if (c == ' ') { return 0.30f; }
c = djui_unicode_get_base_char(text);
@ -83,7 +85,9 @@ static const struct DjuiFont sDjuiFontTitle = {
.yOffset = 0.0f,
.defaultFontScale = 64.0f,
.textBeginDisplayList = NULL,
.render_begin = djui_gfx_render_texture_tile_font_begin,
.render_char = djui_font_title_render_char,
.render_end = djui_gfx_render_texture_tile_font_end,
.char_width = djui_font_title_char_width,
};
@ -124,27 +128,29 @@ static u8 djui_font_hud_index(char c) {
return c;
}
static void djui_font_hud_render_char(char* text) {
static void djui_font_hud_render_char(const char* text) {
char c = *text;
if (c == ' ') { return; }
c = djui_unicode_get_base_char(text);
u8 index = djui_font_hud_index(c);
djui_gfx_render_texture(main_hud_lut[index], 16, 16, G_IM_FMT_RGBA, G_IM_SIZ_16b, djui_hud_get_filter());
djui_gfx_render_texture_font(main_hud_lut[index], 16, 16, G_IM_FMT_RGBA, G_IM_SIZ_16b);
}
static f32 djui_font_hud_char_width(UNUSED char* text) {
static f32 djui_font_hud_char_width(UNUSED const char* text) {
return 0.75f;
}
static const struct DjuiFont sDjuiFontHud = {
.charWidth = 1.0f,
.charHeight = 0.9f,
.lineHeight = 0.7f,
.lineHeight = 1.25f,
.xOffset = 0.0f,
.yOffset = 0.0f,
.defaultFontScale = 16.0f,
.textBeginDisplayList = NULL,
.render_begin = djui_gfx_render_texture_font_begin,
.render_char = djui_font_hud_render_char,
.render_end = djui_gfx_render_texture_font_end,
.char_width = djui_font_hud_char_width,
};
@ -152,7 +158,7 @@ static const struct DjuiFont sDjuiFontHud = {
// font 3 (DJ's aliased font) //
////////////////////////////////
static void djui_font_aliased_render_char(char* c) {
static void djui_font_aliased_render_char(const char* c) {
// replace undisplayable characters
if (*c == ' ') { return; }
@ -163,16 +169,16 @@ static void djui_font_aliased_render_char(char* c) {
u32 tx = index % 64;
u32 ty = index / 64;
extern ALIGNED8 const Texture texture_font_jp_aliased[];
djui_gfx_render_texture_tile(texture_font_jp_aliased, 1024, 2048, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 16, ty * 32, 16, 32, false, true);
djui_gfx_render_texture_tile_font(texture_font_jp_aliased, 1024, 2048, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 16, ty * 32, 16, 32);
} else {
u32 tx = index % 32;
u32 ty = index / 32;
extern ALIGNED8 const Texture texture_font_aliased[];
djui_gfx_render_texture_tile(texture_font_aliased, 512, 256, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 16, ty * 32, 16, 32, false, true);
djui_gfx_render_texture_tile_font(texture_font_aliased, 512, 256, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 16, ty * 32, 16, 32);
}
}
static f32 djui_font_aliased_char_width(char* c) {
static f32 djui_font_aliased_char_width(const char* c) {
if (*c == ' ') { return 6 / 32.0f; }
extern const f32 font_aliased_widths[];
return djui_unicode_get_sprite_width(c, font_aliased_widths, 1.0f) / 32.0f;
@ -186,7 +192,9 @@ static const struct DjuiFont sDjuiFontAliased = {
.lineHeight = 0.8125f,
.defaultFontScale = 32.0f,
.textBeginDisplayList = NULL,
.render_begin = djui_gfx_render_texture_tile_font_begin,
.render_char = djui_font_aliased_render_char,
.render_end = djui_gfx_render_texture_tile_font_end,
.char_width = djui_font_aliased_char_width,
};
@ -194,7 +202,7 @@ static const struct DjuiFont sDjuiFontAliased = {
// font 4/5 (custom hud font/recolor) //
////////////////////////////////////////
static void djui_font_custom_hud_render_char(char* c) {
static void djui_font_custom_hud_render_char(const char* c) {
// replace undisplayable characters
if (*c == ' ') { return; }
@ -204,10 +212,10 @@ static void djui_font_custom_hud_render_char(char* c) {
u32 ty = index / 16;
extern ALIGNED8 const Texture texture_font_hud[];
djui_gfx_render_texture_tile(texture_font_hud, 512, 512, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 32, ty * 32, 32, 32, false, true);
djui_gfx_render_texture_tile_font(texture_font_hud, 512, 512, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 32, ty * 32, 32, 32);
}
static void djui_font_custom_hud_recolor_render_char(char* c) {
static void djui_font_custom_hud_recolor_render_char(const char* c) {
// replace undisplayable characters
if (*c == ' ') { return; }
@ -217,10 +225,10 @@ static void djui_font_custom_hud_recolor_render_char(char* c) {
u32 ty = index / 16;
extern ALIGNED8 const Texture texture_font_hud_recolor[];
djui_gfx_render_texture_tile(texture_font_hud_recolor, 512, 512, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 32, ty * 32, 32, 32, false, true);
djui_gfx_render_texture_tile_font(texture_font_hud_recolor, 512, 512, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 32, ty * 32, 32, 32);
}
static f32 djui_font_custom_hud_char_width(char* text) {
static f32 djui_font_custom_hud_char_width(const char* text) {
char c = *text;
if (c == ' ') { return 0.3750f; }
c = djui_unicode_get_base_char(text);
@ -236,7 +244,9 @@ static const struct DjuiFont sDjuiFontCustomHud = {
.yOffset = -10.25f,
.defaultFontScale = 32.0f,
.textBeginDisplayList = NULL,
.render_begin = djui_gfx_render_texture_tile_font_begin,
.render_char = djui_font_custom_hud_render_char,
.render_end = djui_gfx_render_texture_tile_font_end,
.char_width = djui_font_custom_hud_char_width,
};
@ -248,7 +258,9 @@ static const struct DjuiFont sDjuiFontCustomHudRecolor = {
.yOffset = -10.25f,
.defaultFontScale = 32.0f,
.textBeginDisplayList = NULL,
.render_begin = djui_gfx_render_texture_tile_font_begin,
.render_char = djui_font_custom_hud_recolor_render_char,
.render_end = djui_gfx_render_texture_tile_font_end,
.char_width = djui_font_custom_hud_char_width,
};
@ -256,7 +268,7 @@ static const struct DjuiFont sDjuiFontCustomHudRecolor = {
// font 6 (special font) //
///////////////////////////
static void djui_font_special_render_char(char* c) {
static void djui_font_special_render_char(const char* c) {
// replace undisplayable characters
if (*c == ' ') { return; }
@ -266,17 +278,17 @@ static void djui_font_special_render_char(char* c) {
u32 tx = index % 64;
u32 ty = index / 64;
extern ALIGNED8 const Texture texture_font_jp[];
djui_gfx_render_texture_tile(texture_font_jp, 512, 1024, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 8, ty * 16, 8, 16, false, true);
djui_gfx_render_texture_tile_font(texture_font_jp, 512, 1024, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 8, ty * 16, 8, 16);
} else {
u32 tx = index % 32;
u32 ty = index / 32;
extern ALIGNED8 const Texture texture_font_special[];
djui_gfx_render_texture_tile(texture_font_special, 256, 128, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 8, ty * 16, 8, 16, false, true);
djui_gfx_render_texture_tile_font(texture_font_special, 256, 128, G_IM_FMT_RGBA, G_IM_SIZ_32b, tx * 8, ty * 16, 8, 16);
}
}
static f32 djui_font_special_char_width(char* c) {
static f32 djui_font_special_char_width(const char* c) {
if (*c == ' ') { return 0.5f; }
extern const f32 font_special_widths[];
return djui_unicode_get_sprite_width(c, font_special_widths, 32.0f);
@ -290,7 +302,9 @@ static const struct DjuiFont sDjuiFontSpecial = {
.yOffset = 0.0f,
.defaultFontScale = 32.0f,
.textBeginDisplayList = NULL,
.render_begin = djui_gfx_render_texture_tile_font_begin,
.render_char = djui_font_special_render_char,
.render_end = djui_gfx_render_texture_tile_font_end,
.char_width = djui_font_special_char_width,
};

View file

@ -9,8 +9,10 @@ struct DjuiFont {
f32 yOffset;
f32 defaultFontScale;
const Gfx* textBeginDisplayList;
void (*render_char)(char*);
f32 (*char_width)(char*);
void (*render_begin)();
void (*render_char)(const char*);
void (*render_end)();
f32 (*char_width)(const char*);
};
extern const struct DjuiFont* gDjuiFonts[];

View file

@ -1,6 +1,7 @@
#include <ultra64.h>
#include "sm64.h"
#include "djui.h"
#include "djui_hud_utils.h"
#include "game/ingame_menu.h"
#include "game/segment2.h"
#include "pc/pc_main.h"
@ -118,7 +119,93 @@ void djui_gfx_render_texture(const Texture* texture, u32 w, u32 h, u8 fmt, u8 si
gSPDisplayList(gDisplayListHead++, dl_djui_image);
}
void djui_gfx_render_texture_tile(const Texture* texture, u32 w, u32 h, u8 fmt, u8 siz, u32 tileX, u32 tileY, u32 tileW, u32 tileH, bool filter, bool font) {
void djui_gfx_render_texture_tile(const Texture* texture, u32 w, u32 h, u8 fmt, u8 siz, u32 tileX, u32 tileY, u32 tileW, u32 tileH, bool filter) {
if (!gDisplayListHead) {
LOG_ERROR("Retrieved a null displaylist head");
return;
}
if (!texture) {
LOG_ERROR("Attempted to render null texture");
return;
}
Vtx *vtx = alloc_display_list(sizeof(Vtx) * 4);
if (!vtx) {
LOG_ERROR("Failed to allocate vertices");
return;
}
f32 aspect = tileH ? ((f32)tileW / (f32)tileH) : 1;
vtx[0] = (Vtx) {{{ 0, -1, 0 }, 0, { ( tileX * 2048.0f) / (f32)w + 1, ((tileY + tileH) * 2048.0f) / (f32)h + 1 }, { 0xff, 0xff, 0xff, 0xff }}};
vtx[2] = (Vtx) {{{ 1 * aspect, 0, 0 }, 0, { ((tileX + tileW) * 2048.0f) / (f32)w + 1, ( tileY * 2048.0f) / (f32)h + 1 }, { 0xff, 0xff, 0xff, 0xff }}};
vtx[1] = (Vtx) {{{ 1 * aspect, -1, 0 }, 0, { ((tileX + tileW) * 2048.0f) / (f32)w + 1, ((tileY + tileH) * 2048.0f) / (f32)h + 1 }, { 0xff, 0xff, 0xff, 0xff }}};
vtx[3] = (Vtx) {{{ 0, 0, 0 }, 0, { ( tileX * 2048.0f) / (f32)w + 1, ( tileY * 2048.0f) / (f32)h + 1 }, { 0xff, 0xff, 0xff, 0xff }}};
gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING | G_CULL_BOTH);
gDPSetCombineMode(gDisplayListHead++, G_CC_FADEA, G_CC_FADEA);
gDPSetRenderMode(gDisplayListHead++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
gDPSetTextureFilter(gDisplayListHead++, filter ? G_TF_BILERP : G_TF_POINT);
gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON);
gDPSetTextureOverrideDjui(gDisplayListHead++, texture, djui_gfx_power_of_two(w), djui_gfx_power_of_two(h), fmt, siz);
gDPLoadTextureBlockWithoutTexture(gDisplayListHead++, NULL, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 64, 0, G_TX_CLAMP, G_TX_CLAMP, 0, 0, 0, 0);
*(gDisplayListHead++) = (Gfx) gsSPExecuteDjui(G_TEXOVERRIDE_DJUI);
gSPVertexNonGlobal(gDisplayListHead++, vtx, 4, 0);
*(gDisplayListHead++) = (Gfx) gsSPExecuteDjui(G_TEXCLIP_DJUI);
gSP2TrianglesDjui(gDisplayListHead++, 0, 1, 2, 0x0, 0, 2, 3, 0x0);
gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF);
gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE);
gSPSetGeometryMode(gDisplayListHead++, G_LIGHTING | G_CULL_BACK);
}
void djui_gfx_render_texture_font_begin() {
gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING | G_CULL_BOTH);
gDPSetCombineMode(gDisplayListHead++, G_CC_FADEA, G_CC_FADEA);
gDPSetRenderMode(gDisplayListHead++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
gDPSetTextureFilter(gDisplayListHead++, djui_hud_get_filter() ? G_TF_BILERP : G_TF_POINT);
gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON);
gDPLoadTextureBlockWithoutTexture(gDisplayListHead++, NULL, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 64, 0, G_TX_CLAMP, G_TX_CLAMP, 0, 0, 0, 0);
}
void djui_gfx_render_texture_font(const Texture* texture, u32 w, u32 h, u8 fmt, u8 siz) {
if (!gDisplayListHead) {
LOG_ERROR("Retrieved a null displaylist head");
return;
}
if (!texture) {
LOG_ERROR("Attempted to render null texture");
return;
}
gDPSetTextureOverrideDjui(gDisplayListHead++, texture, djui_gfx_power_of_two(w), djui_gfx_power_of_two(h), fmt, siz);
*(gDisplayListHead++) = (Gfx) gsSPExecuteDjui(G_TEXOVERRIDE_DJUI);
gSPVertexNonGlobal(gDisplayListHead++, vertex_djui_image, 4, 0);
gSP2Triangles(gDisplayListHead++, 0, 1, 2, 0x0, 0, 2, 3, 0x0);
}
void djui_gfx_render_texture_font_end() {
gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF);
gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE);
gSPSetGeometryMode(gDisplayListHead++, G_LIGHTING | G_CULL_BACK);
}
void djui_gfx_render_texture_tile_font_begin() {
gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING | G_CULL_BOTH);
gDPSetCombineMode(gDisplayListHead++, G_CC_FADEA, G_CC_FADEA);
gDPSetRenderMode(gDisplayListHead++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
gDPSetTextureFilter(gDisplayListHead++, G_TF_POINT);
gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON);
gDPLoadTextureBlockWithoutTexture(gDisplayListHead++, NULL, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 64, 0, G_TX_CLAMP, G_TX_CLAMP, 0, 0, 0, 0);
}
void djui_gfx_render_texture_tile_font(const Texture* texture, u32 w, u32 h, u8 fmt, u8 siz, u32 tileX, u32 tileY, u32 tileW, u32 tileH) {
if (!gDisplayListHead) {
LOG_ERROR("Retrieved a null displaylist head");
return;
@ -139,29 +226,21 @@ void djui_gfx_render_texture_tile(const Texture* texture, u32 w, u32 h, u8 fmt,
// I don't know why adding 1 to all of the UVs seems to fix rendering, but it does...
// this should be tested carefully. it definitely fixes some stuff, but what does it break?
f32 offsetX = (font ? -1024.0f / (f32)w : 0) + 1;
f32 offsetY = (font ? -1024.0f / (f32)h : 0) + 1;
f32 offsetX = (-1024.0f / (f32)w) + 1;
f32 offsetY = (-1024.0f / (f32)h) + 1;
vtx[0] = (Vtx) {{{ 0, -1, 0 }, 0, { ( tileX * 2048.0f) / (f32)w + offsetX, ((tileY + tileH) * 2048.0f) / (f32)h + offsetY }, { 0xff, 0xff, 0xff, 0xff }}};
vtx[2] = (Vtx) {{{ 1 * aspect, 0, 0 }, 0, { ((tileX + tileW) * 2048.0f) / (f32)w + offsetX, ( tileY * 2048.0f) / (f32)h + offsetY }, { 0xff, 0xff, 0xff, 0xff }}};
vtx[1] = (Vtx) {{{ 1 * aspect, -1, 0 }, 0, { ((tileX + tileW) * 2048.0f) / (f32)w + offsetX, ((tileY + tileH) * 2048.0f) / (f32)h + offsetY }, { 0xff, 0xff, 0xff, 0xff }}};
vtx[3] = (Vtx) {{{ 0, 0, 0 }, 0, { ( tileX * 2048.0f) / (f32)w + offsetX, ( tileY * 2048.0f) / (f32)h + offsetY }, { 0xff, 0xff, 0xff, 0xff }}};
gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING | G_CULL_BOTH);
gDPSetCombineMode(gDisplayListHead++, G_CC_FADEA, G_CC_FADEA);
gDPSetRenderMode(gDisplayListHead++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
gDPSetTextureFilter(gDisplayListHead++, filter ? G_TF_BILERP : G_TF_POINT);
gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON);
gDPSetTextureOverrideDjui(gDisplayListHead++, texture, djui_gfx_power_of_two(w), djui_gfx_power_of_two(h), fmt, siz);
gDPLoadTextureBlockWithoutTexture(gDisplayListHead++, NULL, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 64, 0, G_TX_CLAMP, G_TX_CLAMP, 0, 0, 0, 0);
*(gDisplayListHead++) = (Gfx) gsSPExecuteDjui(G_TEXOVERRIDE_DJUI);
gSPVertexNonGlobal(gDisplayListHead++, vtx, 4, 0);
*(gDisplayListHead++) = (Gfx) gsSPExecuteDjui(G_TEXCLIP_DJUI);
gSP2TrianglesDjui(gDisplayListHead++, 0, 1, 2, 0x0, 0, 2, 3, 0x0);
}
void djui_gfx_render_texture_tile_font_end() {
gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF);
gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE);
gSPSetGeometryMode(gDisplayListHead++, G_LIGHTING | G_CULL_BACK);

View file

@ -16,7 +16,15 @@ void djui_gfx_displaylist_end(void);
f32 djui_gfx_get_scale(void);
void djui_gfx_render_texture(const Texture* texture, u32 w, u32 h, u8 fmt, u8 siz, bool filter);
void djui_gfx_render_texture_tile(const Texture* texture, u32 w, u32 h, u8 fmt, u8 siz, u32 tileX, u32 tileY, u32 tileW, u32 tileH, bool filter, bool font);
void djui_gfx_render_texture_tile(const Texture* texture, u32 w, u32 h, u8 fmt, u8 siz, u32 tileX, u32 tileY, u32 tileW, u32 tileH, bool filter);
void djui_gfx_render_texture_font_begin();
void djui_gfx_render_texture_font(const Texture* texture, u32 w, u32 h, u8 fmt, u8 siz);
void djui_gfx_render_texture_font_end();
void djui_gfx_render_texture_tile_font_begin();
void djui_gfx_render_texture_tile_font(const Texture* texture, u32 w, u32 h, u8 fmt, u8 siz, u32 tileX, u32 tileY, u32 tileW, u32 tileH);
void djui_gfx_render_texture_tile_font_end();
void gfx_get_dimensions(u32* width, u32* height);

View file

@ -24,13 +24,45 @@
#include "engine/math_util.h"
static enum HudUtilsResolution sResolution = RESOLUTION_DJUI;
static enum HudUtilsFilter sFilter = FILTER_NEAREST;
static enum DjuiFontType sFont = FONT_NORMAL;
static struct HudUtilsRotation sRotation = { 0, 0, 0, 0, 0, 0 };
static struct DjuiColor sColor = { 255, 255, 255, 255 };
#define INTERP_INIT(v) {v, v}
typedef struct {
f32 prev, curr;
} InterpFieldF32;
struct HudUtilsState {
enum HudUtilsResolution resolution;
enum HudUtilsFilter filter;
enum DjuiFontType font;
struct DjuiColor color;
struct {
InterpFieldF32 degrees;
InterpFieldF32 pivotX;
InterpFieldF32 pivotY;
} rotation;
struct {
InterpFieldF32 h;
InterpFieldF32 v;
} textAlignment;
};
static struct HudUtilsState sHudUtilsState = {
.resolution = RESOLUTION_DJUI,
.filter = FILTER_NEAREST,
.font = FONT_NORMAL,
.color = { 255, 255, 255, 255 },
.rotation = {
.degrees = INTERP_INIT(0),
.pivotX = INTERP_INIT(ROTATION_PIVOT_X_LEFT),
.pivotY = INTERP_INIT(ROTATION_PIVOT_Y_TOP),
},
.textAlignment = {
.h = INTERP_INIT(TEXT_HALIGN_LEFT),
.v = INTERP_INIT(TEXT_VALIGN_TOP),
},
};
static struct DjuiColor sRefColor = { 255, 255, 255, 255 };
static bool sLegacy = false;
f32 gDjuiHudUtilsZ = 0;
bool gDjuiHudLockMouse = false;
@ -67,8 +99,16 @@ struct GlobalTextures gGlobalTextures = {
.wario_head = { .texture = texture_hud_char_wario_head, "texture_hud_char_wario_head", .width = 16, .height = 16, .format = G_IM_FMT_RGBA, .size = G_IM_SIZ_16b }
};
static inline const struct DjuiFont *djui_hud_get_text_font() {
return gDjuiFonts[sHudUtilsState.font < 0 ? FONT_NORMAL : sHudUtilsState.font];
}
static inline bool djui_hud_text_font_is_legacy() {
return sHudUtilsState.font < 0;
}
static void djui_hud_position_translate(f32* x, f32* y) {
if (sResolution == RESOLUTION_DJUI) {
if (sHudUtilsState.resolution == RESOLUTION_DJUI) {
djui_gfx_position_translate(x, y);
} else {
*x = GFX_DIMENSIONS_FROM_LEFT_EDGE(0) + *x;
@ -77,7 +117,7 @@ static void djui_hud_position_translate(f32* x, f32* y) {
}
static void djui_hud_size_translate(f32* size) {
if (sResolution == RESOLUTION_DJUI) {
if (sHudUtilsState.resolution == RESOLUTION_DJUI) {
djui_gfx_size_translate(size);
}
}
@ -90,7 +130,7 @@ static void djui_hud_translate_positions(f32 *outX, f32 *outY, f32 *outW, f32 *o
*outY -= SCREEN_HEIGHT;
// translate scale
if (sResolution == RESOLUTION_DJUI) {
if (sHudUtilsState.resolution == RESOLUTION_DJUI) {
u32 windowWidth, windowHeight;
gfx_get_dimensions(&windowWidth, &windowHeight);
f32 screenWidth = (f32) windowWidth / djui_gfx_get_scale();
@ -105,22 +145,31 @@ static void djui_hud_translate_positions(f32 *outX, f32 *outY, f32 *outW, f32 *o
////////////
#define MAX_INTERP_HUD 512
struct InterpHud {
Gfx* headPos;
f32 z;
f32 prevX;
f32 prevY;
f32 x;
f32 y;
f32 prevScaleW;
f32 prevScaleH;
f32 scaleW;
f32 scaleH;
f32 width;
f32 height;
enum HudUtilsResolution resolution;
struct HudUtilsRotation rotation;
enum InterpHudType {
INTERP_HUD_TRANSLATION,
INTERP_HUD_ROTATION,
INTERP_HUD_SCALE,
INTERP_HUD_HALIGN,
INTERP_HUD_VALIGN,
INTERP_HUD_NEW_LINE,
};
typedef struct {
enum InterpHudType type;
Gfx *pos;
f32 params[1]; // we don't need more for now
} InterpHudGfx;
struct InterpHud {
f32 z;
InterpFieldF32 posX, posY;
InterpFieldF32 scaleX, scaleY;
f32 width, height;
struct HudUtilsState state;
struct GrowingArray *gfx;
};
static struct InterpHud sInterpHuds[MAX_INTERP_HUD] = { 0 };
static u16 sInterpHudCount = 0;
static u8 sColorAltered = FALSE;
@ -132,140 +181,211 @@ void patch_djui_hud_before(void) {
void patch_djui_hud(f32 delta) {
f32 savedZ = gDjuiHudUtilsZ;
Gfx* savedHeadPos = gDisplayListHead;
enum HudUtilsResolution savedResolution = sResolution;
struct HudUtilsRotation savedRotation = sRotation;
struct HudUtilsState savedState = sHudUtilsState;
for (u16 i = 0; i < sInterpHudCount; i++) {
struct InterpHud* interp = &sInterpHuds[i];
f32 x = delta_interpolate_f32(interp->prevX, interp->x, delta);
f32 y = delta_interpolate_f32(interp->prevY, interp->y, delta);
f32 scaleW = delta_interpolate_f32(interp->prevScaleW, interp->scaleW, delta);
f32 scaleH = delta_interpolate_f32(interp->prevScaleH, interp->scaleH, delta);
sResolution = interp->resolution;
sRotation = interp->rotation;
f32 x = delta_interpolate_f32(interp->posX.prev, interp->posX.curr, delta);
f32 y = delta_interpolate_f32(interp->posY.prev, interp->posY.curr, delta);
f32 scaleW = delta_interpolate_f32(interp->scaleX.prev, interp->scaleX.curr, delta);
f32 scaleH = delta_interpolate_f32(interp->scaleY.prev, interp->scaleY.curr, delta);
sHudUtilsState = interp->state;
gDjuiHudUtilsZ = interp->z;
gDisplayListHead = interp->headPos;
// translate position
f32 translatedX = x;
f32 translatedY = y;
djui_hud_position_translate(&translatedX, &translatedY);
create_dl_translation_matrix(DJUI_MTX_PUSH, translatedX, translatedY, gDjuiHudUtilsZ);
for (u32 j = 0; j != interp->gfx->count; ++j) {
const InterpHudGfx *gfx = interp->gfx->buffer[j];
gDisplayListHead = gfx->pos;
// rotate
f32 translatedW = scaleW;
f32 translatedH = scaleH;
djui_hud_size_translate(&translatedW);
djui_hud_size_translate(&translatedH);
if (sRotation.rotationDiff != 0 || sRotation.rotation != 0) {
s32 rotation = delta_interpolate_s32(sRotation.rotation - sRotation.rotationDiff, sRotation.rotation, delta);
f32 pivotX = delta_interpolate_f32(sRotation.prevPivotX, sRotation.pivotX, delta);
f32 pivotY = delta_interpolate_f32(sRotation.prevPivotY, sRotation.pivotY, delta);
f32 pivotTranslationX = interp->width * translatedW * pivotX;
f32 pivotTranslationY = interp->height * translatedH * pivotY;
create_dl_translation_matrix(DJUI_MTX_NOPUSH, +pivotTranslationX, -pivotTranslationY, 0);
create_dl_rotation_matrix(DJUI_MTX_NOPUSH, rotation, 0, 0, 1);
create_dl_translation_matrix(DJUI_MTX_NOPUSH, -pivotTranslationX, +pivotTranslationY, 0);
switch (gfx->type) {
case INTERP_HUD_TRANSLATION: {
f32 translatedX = x;
f32 translatedY = y;
djui_hud_position_translate(&translatedX, &translatedY);
create_dl_translation_matrix(DJUI_MTX_PUSH, translatedX, translatedY, gDjuiHudUtilsZ);
} break;
case INTERP_HUD_ROTATION: {
if (sHudUtilsState.rotation.degrees.prev != 0 || sHudUtilsState.rotation.degrees.curr != 0) {
f32 translatedW = scaleW;
f32 translatedH = scaleH;
djui_hud_size_translate(&translatedW);
djui_hud_size_translate(&translatedH);
s16 rotPrev = degrees_to_sm64(sHudUtilsState.rotation.degrees.prev);
s16 rotCurr = degrees_to_sm64(sHudUtilsState.rotation.degrees.curr);
s32 normalizedDiff = (((s32) rotCurr - (s32) rotPrev + 0x8000) & 0xFFFF) - 0x8000; // Fix modular overflow/underflow
s32 rotation = delta_interpolate_s32(rotCurr - normalizedDiff, rotCurr, delta);
f32 pivotX = delta_interpolate_f32(sHudUtilsState.rotation.pivotX.prev, sHudUtilsState.rotation.pivotX.curr, delta);
f32 pivotY = delta_interpolate_f32(sHudUtilsState.rotation.pivotY.prev, sHudUtilsState.rotation.pivotY.curr, delta);
f32 pivotTranslationX = interp->width * translatedW * pivotX;
f32 pivotTranslationY = interp->height * translatedH * pivotY;
create_dl_translation_matrix(DJUI_MTX_NOPUSH, +pivotTranslationX, -pivotTranslationY, 0);
create_dl_rotation_matrix(DJUI_MTX_NOPUSH, sm64_to_degrees(rotation), 0, 0, 1);
create_dl_translation_matrix(DJUI_MTX_NOPUSH, -pivotTranslationX, +pivotTranslationY, 0);
}
} break;
case INTERP_HUD_SCALE: {
f32 translatedW = scaleW;
f32 translatedH = scaleH;
djui_hud_size_translate(&translatedW);
djui_hud_size_translate(&translatedH);
create_dl_scale_matrix(DJUI_MTX_NOPUSH, interp->width * translatedW, interp->height * translatedH, 1.0f);
} break;
case INTERP_HUD_HALIGN: {
f32 textHAlign = delta_interpolate_f32(sHudUtilsState.textAlignment.h.prev, sHudUtilsState.textAlignment.h.curr, delta);
f32 lineWidth = gfx->params[0];
create_dl_translation_matrix(DJUI_MTX_NOPUSH, -lineWidth * textHAlign, 0, 0);
} break;
case INTERP_HUD_VALIGN: {
f32 textVAlign = delta_interpolate_f32(sHudUtilsState.textAlignment.v.prev, sHudUtilsState.textAlignment.v.curr, delta);
f32 textHeight = gfx->params[0];
create_dl_translation_matrix(DJUI_MTX_NOPUSH, 0, textHeight * textVAlign, 0);
} break;
case INTERP_HUD_NEW_LINE: {
const struct DjuiFont *font = djui_hud_get_text_font();
f32 textHAlign = delta_interpolate_f32(sHudUtilsState.textAlignment.h.prev, sHudUtilsState.textAlignment.h.curr, delta);
f32 lineWidth = gfx->params[0];
create_dl_translation_matrix(DJUI_MTX_NOPUSH, -lineWidth * (1.f - textHAlign), -font->lineHeight, 0);
} break;
}
}
// scale
create_dl_scale_matrix(DJUI_MTX_NOPUSH, interp->width * translatedW, interp->height * translatedH, 1.0f);
}
sResolution = savedResolution;
sRotation = savedRotation;
sHudUtilsState = savedState;
gDisplayListHead = savedHeadPos;
gDjuiHudUtilsZ = savedZ;
}
struct InterpHud *djui_hud_create_interp() {
if (sInterpHudCount >= MAX_INTERP_HUD) { return NULL; }
struct InterpHud *interp = &sInterpHuds[sInterpHudCount++];
interp->z = gDjuiHudUtilsZ;
interp->state = sHudUtilsState;
if (!interp->gfx) {
interp->gfx = growing_array_init(NULL, 8, malloc, free);
} else {
interp->gfx->count = 0;
}
return interp;
}
InterpHudGfx *djui_hud_create_interp_gfx(struct InterpHud *interp, enum InterpHudType type) {
if (!interp) { return NULL; }
InterpHudGfx *gfx = growing_array_alloc(interp->gfx, sizeof(InterpHudGfx));
gfx->type = type;
gfx->pos = gDisplayListHead;
return gfx;
}
////////////
// others //
////////////
u8 djui_hud_get_resolution(void) {
return sResolution;
return sHudUtilsState.resolution;
}
void djui_hud_set_resolution(enum HudUtilsResolution resolutionType) {
if (resolutionType >= RESOLUTION_COUNT) { return; }
sResolution = resolutionType;
sHudUtilsState.resolution = resolutionType;
}
u8 djui_hud_get_filter(void) {
return sFilter;
return sHudUtilsState.filter;
}
void djui_hud_set_filter(enum HudUtilsFilter filterType) {
if (filterType >= FILTER_COUNT) { return; }
sFilter = filterType;
sHudUtilsState.filter = filterType;
}
u8 djui_hud_get_font(void) {
return sFont;
s8 djui_hud_get_font(void) {
return sHudUtilsState.font;
}
void djui_hud_set_font(s8 fontType) {
if (fontType >= FONT_COUNT || fontType < -1) { return; }
sLegacy = fontType == -1;
if (sLegacy) { fontType = 0; }
sFont = fontType;
sHudUtilsState.font = fontType;
}
struct DjuiColor* djui_hud_get_color(void) {
sRefColor.r = sColor.r;
sRefColor.g = sColor.g;
sRefColor.b = sColor.b;
sRefColor.a = sColor.a;
sRefColor.r = sHudUtilsState.color.r;
sRefColor.g = sHudUtilsState.color.g;
sRefColor.b = sHudUtilsState.color.b;
sRefColor.a = sHudUtilsState.color.a;
return &sRefColor;
}
void djui_hud_set_color(u8 r, u8 g, u8 b, u8 a) {
sColor.r = r;
sColor.g = g;
sColor.b = b;
sColor.a = a;
sHudUtilsState.color.r = r;
sHudUtilsState.color.g = g;
sHudUtilsState.color.b = b;
sHudUtilsState.color.a = a;
sColorAltered = TRUE;
gDPSetEnvColor(gDisplayListHead++, r, g, b, a);
}
void djui_hud_reset_color(void) {
if (sColorAltered) {
sColor.r = 255;
sColor.g = 255;
sColor.b = 255;
sColor.a = 255;
sHudUtilsState.color.r = 255;
sHudUtilsState.color.g = 255;
sHudUtilsState.color.b = 255;
sHudUtilsState.color.a = 255;
sColorAltered = FALSE;
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
}
}
struct HudUtilsRotation* djui_hud_get_rotation(void) {
return &sRotation;
void djui_hud_get_rotation(RET s16 *rotation, RET f32 *pivotX, RET f32 *pivotY) {
*rotation = degrees_to_sm64(sHudUtilsState.rotation.degrees.curr);
*pivotX = sHudUtilsState.rotation.pivotX.curr;
*pivotY = sHudUtilsState.rotation.pivotY.curr;
}
void djui_hud_set_rotation(s16 rotation, f32 pivotX, f32 pivotY) {
sRotation.rotationDiff = 0;
sRotation.prevPivotX = pivotX;
sRotation.prevPivotY = pivotY;
sRotation.rotation = (rotation * 180.f) / 0x8000;
sRotation.pivotX = pivotX;
sRotation.pivotY = pivotY;
sHudUtilsState.rotation.degrees.prev = sHudUtilsState.rotation.degrees.curr = sm64_to_degrees(rotation);
sHudUtilsState.rotation.pivotX.prev = sHudUtilsState.rotation.pivotX.curr = pivotX;
sHudUtilsState.rotation.pivotY.prev = sHudUtilsState.rotation.pivotY.curr = pivotY;
}
void djui_hud_set_rotation_interpolated(s32 prevRotation, f32 prevPivotX, f32 prevPivotY, s32 rotation, f32 pivotX, f32 pivotY) {
f32 normalizedDiff = ((rotation - prevRotation + 0x8000) & 0xFFFF) - 0x8000; // Fix modular overflow/underflow
sRotation.rotationDiff = (normalizedDiff * 180.f) / 0x8000;
sRotation.prevPivotX = prevPivotX;
sRotation.prevPivotY = prevPivotY;
sRotation.rotation = (rotation * 180.f) / 0x8000;
sRotation.pivotX = pivotX;
sRotation.pivotY = pivotY;
void djui_hud_set_rotation_interpolated(s16 prevRotation, f32 prevPivotX, f32 prevPivotY, s16 rotation, f32 pivotX, f32 pivotY) {
sHudUtilsState.rotation.degrees.prev = sm64_to_degrees(prevRotation);
sHudUtilsState.rotation.degrees.curr = sm64_to_degrees(rotation);
sHudUtilsState.rotation.pivotX.prev = prevPivotX;
sHudUtilsState.rotation.pivotX.curr = pivotX;
sHudUtilsState.rotation.pivotY.prev = prevPivotY;
sHudUtilsState.rotation.pivotY.curr = pivotY;
}
void djui_hud_get_text_alignment(RET f32 *textHAlign, RET f32 *textVAlign) {
*textHAlign = sHudUtilsState.textAlignment.h.curr;
*textVAlign = sHudUtilsState.textAlignment.v.curr;
}
void djui_hud_set_text_alignment(f32 textHAlign, f32 textVAlign) {
sHudUtilsState.textAlignment.h.prev = sHudUtilsState.textAlignment.h.curr = textHAlign;
sHudUtilsState.textAlignment.v.prev = sHudUtilsState.textAlignment.v.curr = textVAlign;
}
void djui_hud_set_text_alignment_interpolated(f32 prevTextHAlign, f32 prevTextVAlign, f32 textHAlign, f32 textVAlign) {
sHudUtilsState.textAlignment.h.prev = prevTextHAlign;
sHudUtilsState.textAlignment.h.curr = textHAlign;
sHudUtilsState.textAlignment.v.prev = prevTextVAlign;
sHudUtilsState.textAlignment.v.curr = textVAlign;
}
u32 djui_hud_get_screen_width(void) {
u32 windowWidth, windowHeight;
gfx_get_dimensions(&windowWidth, &windowHeight);
return (sResolution == RESOLUTION_N64)
return (sHudUtilsState.resolution == RESOLUTION_N64)
? GFX_DIMENSIONS_ASPECT_RATIO * SCREEN_HEIGHT
: (windowWidth / djui_gfx_get_scale());
}
@ -274,7 +394,7 @@ u32 djui_hud_get_screen_height(void) {
u32 windowWidth, windowHeight;
gfx_get_dimensions(&windowWidth, &windowHeight);
return (sResolution == RESOLUTION_N64)
return (sHudUtilsState.resolution == RESOLUTION_N64)
? SCREEN_HEIGHT
: (windowHeight / djui_gfx_get_scale());
}
@ -364,23 +484,58 @@ void djui_hud_reset_scissor(void) {
f32 djui_hud_measure_text(const char* message) {
if (message == NULL) { return 0; }
const struct DjuiFont* font = gDjuiFonts[sFont];
f32 width = 0;
const char* c = message;
while(*c != '\0') {
width += font->char_width((char*)c) * (sLegacy ? 0.5f : 1.0f);
c = djui_unicode_next_char((char*)c);
const struct DjuiFont* font = djui_hud_get_text_font();
f32 width = 0, maxWidth = 0;
char *c = (char *) message;
const char *end = message + strlen(message);
while (*c != '\0') {
// check color code
if (djui_text_parse_color(c, end, false, NULL, &c, NULL)) {
continue;
}
// new line
if (*c == '\n') {
maxWidth = max(width, maxWidth);
width = 0;
}
// tab: align to the next (4 x space width)
else if (*c == '\t') {
f32 tabWidth = 4 * font->char_width(" ") * (djui_hud_text_font_is_legacy() ? 0.5f : 1.0f);
width += tabWidth - fmodf(width, tabWidth);
}
// unprintable chars
else if (!djui_text_is_printable(c)) {
// treat them as empty
}
// regular chars
else {
width += font->char_width(c) * (djui_hud_text_font_is_legacy() ? 0.5f : 1.0f);
}
c = djui_unicode_next_char(c);
}
return width * font->defaultFontScale;
return max(width, maxWidth) * font->defaultFontScale;
}
void djui_hud_print_text(const char* message, f32 x, f32 y, f32 scale) {
static Mtx *allocate_dl_translation_matrix() {
Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
if (matrix == NULL) { return NULL; }
gSPMatrix(gDisplayListHead++, matrix, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
return matrix;
}
static void djui_hud_print_text_internal(const char* message, f32 x, f32 y, f32 scale, struct InterpHud *interp) {
if (message == NULL) { return; }
gDjuiHudUtilsZ += 0.001f;
if (sLegacy) { scale *= 0.5f; }
if (djui_hud_text_font_is_legacy()) { scale *= 0.5f; }
const struct DjuiFont* font = gDjuiFonts[sFont];
const struct DjuiFont* font = djui_hud_get_text_font();
f32 fontScale = font->defaultFontScale * scale;
// setup display list
@ -389,117 +544,147 @@ void djui_hud_print_text(const char* message, f32 x, f32 y, f32 scale) {
}
// translate position
djui_hud_create_interp_gfx(interp, INTERP_HUD_TRANSLATION);
f32 translatedX = x + (font->xOffset * scale);
f32 translatedY = y + (font->yOffset * scale);
djui_hud_position_translate(&translatedX, &translatedY);
create_dl_translation_matrix(DJUI_MTX_PUSH, translatedX, translatedY, gDjuiHudUtilsZ);
// compute font size
// rotate
f32 translatedFontSize = fontScale;
djui_hud_size_translate(&translatedFontSize);
if (sHudUtilsState.rotation.degrees.prev != 0 || sHudUtilsState.rotation.degrees.curr != 0) {
djui_hud_create_interp_gfx(interp, INTERP_HUD_ROTATION);
f32 pivotTranslationX = font->defaultFontScale * translatedFontSize * sHudUtilsState.rotation.pivotX.curr;
f32 pivotTranslationY = font->defaultFontScale * translatedFontSize * sHudUtilsState.rotation.pivotY.curr;
create_dl_translation_matrix(DJUI_MTX_NOPUSH, +pivotTranslationX, -pivotTranslationY, 0);
create_dl_rotation_matrix(DJUI_MTX_NOPUSH, sHudUtilsState.rotation.degrees.curr, 0, 0, 1);
create_dl_translation_matrix(DJUI_MTX_NOPUSH, -pivotTranslationX, +pivotTranslationY, 0);
}
// compute font size
djui_hud_create_interp_gfx(interp, INTERP_HUD_SCALE);
create_dl_scale_matrix(DJUI_MTX_NOPUSH, translatedFontSize, translatedFontSize, 1.0f);
// render the line
f32 addX = 0;
char* c = (char*)message;
while (*c != '\0') {
f32 charWidth = font->char_width(c);
// allocate the translation matrix for the vertical alignment
InterpHudGfx *valignGfx = djui_hud_create_interp_gfx(interp, INTERP_HUD_VALIGN);
Mtx *valignMatrix = allocate_dl_translation_matrix();
if (valignMatrix == NULL) { return; }
if (*c == '\n' && *c == ' ') {
addX += charWidth;
c++;
// allocate the translation matrix for the horizontal alignment
InterpHudGfx *halignGfx = djui_hud_create_interp_gfx(interp, INTERP_HUD_HALIGN);
Mtx *halignMatrix = allocate_dl_translation_matrix();
if (halignMatrix == NULL) { return; }
// render the line
char* c = (char*)message;
const char *end = message + strlen(message);
f32 lineWidth = 0;
f32 textHeight = font->lineHeight;
font->render_begin();
while (*c != '\0') {
// check color code
struct DjuiColor parsedColor;
if (djui_text_parse_color(c, end, false, &sHudUtilsState.color, &c, &parsedColor)) {
gDPSetEnvColor(gDisplayListHead++, parsedColor.r, parsedColor.g, parsedColor.b, parsedColor.a);
continue;
}
// new line
if (*c == '\n') {
// compute the horizontal alignment matrix for the current line
guTranslate(halignMatrix, -lineWidth * sHudUtilsState.textAlignment.h.curr, 0, 0);
if (halignGfx) { halignGfx->params[0] = lineWidth; }
// allocate a new translation matrix for the next line
halignGfx = djui_hud_create_interp_gfx(interp, INTERP_HUD_HALIGN);
halignMatrix = allocate_dl_translation_matrix();
if (halignMatrix == NULL) { return; }
// cancel out the line translation and move to the next line
// this is needed because otherwise the text would be rendered in a staircase way
InterpHudGfx *newlineGfx = djui_hud_create_interp_gfx(interp, INTERP_HUD_NEW_LINE);
create_dl_translation_matrix(DJUI_MTX_NOPUSH, -lineWidth * (1.f - sHudUtilsState.textAlignment.h.curr), -font->lineHeight, 0);
if (newlineGfx) { newlineGfx->params[0] = lineWidth; }
lineWidth = 0;
textHeight += font->lineHeight;
c = djui_unicode_next_char(c);
continue;
}
// tab: align to the next (4 x space width)
else if (*c == '\t') {
f32 tabWidth = 4 * font->char_width(" ");
f32 newLineWidth = lineWidth + tabWidth - fmodf(lineWidth, tabWidth);
create_dl_translation_matrix(DJUI_MTX_NOPUSH, newLineWidth - lineWidth, 0, 0);
lineWidth = newLineWidth;
c = djui_unicode_next_char(c);
continue;
}
// unprintable chars
if (!djui_text_is_printable(c)) {
c = djui_unicode_next_char(c);
continue;
}
// render
f32 charWidth = font->char_width(c);
font->render_char(c);
create_dl_translation_matrix(DJUI_MTX_NOPUSH, charWidth + addX, 0, 0);
addX = 0;
create_dl_translation_matrix(DJUI_MTX_NOPUSH, charWidth, 0, 0);
lineWidth += charWidth;
c = djui_unicode_next_char(c);
}
font->render_end();
// compute the horizontal alignment matrix for the last line
guTranslate(halignMatrix, -lineWidth * sHudUtilsState.textAlignment.h.curr, 0, 0);
if (halignGfx) { halignGfx->params[0] = lineWidth; }
// compute the vertical alignment matrix
guTranslate(valignMatrix, 0, textHeight * sHudUtilsState.textAlignment.v.curr, 0);
if (valignGfx) { valignGfx->params[0] = textHeight; }
// pop
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
void djui_hud_print_text(const char* message, f32 x, f32 y, f32 scale) {
djui_hud_print_text_internal(message, x, y, scale, NULL);
}
void djui_hud_print_text_interpolated(const char* message, f32 prevX, f32 prevY, f32 prevScale, f32 x, f32 y, f32 scale) {
if (message == NULL) { return; }
f32 savedZ = gDjuiHudUtilsZ;
gDjuiHudUtilsZ += 0.001f;
if (sLegacy) {
prevScale *= 0.5f;
scale *= 0.5f;
if (djui_hud_text_font_is_legacy()) { prevScale *= 0.5f; }
struct InterpHud *interp = djui_hud_create_interp();
if (interp) {
const struct DjuiFont* font = djui_hud_get_text_font();
interp->posX.prev = prevX;
interp->posY.prev = prevY;
interp->posX.curr = x;
interp->posY.curr = y;
interp->scaleX.prev = prevScale;
interp->scaleY.prev = prevScale;
interp->scaleX.curr = scale;
interp->scaleY.curr = scale;
interp->width = font->defaultFontScale;
interp->height = font->defaultFontScale;
}
const struct DjuiFont* font = gDjuiFonts[sFont];
f32 fontScale = font->defaultFontScale * scale;
// setup display list
if (font->textBeginDisplayList != NULL) {
gSPDisplayList(gDisplayListHead++, font->textBeginDisplayList);
}
Gfx* savedHeadPos = gDisplayListHead;
// translate position
f32 translatedX = x + (font->xOffset * scale);
f32 translatedY = y + (font->yOffset * scale);
djui_hud_position_translate(&translatedX, &translatedY);
create_dl_translation_matrix(DJUI_MTX_PUSH, translatedX, translatedY, gDjuiHudUtilsZ);
// compute font size
f32 translatedFontSize = fontScale;
djui_hud_size_translate(&translatedFontSize);
create_dl_scale_matrix(DJUI_MTX_NOPUSH, translatedFontSize, translatedFontSize, 1.0f);
// render the line
f32 addX = 0;
char* c = (char*)message;
while (*c != '\0') {
f32 charWidth = font->char_width(c);
if (*c == '\n' && *c == ' ') {
addX += charWidth;
c++;
continue;
}
// render
font->render_char(c);
create_dl_translation_matrix(DJUI_MTX_NOPUSH, charWidth + addX, 0, 0);
addX = 0;
c = djui_unicode_next_char(c);
}
// pop
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
if (sInterpHudCount >= MAX_INTERP_HUD) { return; }
struct InterpHud* interp = &sInterpHuds[sInterpHudCount++];
interp->headPos = savedHeadPos;
interp->prevX = prevX;
interp->prevY = prevY;
interp->prevScaleW = prevScale;
interp->prevScaleH = prevScale;
interp->x = x;
interp->y = y;
interp->scaleW = scale;
interp->scaleH = scale;
interp->width = font->defaultFontScale;
interp->height = font->defaultFontScale;
interp->z = savedZ;
interp->resolution = sResolution;
interp->rotation = sRotation;
djui_hud_print_text_internal(message, x, y, scale, interp);
}
static inline bool is_power_of_two(u32 n) {
return (n > 0) && ((n & (n - 1)) == 0);
}
static void djui_hud_render_texture_raw(const Texture* texture, u32 width, u32 height, u8 fmt, u8 siz, f32 x, f32 y, f32 scaleW, f32 scaleH) {
static void djui_hud_render_texture_raw(const Texture* texture, u32 width, u32 height, u8 fmt, u8 siz, f32 x, f32 y, f32 scaleW, f32 scaleH, struct InterpHud *interp) {
if (!is_power_of_two(width) || !is_power_of_two(height)) {
LOG_LUA_LINE("Tried to render DJUI HUD texture with NPOT width or height");
return;
@ -510,6 +695,7 @@ static void djui_hud_render_texture_raw(const Texture* texture, u32 width, u32 h
gDjuiHudUtilsZ += 0.001f;
// translate position
djui_hud_create_interp_gfx(interp, INTERP_HUD_TRANSLATION);
f32 translatedX = x;
f32 translatedY = y;
djui_hud_position_translate(&translatedX, &translatedY);
@ -520,25 +706,27 @@ static void djui_hud_render_texture_raw(const Texture* texture, u32 width, u32 h
f32 translatedH = scaleH;
djui_hud_size_translate(&translatedW);
djui_hud_size_translate(&translatedH);
if (sRotation.rotation != 0) {
f32 pivotTranslationX = width * translatedW * sRotation.pivotX;
f32 pivotTranslationY = height * translatedH * sRotation.pivotY;
if (sHudUtilsState.rotation.degrees.prev != 0 || sHudUtilsState.rotation.degrees.curr != 0) {
djui_hud_create_interp_gfx(interp, INTERP_HUD_ROTATION);
f32 pivotTranslationX = width * translatedW * sHudUtilsState.rotation.pivotX.curr;
f32 pivotTranslationY = height * translatedH * sHudUtilsState.rotation.pivotY.curr;
create_dl_translation_matrix(DJUI_MTX_NOPUSH, +pivotTranslationX, -pivotTranslationY, 0);
create_dl_rotation_matrix(DJUI_MTX_NOPUSH, sRotation.rotation, 0, 0, 1);
create_dl_rotation_matrix(DJUI_MTX_NOPUSH, sHudUtilsState.rotation.degrees.curr, 0, 0, 1);
create_dl_translation_matrix(DJUI_MTX_NOPUSH, -pivotTranslationX, +pivotTranslationY, 0);
}
// translate scale
djui_hud_create_interp_gfx(interp, INTERP_HUD_SCALE);
create_dl_scale_matrix(DJUI_MTX_NOPUSH, width * translatedW, height * translatedH, 1.0f);
// render
djui_gfx_render_texture(texture, width, height, fmt, siz, sFilter);
djui_gfx_render_texture(texture, width, height, fmt, siz, sHudUtilsState.filter);
// pop
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
static void djui_hud_render_texture_tile_raw(const Texture* texture, u32 width, u32 height, u8 fmt, u8 siz, f32 x, f32 y, f32 scaleW, f32 scaleH, u32 tileX, u32 tileY, u32 tileW, u32 tileH) {
static void djui_hud_render_texture_tile_raw(const Texture* texture, u32 width, u32 height, u8 fmt, u8 siz, f32 x, f32 y, f32 scaleW, f32 scaleH, u32 tileX, u32 tileY, u32 tileW, u32 tileH, struct InterpHud *interp) {
if (!texture) { return; }
gDjuiHudUtilsZ += 0.001f;
@ -546,6 +734,7 @@ static void djui_hud_render_texture_tile_raw(const Texture* texture, u32 width,
if (height != 0) { scaleH *= (f32) tileH / (f32) height; }
// translate position
djui_hud_create_interp_gfx(interp, INTERP_HUD_TRANSLATION);
f32 translatedX = x;
f32 translatedY = y;
djui_hud_position_translate(&translatedX, &translatedY);
@ -556,20 +745,22 @@ static void djui_hud_render_texture_tile_raw(const Texture* texture, u32 width,
f32 translatedH = scaleH;
djui_hud_size_translate(&translatedW);
djui_hud_size_translate(&translatedH);
if (sRotation.rotation != 0) {
if (sHudUtilsState.rotation.degrees.prev != 0 || sHudUtilsState.rotation.degrees.curr != 0) {
djui_hud_create_interp_gfx(interp, INTERP_HUD_ROTATION);
f32 aspect = tileH ? ((f32) tileW / (f32) tileH) : 1.f;
f32 pivotTranslationX = width * translatedW * aspect * sRotation.pivotX;
f32 pivotTranslationY = height * translatedH * sRotation.pivotY;
f32 pivotTranslationX = width * translatedW * aspect * sHudUtilsState.rotation.pivotX.curr;
f32 pivotTranslationY = height * translatedH * sHudUtilsState.rotation.pivotY.curr;
create_dl_translation_matrix(DJUI_MTX_NOPUSH, +pivotTranslationX, -pivotTranslationY, 0);
create_dl_rotation_matrix(DJUI_MTX_NOPUSH, sRotation.rotation, 0, 0, 1);
create_dl_rotation_matrix(DJUI_MTX_NOPUSH, sHudUtilsState.rotation.degrees.curr, 0, 0, 1);
create_dl_translation_matrix(DJUI_MTX_NOPUSH, -pivotTranslationX, +pivotTranslationY, 0);
}
// translate scale
djui_hud_create_interp_gfx(interp, INTERP_HUD_SCALE);
create_dl_scale_matrix(DJUI_MTX_NOPUSH, width * translatedW, height * translatedH, 1.0f);
// render
djui_gfx_render_texture_tile(texture, width, height, fmt, siz, tileX, tileY, tileW, tileH, sFilter, false);
djui_gfx_render_texture_tile(texture, width, height, fmt, siz, tileX, tileY, tileW, tileH, sHudUtilsState.filter);
// pop
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
@ -577,44 +768,35 @@ static void djui_hud_render_texture_tile_raw(const Texture* texture, u32 width,
void djui_hud_render_texture(struct TextureInfo* texInfo, f32 x, f32 y, f32 scaleW, f32 scaleH) {
if (!texInfo) { return; }
djui_hud_render_texture_raw(texInfo->texture, texInfo->width, texInfo->height, texInfo->format, texInfo->size, x, y, scaleW, scaleH);
djui_hud_render_texture_raw(texInfo->texture, texInfo->width, texInfo->height, texInfo->format, texInfo->size, x, y, scaleW, scaleH, NULL);
}
void djui_hud_render_texture_tile(struct TextureInfo* texInfo, f32 x, f32 y, f32 scaleW, f32 scaleH, u32 tileX, u32 tileY, u32 tileW, u32 tileH) {
if (!texInfo) { return; }
djui_hud_render_texture_tile_raw(texInfo->texture, texInfo->width, texInfo->height, texInfo->format, texInfo->size, x, y, scaleW, scaleH, tileX, tileY, tileW, tileH);
djui_hud_render_texture_tile_raw(texInfo->texture, texInfo->width, texInfo->height, texInfo->format, texInfo->size, x, y, scaleW, scaleH, tileX, tileY, tileW, tileH, NULL);
}
void djui_hud_render_texture_interpolated(struct TextureInfo* texInfo, f32 prevX, f32 prevY, f32 prevScaleW, f32 prevScaleH, f32 x, f32 y, f32 scaleW, f32 scaleH) {
Gfx* savedHeadPos = gDisplayListHead;
f32 savedZ = gDjuiHudUtilsZ;
if (!texInfo) { return; }
djui_hud_render_texture_raw(texInfo->texture, texInfo->width, texInfo->height, texInfo->format, texInfo->size, prevX, prevY, prevScaleW, prevScaleH);
struct InterpHud *interp = djui_hud_create_interp();
if (interp) {
interp->posX.prev = prevX;
interp->posY.prev = prevY;
interp->posX.curr = x;
interp->posY.curr = y;
interp->scaleX.prev = prevScaleW;
interp->scaleY.prev = prevScaleH;
interp->scaleX.curr = scaleW;
interp->scaleY.curr = scaleH;
interp->width = texInfo->width;
interp->height = texInfo->height;
}
if (sInterpHudCount >= MAX_INTERP_HUD) { return; }
struct InterpHud* interp = &sInterpHuds[sInterpHudCount++];
interp->headPos = savedHeadPos;
interp->prevX = prevX;
interp->prevY = prevY;
interp->prevScaleW = prevScaleW;
interp->prevScaleH = prevScaleH;
interp->x = x;
interp->y = y;
interp->scaleW = scaleW;
interp->scaleH = scaleH;
interp->width = texInfo->width;
interp->height = texInfo->height;
interp->z = savedZ;
interp->resolution = sResolution;
interp->rotation = sRotation;
djui_hud_render_texture_raw(texInfo->texture, texInfo->width, texInfo->height, texInfo->format, texInfo->size, prevX, prevY, prevScaleW, prevScaleH, interp);
}
void djui_hud_render_texture_tile_interpolated(struct TextureInfo* texInfo, f32 prevX, f32 prevY, f32 prevScaleW, f32 prevScaleH, f32 x, f32 y, f32 scaleW, f32 scaleH, u32 tileX, u32 tileY, u32 tileW, u32 tileH) {
Gfx* savedHeadPos = gDisplayListHead;
f32 savedZ = gDjuiHudUtilsZ;
if (!texInfo) { return; }
// apply scale correction for tiles
@ -627,30 +809,28 @@ void djui_hud_render_texture_tile_interpolated(struct TextureInfo* texInfo, f32
prevScaleH *= ((f32)tileH / (f32)texInfo->height);
}
djui_hud_render_texture_tile_raw(texInfo->texture, texInfo->width, texInfo->height, texInfo->format, texInfo->size, prevX, prevY, prevScaleW, prevScaleH, tileX, tileY, tileW, tileH);
struct InterpHud *interp = djui_hud_create_interp();
if (interp) {
interp->posX.prev = prevX;
interp->posY.prev = prevY;
interp->posX.curr = x;
interp->posY.curr = y;
interp->scaleX.prev = prevScaleW;
interp->scaleY.prev = prevScaleH;
interp->scaleX.curr = scaleW;
interp->scaleY.curr = scaleH;
interp->width = texInfo->width;
interp->height = texInfo->height;
}
if (sInterpHudCount >= MAX_INTERP_HUD) { return; }
struct InterpHud* interp = &sInterpHuds[sInterpHudCount++];
interp->headPos = savedHeadPos;
interp->prevX = prevX;
interp->prevY = prevY;
interp->prevScaleW = prevScaleW;
interp->prevScaleH = prevScaleH;
interp->x = x;
interp->y = y;
interp->scaleW = scaleW;
interp->scaleH = scaleH;
interp->width = texInfo->width;
interp->height = texInfo->height;
interp->z = savedZ;
interp->resolution = sResolution;
interp->rotation = sRotation;
djui_hud_render_texture_tile_raw(texInfo->texture, texInfo->width, texInfo->height, texInfo->format, texInfo->size, prevX, prevY, prevScaleW, prevScaleH, tileX, tileY, tileW, tileH, interp);
}
void djui_hud_render_rect(f32 x, f32 y, f32 width, f32 height) {
static void djui_hud_render_rect_internal(f32 x, f32 y, f32 width, f32 height, struct InterpHud *interp) {
gDjuiHudUtilsZ += 0.001f;
// translate position
djui_hud_create_interp_gfx(interp, INTERP_HUD_TRANSLATION);
f32 translatedX = x;
f32 translatedY = y;
djui_hud_position_translate(&translatedX, &translatedY);
@ -661,15 +841,17 @@ void djui_hud_render_rect(f32 x, f32 y, f32 width, f32 height) {
f32 translatedH = height;
djui_hud_size_translate(&translatedW);
djui_hud_size_translate(&translatedH);
if (sRotation.rotation != 0) {
f32 pivotTranslationX = translatedW * sRotation.pivotX;
f32 pivotTranslationY = translatedH * sRotation.pivotY;
if (sHudUtilsState.rotation.degrees.prev != 0 || sHudUtilsState.rotation.degrees.curr != 0) {
djui_hud_create_interp_gfx(interp, INTERP_HUD_ROTATION);
f32 pivotTranslationX = translatedW * sHudUtilsState.rotation.pivotX.curr;
f32 pivotTranslationY = translatedH * sHudUtilsState.rotation.pivotY.curr;
create_dl_translation_matrix(DJUI_MTX_NOPUSH, +pivotTranslationX, -pivotTranslationY, 0);
create_dl_rotation_matrix(DJUI_MTX_NOPUSH, sRotation.rotation, 0, 0, 1);
create_dl_rotation_matrix(DJUI_MTX_NOPUSH, sHudUtilsState.rotation.degrees.curr, 0, 0, 1);
create_dl_translation_matrix(DJUI_MTX_NOPUSH, -pivotTranslationX, +pivotTranslationY, 0);
}
// translate scale
djui_hud_create_interp_gfx(interp, INTERP_HUD_SCALE);
create_dl_scale_matrix(DJUI_MTX_NOPUSH, translatedW, translatedH, 1.0f);
// render
@ -679,28 +861,26 @@ void djui_hud_render_rect(f32 x, f32 y, f32 width, f32 height) {
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
void djui_hud_render_rect(f32 x, f32 y, f32 width, f32 height) {
djui_hud_render_rect_internal(x, y, width, height, NULL);
}
void djui_hud_render_rect_interpolated(f32 prevX, f32 prevY, f32 prevWidth, f32 prevHeight, f32 x, f32 y, f32 width, f32 height) {
Gfx* savedHeadPos = gDisplayListHead;
f32 savedZ = gDjuiHudUtilsZ;
struct InterpHud *interp = djui_hud_create_interp();
if (interp) {
interp->posX.prev = prevX;
interp->posY.prev = prevY;
interp->posX.curr = x;
interp->posY.curr = y;
interp->scaleX.prev = prevWidth;
interp->scaleY.prev = prevHeight;
interp->scaleX.curr = width;
interp->scaleY.curr = height;
interp->width = 1;
interp->height = 1;
}
djui_hud_render_rect(prevX, prevY, prevWidth, prevHeight);
if (sInterpHudCount >= MAX_INTERP_HUD) { return; }
struct InterpHud* interp = &sInterpHuds[sInterpHudCount++];
interp->headPos = savedHeadPos;
interp->prevX = prevX;
interp->prevY = prevY;
interp->prevScaleW = prevWidth;
interp->prevScaleH = prevHeight;
interp->x = x;
interp->y = y;
interp->scaleW = width;
interp->scaleH = height;
interp->width = 1;
interp->height = 1;
interp->z = savedZ;
interp->resolution = sResolution;
interp->rotation = sRotation;
djui_hud_render_rect_internal(prevX, prevY, prevWidth, prevHeight, interp);
}
void djui_hud_render_line(f32 p1X, f32 p1Y, f32 p2X, f32 p2Y, f32 size) {
@ -752,7 +932,7 @@ bool djui_hud_world_pos_to_screen_pos(Vec3f pos, VEC_OUT Vec3f out) {
out[1] *= fovCoeff;
f32 screenWidth, screenHeight;
if (sResolution == RESOLUTION_N64) {
if (sHudUtilsState.resolution == RESOLUTION_N64) {
screenWidth = GFX_DIMENSIONS_ASPECT_RATIO * SCREEN_HEIGHT;
screenHeight = SCREEN_HEIGHT;
} else {

View file

@ -1,6 +1,22 @@
#ifndef DJUI_HUD_UTILS_H
#define DJUI_HUD_UTILS_H
// Common pivot values for rotation
#define ROTATION_PIVOT_X_LEFT 0.0
#define ROTATION_PIVOT_X_CENTER 0.5
#define ROTATION_PIVOT_X_RIGHT 1.0
#define ROTATION_PIVOT_Y_TOP 0.0
#define ROTATION_PIVOT_Y_CENTER 0.5
#define ROTATION_PIVOT_Y_BOTTOM 1.0
// Common alignment values for text alignment
#define TEXT_HALIGN_LEFT 0.0
#define TEXT_HALIGN_CENTER 0.5
#define TEXT_HALIGN_RIGHT 1.0
#define TEXT_VALIGN_TOP 0.0
#define TEXT_VALIGN_CENTER 0.5
#define TEXT_VALIGN_BOTTOM 1.0
enum HudUtilsResolution {
RESOLUTION_DJUI,
RESOLUTION_N64,
@ -14,7 +30,8 @@ enum HudUtilsFilter {
};
enum DjuiFontType {
FONT_NORMAL,
FONT_LEGACY = -1,
FONT_NORMAL = 0,
FONT_MENU,
FONT_HUD,
FONT_ALIASED,
@ -24,15 +41,6 @@ enum DjuiFontType {
FONT_COUNT,
};
struct HudUtilsRotation {
f32 rotation;
f32 rotationDiff;
f32 prevPivotX;
f32 prevPivotY;
f32 pivotX;
f32 pivotY;
};
struct GlobalTextures {
struct TextureInfo camera;
struct TextureInfo lakitu;
@ -63,7 +71,7 @@ u8 djui_hud_get_filter(void);
/* |description|Sets the current DJUI HUD texture filter|descriptionEnd| */
void djui_hud_set_filter(enum HudUtilsFilter filterType);
/* |description|Gets the current DJUI HUD font|descriptionEnd| */
u8 djui_hud_get_font(void);
s8 djui_hud_get_font(void);
/* |description|Sets the current DJUI HUD font|descriptionEnd| */
void djui_hud_set_font(s8 fontType);
/* |description|Gets the current DJUI HUD color|descriptionEnd| */
@ -73,11 +81,17 @@ void djui_hud_set_color(u8 r, u8 g, u8 b, u8 a);
/* |description|Resets the current DJUI HUD color|descriptionEnd| */
void djui_hud_reset_color(void);
/* |description|Gets the current DJUI HUD rotation|descriptionEnd| */
struct HudUtilsRotation* djui_hud_get_rotation(void);
void djui_hud_get_rotation(RET s16 *rotation, RET f32 *pivotX, RET f32 *pivotY);
/* |description|Sets the current DJUI HUD rotation|descriptionEnd| */
void djui_hud_set_rotation(s16 rotation, f32 pivotX, f32 pivotY);
/* |description|Sets the current DJUI HUD rotation interpolated|descriptionEnd| */
void djui_hud_set_rotation_interpolated(s32 prevRotation, f32 prevPivotX, f32 prevPivotY, s32 rotation, f32 pivotX, f32 pivotY);
void djui_hud_set_rotation_interpolated(s16 prevRotation, f32 prevPivotX, f32 prevPivotY, s16 rotation, f32 pivotX, f32 pivotY);
/* |description|Gets the current DJUI HUD text alignment|descriptionEnd| */
void djui_hud_get_text_alignment(RET f32 *textHAlign, RET f32 *textVAlign);
/* |description|Sets the current DJUI HUD text alignment|descriptionEnd| */
void djui_hud_set_text_alignment(f32 textHAlign, f32 textVAlign);
/* |description|Sets the current DJUI HUD text alignment interpolated|descriptionEnd| */
void djui_hud_set_text_alignment_interpolated(f32 prevTextHAlign, f32 prevTextVAlign, f32 textHAlign, f32 textVAlign);
/* |description|Gets the screen width in the current DJUI HUD resolution|descriptionEnd| */
u32 djui_hud_get_screen_width(void);

View file

@ -589,6 +589,8 @@ static bool djui_inputbox_render(struct DjuiBase* base) {
f32 drawX = inputbox->viewX;
f32 additionalShift = 0;
bool wasInsideSelection = false;
font->render_begin();
for (u16 i = 0; i < inputbox->bufferSize; i++) {
//render composition text
@ -617,6 +619,7 @@ static bool djui_inputbox_render(struct DjuiBase* base) {
djui_inputbox_render_char(inputbox, c, &drawX, &additionalShift);
c = djui_unicode_next_char(c);
}
font->render_end();
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);

View file

@ -113,7 +113,8 @@ void djui_panel_mod_menu_mod_create(struct DjuiBase* caller) {
}
if (mod == NULL) { return; }
struct DjuiThreePanel* panel = djui_panel_menu_create(to_uppercase(mod->name), false);
char *modNameUppercase = to_uppercase(mod->name);
struct DjuiThreePanel* panel = djui_panel_menu_create(modNameUppercase, false);
struct DjuiBase* body = djui_three_panel_get_body(panel);
{
struct DjuiPaginated* paginated = djui_paginated_create(body, 8);
@ -130,6 +131,7 @@ void djui_panel_mod_menu_mod_create(struct DjuiBase* caller) {
}
djui_panel_add(caller, panel, NULL);
free(modNameUppercase);
}
void djui_panel_mod_menu_create(struct DjuiBase* caller) {

View file

@ -4,10 +4,146 @@
#include "djui_hud_utils.h"
#include "game/segment2.h"
static u8 sSavedR = 0;
static u8 sSavedG = 0;
static u8 sSavedB = 0;
static u8 sSavedA = 0;
///////////
// color //
///////////
static const struct DjuiColor sDjuiTextDefaultColor = { 220, 220, 220, 255 };
static struct DjuiColor sDjuiTextCurrentColor;
bool djui_text_parse_color(char *begin, const char *end, bool ignoreAlpha, const struct DjuiColor *baseColor, char **nextChar, struct DjuiColor *parsedColor) {
char *c = begin;
// Not an escape
if (*c != '\\') {
return false;
}
c = djui_unicode_next_char(c);
// Not a color
if (*c != '#') {
return false;
}
c = djui_unicode_next_char(c);
// Parse color
u32 color = 0;
u8 length = 0;
while (c < end) {
if (*c == '\\') {
break;
}
u8 colorPiece = 0;
if (*c >= '0' && *c <= '9') { colorPiece = *c - '0'; }
else if (*c >= 'a' && *c <= 'f') { colorPiece = 10 + *c - 'a'; }
else if (*c >= 'A' && *c <= 'F') { colorPiece = 10 + *c - 'A'; }
else { // Not a valid color piece
return false;
}
color = (color << 4) | colorPiece;
length++;
c = djui_unicode_next_char(c);
}
// Unterminated color code
if (c == end) {
return false;
}
switch (length) {
// reset to base color
case 0: {
if (baseColor && parsedColor) {
*parsedColor = *baseColor;
}
} break;
// #rgb
case 3: {
if (parsedColor) {
u32 r = (color >> 8) & 0xF;
u32 g = (color >> 4) & 0xF;
u32 b = (color >> 0) & 0xF;
parsedColor->r = (r << 4) | r;
parsedColor->g = (g << 4) | g;
parsedColor->b = (b << 4) | b;
parsedColor->a = 0xFF;
}
} break;
// #rgba
case 4: {
if (parsedColor) {
u32 r = (color >> 12) & 0xF;
u32 g = (color >> 8) & 0xF;
u32 b = (color >> 4) & 0xF;
u32 a = (color >> 0) & 0xF;
parsedColor->r = (r << 4) | r;
parsedColor->g = (g << 4) | g;
parsedColor->b = (b << 4) | b;
parsedColor->a = ignoreAlpha ? 0xFF : ((a << 4) | a);
}
} break;
// #rrggbb
case 6: {
if (parsedColor) {
parsedColor->r = ((color >> 16) & 0xFF);
parsedColor->g = ((color >> 8) & 0xFF);
parsedColor->b = ((color >> 0) & 0xFF);
parsedColor->a = 0xFF;
}
} break;
// #rrggbbaa
case 8: {
if (parsedColor) {
parsedColor->r = ((color >> 24) & 0xFF);
parsedColor->g = ((color >> 16) & 0xFF);
parsedColor->b = ((color >> 8) & 0xFF);
parsedColor->a = ignoreAlpha ? 0xFF : ((color >> 0) & 0xFF);
}
} break;
// Invalid color
default: return false;
}
if (nextChar) {
*nextChar = djui_unicode_next_char(c);
}
return true;
}
void djui_text_remove_colors(char *str) {
if (!str) { return; }
char *colorStart = str;
const char *strEnd = str + strlen(str);
while ((colorStart = strstr(colorStart, "\\#"))) {
char *colorEnd;
if (djui_text_parse_color(colorStart, strEnd, false, NULL, &colorEnd, NULL) && colorEnd > colorStart) {
memmove(colorStart, colorEnd, strlen(colorEnd) + 1);
} else {
colorStart++;
}
}
}
char *djui_text_get_uncolored_string(char *dest, size_t length, const char *str) {
if (!dest) {
dest = malloc(length * sizeof(char));
if (!dest) {
return NULL;
}
}
strncpy(dest, str, length - 1);
dest[length - 1] = 0;
djui_text_remove_colors(dest);
return dest;
}
////////////////
// properties //
@ -59,6 +195,10 @@ static f32 sTextRenderY = 0;
static f32 sTextRenderLastX = 0;
static f32 sTextRenderLastY = 0;
bool djui_text_is_printable(const char *c) {
return c != NULL && (!iscntrl(*c) || *c == 0x7F); // the star
}
static void djui_text_translate(f32 x, f32 y) {
sTextRenderX += x;
sTextRenderY += y;
@ -90,7 +230,7 @@ static void djui_text_render_char(struct DjuiText* text, char* c) {
sTextRenderY += 1.0f / text->fontScale;
gDPSetEnvColor(gDisplayListHead++, text->dropShadow.r, text->dropShadow.g, text->dropShadow.b, text->dropShadow.a);
djui_text_render_single_char(text, c);
gDPSetEnvColor(gDisplayListHead++, sSavedR, sSavedG, sSavedB, sSavedA);
gDPSetEnvColor(gDisplayListHead++, sDjuiTextCurrentColor.r, sDjuiTextCurrentColor.g, sDjuiTextCurrentColor.b, sDjuiTextCurrentColor.a);
sTextRenderX -= 1.0f / text->fontScale;
sTextRenderY -= 1.0f / text->fontScale;
}
@ -99,16 +239,21 @@ static void djui_text_render_char(struct DjuiText* text, char* c) {
static f32 djui_text_measure_word_width(struct DjuiText* text, char* message) {
f32 width = 0;
bool skipping = false;
char* c = message;
const char *end = message + strlen(message);
while (*c != '\0') {
if (*c == ' ') { return width; }
if (*c == '\n') { return width; }
if (*c == '\0') { return width; }
if (*c == '\\') { skipping = !skipping; }
if (!skipping) {
width += text->font->char_width(c);
// color code
if (djui_text_parse_color(c, end, true, NULL, &c, NULL)) {
continue;
}
// end of word due to unprintable chars or space
if (!djui_text_is_printable(c) || *c == ' ') {
return width;
}
width += text->font->char_width(c);
c = djui_unicode_next_char(c);
}
return width;
@ -122,17 +267,18 @@ static void djui_text_read_line(struct DjuiText* text, char** message, f32* line
u16 lastSafeEllipsesIndex = *index;
u16 lastSafeEllipsesLineWidth = *lineWidth + ellipsesWidth;*/
bool skipping = false;
char* c = *message;
const char *end = *message + strlen(*message);
while (*c != '\0') {
f32 charWidth = text->font->char_width(c);
// check for special escape sequences
if (*c == '\\') { skipping = !skipping; }
if (skipping || *c == '\\') {
// check for color code
if (*c == '\\') {
lastC = c;
c = djui_unicode_next_char(c);
continue;
if (djui_text_parse_color(c, end, true, NULL, &c, NULL)) {
lastC = c;
continue;
}
}
// check for newline
@ -212,59 +358,6 @@ f32 djui_text_find_width(struct DjuiText* text, u16 maxLines) {
return largestWidth * text->fontScale;
}
static char* djui_text_render_line_parse_escape(char* c1, char* c2) {
bool parsingColor = (c1[1] == '#');
char* c = parsingColor ? (c1 + 2) : (c1 + 1);
u32 color = 0;
u8 colorPieces = 0;
while (c < c2) {
if (*c == '\\') { break; }
if (parsingColor) {
u8 colorPiece = 0;
if (*c >= '0' && *c <= '9') { colorPiece = *c - '0'; }
else if (*c >= 'a' && *c <= 'f') { colorPiece = 10 + *c - 'a'; }
else if (*c >= 'A' && *c <= 'F') { colorPiece = 10 + *c - 'A'; }
color = (color << 4) | colorPiece;
colorPieces++;
}
c = djui_unicode_next_char(c);
}
if (parsingColor) {
if (colorPieces == 3) {
u32 r = (color >> 8) & 0xF;
u32 g = (color >> 4) & 0xF;
u32 b = (color >> 0) & 0xF;
sSavedR = (r << 4) | r;
sSavedG = (g << 4) | g;
sSavedB = (b << 4) | b;
/*} else if (colorPieces == 4) {
u32 r = (color >> 12) & 0xF;
u32 g = (color >> 8) & 0xF;
u32 b = (color >> 4) & 0xF;
u32 a = (color >> 0) & 0xF;
sSavedR = (r << 4) | r;
sSavedG = (g << 4) | g;
sSavedB = (b << 4) | b;
sSavedA = (a << 4) | a;*/
} else if (colorPieces == 6) {
sSavedR = ((color >> 16) & 0xFF);
sSavedG = ((color >> 8) & 0xFF);
sSavedB = ((color >> 0) & 0xFF);
}/*else if (colorPieces == 8) {
sSavedR = ((color >> 24) & 0xFF);
sSavedG = ((color >> 16) & 0xFF);
sSavedB = ((color >> 8) & 0xFF);
sSavedA = ((color >> 0) & 0xFF);
}*/
gDPSetEnvColor(gDisplayListHead++, sSavedR, sSavedG, sSavedB, sSavedA);
}
c = djui_unicode_next_char(c);
return c;
}
static void djui_text_render_line(struct DjuiText* text, char* c1, char* c2, f32 lineWidth, bool ellipses) {
struct DjuiBase* base = &text->base;
struct DjuiBaseRect* comp = &base->comp;
@ -284,9 +377,13 @@ static void djui_text_render_line(struct DjuiText* text, char* c1, char* c2, f32
}
// render the line
text->font->render_begin();
for (char* c = c1; c < c2;) {
if (*c == '\\') {
c = djui_text_render_line_parse_escape(c, c2);
struct DjuiColor parsedColor;
if (djui_text_parse_color(c, c2, true, &sDjuiTextDefaultColor, &c, &parsedColor)) {
gDPSetEnvColor(gDisplayListHead++, parsedColor.r, parsedColor.g, parsedColor.b, parsedColor.a);
sDjuiTextCurrentColor = parsedColor;
continue;
}
@ -312,6 +409,8 @@ static void djui_text_render_line(struct DjuiText* text, char* c1, char* c2, f32
}
}
text->font->render_end();
// reset translation matrix
djui_text_translate(-curWidth, text->font->lineHeight);
}
@ -352,10 +451,7 @@ static bool djui_text_render(struct DjuiBase* base) {
// set color
gDPSetEnvColor(gDisplayListHead++, base->color.r, base->color.g, base->color.b, base->color.a);
sSavedR = base->color.r;
sSavedG = base->color.g;
sSavedB = base->color.b;
sSavedA = base->color.a;
sDjuiTextCurrentColor = base->color;
// count lines
u16 maxLines = comp->height / ((f32)text->font->lineHeight * text->fontScale);

View file

@ -11,12 +11,17 @@ struct DjuiText {
enum DjuiVAlign textVAlign;
};
bool djui_text_parse_color(char *begin, const char *end, bool ignoreAlpha, const struct DjuiColor *baseColor, char **nextChar, struct DjuiColor *parsedColor);
void djui_text_remove_colors(char *str);
char *djui_text_get_uncolored_string(char *dest, size_t length, const char *str);
void djui_text_set_text(struct DjuiText* text, const char* message);
void djui_text_set_font(struct DjuiText* text, const struct DjuiFont* font);
void djui_text_set_font_scale(struct DjuiText* text, f32 fontScale);
void djui_text_set_drop_shadow(struct DjuiText* text, f32 r, f32 g, f32 b, f32 a);
void djui_text_set_alignment(struct DjuiText* text, enum DjuiHAlign hAlign, enum DjuiVAlign vAlign);
bool djui_text_is_printable(const char *c);
int djui_text_count_lines(struct DjuiText* text, u16 maxLines);
f32 djui_text_find_width(struct DjuiText* text, u16 maxLines);

View file

@ -204,7 +204,7 @@ struct SmCodeGlyph sSmCodeDuplicateGlyphs[] = {
static void* sCharMap = NULL;
static s32 count_bytes_for_char(char* text) {
static s32 count_bytes_for_char(const char* text) {
s32 bytes = 0;
u8 mask = (1 << 7);
while (*text & mask) {
@ -214,7 +214,7 @@ static s32 count_bytes_for_char(char* text) {
return bytes ? bytes : 1;
}
static u64 convert_unicode_char_to_u64(char* text) {
static u64 convert_unicode_char_to_u64(const char* text) {
s32 bytes = count_bytes_for_char(text);
u64 value = (u8)*text;
@ -273,7 +273,7 @@ void djui_unicode_init(void) {
}
}
u32 djui_unicode_get_sprite_index(char* text) {
u32 djui_unicode_get_sprite_index(const char* text) {
// check for ASCI
if ((u8)*text < 128) {
// make sure it's in the valid range
@ -298,7 +298,7 @@ u32 djui_unicode_get_sprite_index(char* text) {
return (u8)'?' - SPRITE_INDEX_START_CHAR;
}
f32 djui_unicode_get_sprite_width(char* text, const f32 font_widths[], f32 unicodeScale) {
f32 djui_unicode_get_sprite_width(const char* text, const f32 font_widths[], f32 unicodeScale) {
if (!text) { return 0; }
// check for ASCII
@ -358,7 +358,7 @@ size_t djui_unicode_len(char* text) {
return len;
}
bool djui_unicode_valid_char(char* text) {
bool djui_unicode_valid_char(const char* text) {
if ((u8)*text < 128) {
return ((u8)*text >= ' ');
}
@ -397,7 +397,7 @@ void djui_unicode_cleanup_end(char* text) {
}
}
char djui_unicode_get_base_char(char* text) {
char djui_unicode_get_base_char(const char* text) {
if ((u8)*text < ' ') { return '?'; }
if ((u8)*text < 128) { return *text; }
if (!sCharMap) { return '?'; }
@ -406,7 +406,7 @@ char djui_unicode_get_base_char(char* text) {
return (glyph == NULL) ? '?' : glyph->base;
}
void djui_unicode_get_char(char* text, char* output) {
void djui_unicode_get_char(const char* text, char* output) {
s32 bytes = count_bytes_for_char(text);
while (bytes-- > 0) {
*output = *text;

View file

@ -4,12 +4,12 @@
#include <stdbool.h>
void djui_unicode_init(void);
u32 djui_unicode_get_sprite_index(char* text);
f32 djui_unicode_get_sprite_width(char* text, const f32 font_widths[], f32 unicodeScale);
u32 djui_unicode_get_sprite_index(const char* text);
f32 djui_unicode_get_sprite_width(const char* text, const f32 font_widths[], f32 unicodeScale);
char* djui_unicode_next_char(char* text);
char* djui_unicode_at_index(char* text, s32 index);
size_t djui_unicode_len(char* text);
bool djui_unicode_valid_char(char* text);
bool djui_unicode_valid_char(const char* text);
void djui_unicode_cleanup_end(char* text);
char djui_unicode_get_base_char(char* text);
void djui_unicode_get_char(char* text, char* output);
char djui_unicode_get_base_char(const char* text);
void djui_unicode_get_char(const char* text, char* output);

View file

@ -1228,16 +1228,6 @@ static struct LuaObjectField sGraphNodeTranslationRotationFields[LUA_GRAPH_NODE_
{ "translation", LVT_COBJECT, offsetof(struct GraphNodeTranslationRotation, translation), true, LOT_VEC3S, 1, sizeof(Vec3s) },
};
#define LUA_HUD_UTILS_ROTATION_FIELD_COUNT 6
static struct LuaObjectField sHudUtilsRotationFields[LUA_HUD_UTILS_ROTATION_FIELD_COUNT] = {
{ "pivotX", LVT_F32, offsetof(struct HudUtilsRotation, pivotX), false, LOT_NONE, 1, sizeof(f32) },
{ "pivotY", LVT_F32, offsetof(struct HudUtilsRotation, pivotY), false, LOT_NONE, 1, sizeof(f32) },
{ "prevPivotX", LVT_F32, offsetof(struct HudUtilsRotation, prevPivotX), false, LOT_NONE, 1, sizeof(f32) },
{ "prevPivotY", LVT_F32, offsetof(struct HudUtilsRotation, prevPivotY), false, LOT_NONE, 1, sizeof(f32) },
{ "rotation", LVT_F32, offsetof(struct HudUtilsRotation, rotation), false, LOT_NONE, 1, sizeof(f32) },
{ "rotationDiff", LVT_F32, offsetof(struct HudUtilsRotation, rotationDiff), false, LOT_NONE, 1, sizeof(f32) },
};
#define LUA_INSTANT_WARP_FIELD_COUNT 3
static struct LuaObjectField sInstantWarpFields[LUA_INSTANT_WARP_FIELD_COUNT] = {
{ "area", LVT_U8, offsetof(struct InstantWarp, area), false, LOT_NONE, 1, sizeof(u8) },
@ -1484,7 +1474,7 @@ static struct LuaObjectField sModFields[LUA_MOD_FIELD_COUNT] = {
{ "incompatible", LVT_STRING_P, offsetof(struct Mod, incompatible), true, LOT_NONE, 1, sizeof(char*) },
{ "index", LVT_S32, offsetof(struct Mod, index), true, LOT_NONE, 1, sizeof(s32) },
{ "isDirectory", LVT_BOOL, offsetof(struct Mod, isDirectory), true, LOT_NONE, 1, sizeof(bool) },
{ "name", LVT_STRING_P, offsetof(struct Mod, name), true, LOT_NONE, 1, sizeof(char*) },
{ "name", LVT_STRING, offsetof(struct Mod, name), true, LOT_NONE, 1, sizeof(char) },
{ "pausable", LVT_BOOL, offsetof(struct Mod, pausable), true, LOT_NONE, 1, sizeof(bool) },
{ "relativePath", LVT_STRING, offsetof(struct Mod, relativePath), true, LOT_NONE, 1, sizeof(char) },
{ "renderBehindHud", LVT_BOOL, offsetof(struct Mod, renderBehindHud), true, LOT_NONE, 1, sizeof(bool) },
@ -2734,7 +2724,6 @@ struct LuaObjectTable sLuaObjectAutogenTable[LOT_AUTOGEN_MAX - LOT_AUTOGEN_MIN]
{ LOT_GRAPHNODESWITCHCASE, sGraphNodeSwitchCaseFields, LUA_GRAPH_NODE_SWITCH_CASE_FIELD_COUNT },
{ LOT_GRAPHNODETRANSLATION, sGraphNodeTranslationFields, LUA_GRAPH_NODE_TRANSLATION_FIELD_COUNT },
{ LOT_GRAPHNODETRANSLATIONROTATION, sGraphNodeTranslationRotationFields, LUA_GRAPH_NODE_TRANSLATION_ROTATION_FIELD_COUNT },
{ LOT_HUDUTILSROTATION, sHudUtilsRotationFields, LUA_HUD_UTILS_ROTATION_FIELD_COUNT },
{ LOT_INSTANTWARP, sInstantWarpFields, LUA_INSTANT_WARP_FIELD_COUNT },
{ LOT_LAKITUSTATE, sLakituStateFields, LUA_LAKITU_STATE_FIELD_COUNT },
{ LOT_LEVELVALUES, sLevelValuesFields, LUA_LEVEL_VALUES_FIELD_COUNT },
@ -2840,7 +2829,6 @@ const char *sLuaLotNames[] = {
[LOT_GRAPHNODESWITCHCASE] = "GraphNodeSwitchCase",
[LOT_GRAPHNODETRANSLATION] = "GraphNodeTranslation",
[LOT_GRAPHNODETRANSLATIONROTATION] = "GraphNodeTranslationRotation",
[LOT_HUDUTILSROTATION] = "HudUtilsRotation",
[LOT_INSTANTWARP] = "InstantWarp",
[LOT_LAKITUSTATE] = "LakituState",
[LOT_LEVELVALUES] = "LevelValues",

View file

@ -74,7 +74,6 @@ enum LuaObjectAutogenType {
LOT_GRAPHNODESWITCHCASE,
LOT_GRAPHNODETRANSLATION,
LOT_GRAPHNODETRANSLATIONROTATION,
LOT_HUDUTILSROTATION,
LOT_INSTANTWARP,
LOT_LAKITUSTATE,
LOT_LEVELVALUES,

View file

@ -1488,12 +1488,25 @@ char gSmluaConstants[] = ""
"CONSOLE_MESSAGE_INFO=0\n"
"CONSOLE_MESSAGE_WARNING=1\n"
"CONSOLE_MESSAGE_ERROR=2\n"
"ROTATION_PIVOT_X_LEFT=0.0\n"
"ROTATION_PIVOT_X_CENTER=0.5\n"
"ROTATION_PIVOT_X_RIGHT=1.0\n"
"ROTATION_PIVOT_Y_TOP=0.0\n"
"ROTATION_PIVOT_Y_CENTER=0.5\n"
"ROTATION_PIVOT_Y_BOTTOM=1.0\n"
"TEXT_HALIGN_LEFT=0.0\n"
"TEXT_HALIGN_CENTER=0.5\n"
"TEXT_HALIGN_RIGHT=1.0\n"
"TEXT_VALIGN_TOP=0.0\n"
"TEXT_VALIGN_CENTER=0.5\n"
"TEXT_VALIGN_BOTTOM=1.0\n"
"RESOLUTION_DJUI=0\n"
"RESOLUTION_N64=1\n"
"RESOLUTION_COUNT=2\n"
"FILTER_NEAREST=0\n"
"FILTER_LINEAR=1\n"
"FILTER_COUNT=2\n"
"FONT_LEGACY=-1\n"
"FONT_NORMAL=0\n"
"FONT_MENU=1\n"
"FONT_HUD=2\n"

View file

@ -945,7 +945,7 @@ int smlua_func_get_uncolored_string(lua_State* L) {
const char *str = smlua_to_string(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("get_uncolored_string: Failed to convert parameter 1"); return 0; }
char *strNoColor = str_remove_color_codes(str);
char *strNoColor = djui_text_get_uncolored_string(NULL, strlen(str) + 1, str);
lua_pushstring(L, strNoColor);
free(strNoColor);

View file

@ -12318,7 +12318,7 @@ int smlua_func_djui_hud_reset_color(UNUSED lua_State* L) {
return 1;
}
int smlua_func_djui_hud_get_rotation(UNUSED lua_State* L) {
int smlua_func_djui_hud_get_rotation(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
@ -12328,9 +12328,17 @@ int smlua_func_djui_hud_get_rotation(UNUSED lua_State* L) {
}
smlua_push_object(L, LOT_HUDUTILSROTATION, djui_hud_get_rotation(), NULL);
s16 rotation;
f32 pivotX;
f32 pivotY;
return 1;
djui_hud_get_rotation(&rotation, &pivotX, &pivotY);
lua_pushinteger(L, rotation);
lua_pushnumber(L, pivotX);
lua_pushnumber(L, pivotY);
return 3;
}
int smlua_func_djui_hud_set_rotation(lua_State* L) {
@ -12363,13 +12371,13 @@ int smlua_func_djui_hud_set_rotation_interpolated(lua_State* L) {
return 0;
}
s32 prevRotation = smlua_to_integer(L, 1);
s16 prevRotation = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "djui_hud_set_rotation_interpolated"); return 0; }
f32 prevPivotX = smlua_to_number(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "djui_hud_set_rotation_interpolated"); return 0; }
f32 prevPivotY = smlua_to_number(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "djui_hud_set_rotation_interpolated"); return 0; }
s32 rotation = smlua_to_integer(L, 4);
s16 rotation = smlua_to_integer(L, 4);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 4, "djui_hud_set_rotation_interpolated"); return 0; }
f32 pivotX = smlua_to_number(L, 5);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 5, "djui_hud_set_rotation_interpolated"); return 0; }
@ -12381,6 +12389,69 @@ int smlua_func_djui_hud_set_rotation_interpolated(lua_State* L) {
return 1;
}
int smlua_func_djui_hud_get_text_alignment(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 0) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "djui_hud_get_text_alignment", 0, top);
return 0;
}
f32 textHAlign;
f32 textVAlign;
djui_hud_get_text_alignment(&textHAlign, &textVAlign);
lua_pushnumber(L, textHAlign);
lua_pushnumber(L, textVAlign);
return 2;
}
int smlua_func_djui_hud_set_text_alignment(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "djui_hud_set_text_alignment", 2, top);
return 0;
}
f32 textHAlign = smlua_to_number(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "djui_hud_set_text_alignment"); return 0; }
f32 textVAlign = smlua_to_number(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "djui_hud_set_text_alignment"); return 0; }
djui_hud_set_text_alignment(textHAlign, textVAlign);
return 1;
}
int smlua_func_djui_hud_set_text_alignment_interpolated(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 4) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "djui_hud_set_text_alignment_interpolated", 4, top);
return 0;
}
f32 prevTextHAlign = smlua_to_number(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "djui_hud_set_text_alignment_interpolated"); return 0; }
f32 prevTextVAlign = smlua_to_number(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "djui_hud_set_text_alignment_interpolated"); return 0; }
f32 textHAlign = smlua_to_number(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "djui_hud_set_text_alignment_interpolated"); return 0; }
f32 textVAlign = smlua_to_number(L, 4);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 4, "djui_hud_set_text_alignment_interpolated"); return 0; }
djui_hud_set_text_alignment_interpolated(prevTextHAlign, prevTextVAlign, textHAlign, textVAlign);
return 1;
}
int smlua_func_djui_hud_get_screen_width(UNUSED lua_State* L) {
if (L == NULL) { return 0; }
@ -37389,6 +37460,9 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "djui_hud_get_rotation", smlua_func_djui_hud_get_rotation);
smlua_bind_function(L, "djui_hud_set_rotation", smlua_func_djui_hud_set_rotation);
smlua_bind_function(L, "djui_hud_set_rotation_interpolated", smlua_func_djui_hud_set_rotation_interpolated);
smlua_bind_function(L, "djui_hud_get_text_alignment", smlua_func_djui_hud_get_text_alignment);
smlua_bind_function(L, "djui_hud_set_text_alignment", smlua_func_djui_hud_set_text_alignment);
smlua_bind_function(L, "djui_hud_set_text_alignment_interpolated", smlua_func_djui_hud_set_text_alignment_interpolated);
smlua_bind_function(L, "djui_hud_get_screen_width", smlua_func_djui_hud_get_screen_width);
smlua_bind_function(L, "djui_hud_get_screen_height", smlua_func_djui_hud_get_screen_height);
smlua_bind_function(L, "djui_hud_get_mouse_x", smlua_func_djui_hud_get_mouse_x);

View file

@ -952,7 +952,7 @@ char** smlua_get_chat_subcommands_list(const char* maincommand) {
for (s32 i = 0; i < sHookedChatCommandsCount; i++) {
struct LuaHookedChatCommand* hook = &sHookedChatCommands[i];
if (strcmp(hook->command, maincommand) == 0) {
char* noColorsDesc = str_remove_color_codes(hook->description);
char* noColorsDesc = djui_text_get_uncolored_string(NULL, strlen(hook->description) + 1, hook->description);
char* startSubcommands = strstr(noColorsDesc, "[");
char* endSubcommands = strstr(noColorsDesc, "]");

View file

@ -197,11 +197,6 @@ void mod_clear(struct Mod* mod) {
}
}
if (mod->name != NULL) {
free(mod->name);
mod->name = NULL;
}
if (mod->incompatible != NULL) {
free(mod->incompatible);
mod->incompatible = NULL;
@ -449,7 +444,7 @@ static void mod_extract_fields(struct Mod* mod) {
fseek(f, 0, SEEK_SET);
// default to null
mod->name = NULL;
mod->name[0] = 0;
mod->incompatible = NULL;
mod->category = NULL;
mod->description = NULL;
@ -457,7 +452,7 @@ static void mod_extract_fields(struct Mod* mod) {
mod->ignoreScriptWarnings = false;
// read line-by-line
#define BUFFER_SIZE MAX(MAX(MOD_NAME_MAX_LENGTH, MOD_INCOMPATIBLE_MAX_LENGTH), MOD_DESCRIPTION_MAX_LENGTH)
#define BUFFER_SIZE MAX(MAX(MOD_NAME_SIZE, MOD_INCOMPATIBLE_SIZE), MOD_DESCRIPTION_SIZE)
char buffer[BUFFER_SIZE] = { 0 };
while (!feof(f)) {
file_get_line(buffer, BUFFER_SIZE, f);
@ -470,24 +465,23 @@ static void mod_extract_fields(struct Mod* mod) {
// extract the field
char* extracted = NULL;
if (mod->name == NULL && (extracted = extract_lua_field("-- name:", buffer))) {
mod->name = calloc(MOD_NAME_MAX_LENGTH + 1, sizeof(char));
if (snprintf(mod->name, MOD_NAME_MAX_LENGTH, "%s", extracted) < 0) {
if (!mod->name[0] && (extracted = extract_lua_field("-- name:", buffer))) {
if (snprintf(mod->name, MOD_NAME_SIZE, "%s", extracted) < 0) {
LOG_INFO("Truncated mod name field '%s'", mod->name);
}
} else if (mod->incompatible == NULL && (extracted = extract_lua_field("-- incompatible:", buffer))) {
mod->incompatible = calloc(MOD_INCOMPATIBLE_MAX_LENGTH + 1, sizeof(char));
if (snprintf(mod->incompatible, MOD_INCOMPATIBLE_MAX_LENGTH, "%s", extracted) < 0) {
mod->incompatible = calloc(MOD_INCOMPATIBLE_SIZE, sizeof(char));
if (snprintf(mod->incompatible, MOD_INCOMPATIBLE_SIZE, "%s", extracted) < 0) {
LOG_INFO("Truncated mod incompatible field '%s'", mod->incompatible);
}
} else if (mod->category == NULL && (extracted = extract_lua_field("-- category:", buffer))) {
mod->category = calloc(MOD_CATEGORY_MAX_LENGTH + 1, sizeof(char));
if (snprintf(mod->category, MOD_CATEGORY_MAX_LENGTH, "%s", extracted) < 0) {
mod->category = calloc(MOD_CATEGORY_SIZE, sizeof(char));
if (snprintf(mod->category, MOD_CATEGORY_SIZE, "%s", extracted) < 0) {
LOG_INFO("Truncated mod category field '%s'", mod->category);
}
} else if (mod->description == NULL && (extracted = extract_lua_field("-- description:", buffer))) {
mod->description = calloc(MOD_DESCRIPTION_MAX_LENGTH + 1, sizeof(char));
if (snprintf(mod->description, MOD_DESCRIPTION_MAX_LENGTH, "%s", extracted) < 0) {
mod->description = calloc(MOD_DESCRIPTION_SIZE, sizeof(char));
if (snprintf(mod->description, MOD_DESCRIPTION_SIZE, "%s", extracted) < 0) {
LOG_INFO("Truncated mod description field '%s'", mod->description);
}
} else if ((extracted = extract_lua_field("-- pausable:", buffer))) {
@ -632,17 +626,19 @@ bool mod_load(struct Mods* mods, char* basePath, char* modName) {
mod_extract_fields(mod);
// set name
if (mod->name == NULL) {
mod->name = strdup(modName);
if (!mod->name[0]) {
if (snprintf(mod->name, MOD_NAME_SIZE, "%s", modName) < 0) {
LOG_INFO("Truncated mod name field '%s'", mod->name);
}
}
// set category
if (mod->category == NULL) {
char *modNameNoColor = str_remove_color_codes(mod->name);
char modNameNoColor[MOD_NAME_SIZE];
djui_text_get_uncolored_string(modNameNoColor, MOD_NAME_SIZE, mod->name);
if (strstr(modNameNoColor, "[CS]") == modNameNoColor) {
mod->category = strdup("cs");
}
free(modNameNoColor);
}
// print

View file

@ -10,6 +10,11 @@
#define MOD_CATEGORY_MAX_LENGTH 64
#define MOD_DESCRIPTION_MAX_LENGTH 800
#define MOD_NAME_SIZE (MOD_NAME_MAX_LENGTH + 1)
#define MOD_INCOMPATIBLE_SIZE (MOD_INCOMPATIBLE_MAX_LENGTH + 1)
#define MOD_CATEGORY_SIZE (MOD_CATEGORY_MAX_LENGTH + 1)
#define MOD_DESCRIPTION_SIZE (MOD_DESCRIPTION_MAX_LENGTH + 1)
struct Mods;
struct ModFile {
@ -25,7 +30,7 @@ struct ModFile {
};
struct Mod {
char* name;
char name[MOD_NAME_SIZE];
char* incompatible;
char* category;
char* description;

View file

@ -184,19 +184,20 @@ static void mods_sort(struct Mods* mods) {
}
// By default, this is the alphabetical order on name
char modNameNoColor_i[MOD_NAME_SIZE];
char modNameNoColor_j[MOD_NAME_SIZE];
for (s32 i = 1; i < mods->entryCount; ++i) {
struct Mod* mod = mods->entries[i];
struct Mod* mod_i = mods->entries[i];
djui_text_get_uncolored_string(modNameNoColor_i, MOD_NAME_SIZE, mod_i->name);
for (s32 j = 0; j < i; ++j) {
struct Mod* mod2 = mods->entries[j];
char* name = str_remove_color_codes(mod->name);
char* name2 = str_remove_color_codes(mod2->name);
if (strcmp(name, name2) < 0) {
mods->entries[i] = mod2;
mods->entries[j] = mod;
mod = mods->entries[i];
struct Mod* mod_j = mods->entries[j];
djui_text_get_uncolored_string(modNameNoColor_j, MOD_NAME_SIZE, mod_j->name);
if (strcmp(modNameNoColor_i, modNameNoColor_j) < 0) {
mods->entries[i] = mod_j;
mods->entries[j] = mod_i;
mod_i = mod_j;
memcpy(modNameNoColor_i, modNameNoColor_j, MOD_NAME_SIZE * sizeof(char));
}
free(name);
free(name2);
}
}
}

View file

@ -318,13 +318,13 @@ after_filled:;
// Cache any mod that doesn't have "(wip)" or "[wip]" in its name (case-insensitive)
static bool should_cache_mod(struct Mod *mod) {
char *modName = sys_strdup(mod->name);
sys_strlwr(modName);
char modNameLowercase[MOD_NAME_SIZE];
memcpy(modNameLowercase, mod->name, MOD_NAME_SIZE * sizeof(char));
sys_strlwr(modNameLowercase);
bool shouldCache = (
!strstr(modName, "(wip)") &&
!strstr(modName, "[wip]")
!strstr(modNameLowercase, "(wip)") &&
!strstr(modNameLowercase, "[wip]")
);
free(modName);
return shouldCache;
}

View file

@ -197,9 +197,8 @@ void network_receive_mod_list_entry(struct Packet* p) {
}
// get name
char name[MOD_NAME_MAX_LENGTH + 1] = { 0 };
packet_read(p, name, nameLength * sizeof(u8));
mod->name = strdup(name);
packet_read(p, mod->name, nameLength * sizeof(u8));
mod->name[nameLength] = 0;
// get incompatible length
u16 incompatibleLength = 0;
@ -211,7 +210,7 @@ void network_receive_mod_list_entry(struct Packet* p) {
// get incompatible
if (incompatibleLength > 0) {
char incompatible[MOD_INCOMPATIBLE_MAX_LENGTH + 1] = { 0 };
char incompatible[MOD_INCOMPATIBLE_SIZE] = { 0 };
packet_read(p, incompatible, incompatibleLength * sizeof(u8));
mod->incompatible = strdup(incompatible);
} else {

View file

@ -594,18 +594,3 @@ void str_seperator_concat(char *output_buffer, int buffer_size, char** strings,
}
}
}
char *str_remove_color_codes(const char *str) {
char *output = strdup(str);
char *startColor;
while ((startColor = strstr(output, "\\#"))) {
char *endColor = strchr(startColor + 2, '\\');
if (endColor) {
memmove(startColor, endColor + 1, strlen(endColor + 1) + 1);
} else {
*startColor = 0;
break;
}
}
return output;
}

View file

@ -37,6 +37,5 @@ void delta_interpolate_mtx(Mtx* out, Mtx* a, Mtx* b, f32 delta);
void detect_and_skip_mtx_interpolation(Mtx** mtxPrev, Mtx** mtx);
void str_seperator_concat(char *output_buffer, int buffer_size, char** strings, int num_strings, char* seperator);
char *str_remove_color_codes(const char *str);
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 39 KiB