mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-22 03:55:11 +00:00
Initial DJUI commit
The birth of a custom user interface system. Has the ability to draw things to the screen at native resolution regardless of window size. Components can be nested within one another to an arbitrary depth. Text rendering is completely rewritten. Text and images can be clipped by their parent container.
This commit is contained in:
parent
52d07c4dde
commit
038c1135b3
27 changed files with 1370 additions and 21 deletions
2
Makefile
2
Makefile
|
@ -316,7 +316,7 @@ LEVEL_DIRS := $(patsubst levels/%,%,$(dir $(wildcard levels/*/header.h)))
|
||||||
|
|
||||||
# Hi, I'm a PC
|
# Hi, I'm a PC
|
||||||
SRC_DIRS := src src/engine src/game src/audio src/menu src/buffers actors levels bin data assets src/pc src/pc/gfx src/pc/audio src/pc/controller src/pc/fs src/pc/fs/packtypes
|
SRC_DIRS := src src/engine src/game src/audio src/menu src/buffers actors levels bin data assets src/pc src/pc/gfx src/pc/audio src/pc/controller src/pc/fs src/pc/fs/packtypes
|
||||||
SRC_DIRS += src/pc/network src/pc/network/packets src/pc/network/socket src/pc/utils
|
SRC_DIRS += src/pc/network src/pc/network/packets src/pc/network/socket src/pc/utils src/pc/djui
|
||||||
ASM_DIRS :=
|
ASM_DIRS :=
|
||||||
|
|
||||||
#ifeq ($(DISCORDRPC),1)
|
#ifeq ($(DISCORDRPC),1)
|
||||||
|
|
|
@ -3940,6 +3940,14 @@
|
||||||
<ClCompile Include="..\src\pc\controller\controller_recorded_tas.c" />
|
<ClCompile Include="..\src\pc\controller\controller_recorded_tas.c" />
|
||||||
<ClCompile Include="..\src\pc\controller\controller_sdl.c" />
|
<ClCompile Include="..\src\pc\controller\controller_sdl.c" />
|
||||||
<ClCompile Include="..\src\pc\discord\discordrpc.c" />
|
<ClCompile Include="..\src\pc\discord\discordrpc.c" />
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui.c" />
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_base.c" />
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_button.c" />
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_gfx.c" />
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_image.c" />
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_rect.c" />
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_root.c" />
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_text.c" />
|
||||||
<ClCompile Include="..\src\pc\fs\dirtree.c" />
|
<ClCompile Include="..\src\pc\fs\dirtree.c" />
|
||||||
<ClCompile Include="..\src\pc\fs\fs.c" />
|
<ClCompile Include="..\src\pc\fs\fs.c" />
|
||||||
<ClCompile Include="..\src\pc\fs\fs_packtype_dir.c" />
|
<ClCompile Include="..\src\pc\fs\fs_packtype_dir.c" />
|
||||||
|
@ -4351,6 +4359,16 @@
|
||||||
<ClInclude Include="..\src\menu\custom_menu_system.h" />
|
<ClInclude Include="..\src\menu\custom_menu_system.h" />
|
||||||
<ClInclude Include="..\src\pc\controller\controller_keyboard_debug.h" />
|
<ClInclude Include="..\src\pc\controller\controller_keyboard_debug.h" />
|
||||||
<ClInclude Include="..\src\pc\debuglog.h" />
|
<ClInclude Include="..\src\pc\debuglog.h" />
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui.h" />
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_base.h" />
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_button.h" />
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_gbi.h" />
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_gfx.h" />
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_image.h" />
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_rect.h" />
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_root.h" />
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_text.h" />
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_types.h" />
|
||||||
<ClInclude Include="..\src\pc\network\branch.h" />
|
<ClInclude Include="..\src\pc\network\branch.h" />
|
||||||
<ClInclude Include="..\src\pc\network\discord\activity.h" />
|
<ClInclude Include="..\src\pc\network\discord\activity.h" />
|
||||||
<ClInclude Include="..\src\pc\network\discord\discord.h" />
|
<ClInclude Include="..\src\pc\network\discord\discord.h" />
|
||||||
|
|
|
@ -3445,6 +3445,12 @@
|
||||||
<Filter Include="Source Files\src\pc\network\packets\reservation-area">
|
<Filter Include="Source Files\src\pc\network\packets\reservation-area">
|
||||||
<UniqueIdentifier>{9ddfaa87-399e-4f61-aae3-f91af79e14cc}</UniqueIdentifier>
|
<UniqueIdentifier>{9ddfaa87-399e-4f61-aae3-f91af79e14cc}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Source Files\src\pc\djui">
|
||||||
|
<UniqueIdentifier>{0e1e4798-796e-4801-be6e-69d0c3b05ad7}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\src\pc\djui\components">
|
||||||
|
<UniqueIdentifier>{471ac819-ed6b-4a33-8952-50a8e0d2d839}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\actors\amp\anims\anim_0800401C.inc.c">
|
<ClCompile Include="..\actors\amp\anims\anim_0800401C.inc.c">
|
||||||
|
@ -15144,6 +15150,30 @@
|
||||||
<ClCompile Include="..\src\pc\network\packets\packet_save_set_flag.c">
|
<ClCompile Include="..\src\pc\network\packets\packet_save_set_flag.c">
|
||||||
<Filter>Source Files\src\pc\network\packets</Filter>
|
<Filter>Source Files\src\pc\network\packets</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui.c">
|
||||||
|
<Filter>Source Files\src\pc\djui</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_gfx.c">
|
||||||
|
<Filter>Source Files\src\pc\djui</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_image.c">
|
||||||
|
<Filter>Source Files\src\pc\djui\components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_rect.c">
|
||||||
|
<Filter>Source Files\src\pc\djui\components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_text.c">
|
||||||
|
<Filter>Source Files\src\pc\djui\components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_base.c">
|
||||||
|
<Filter>Source Files\src\pc\djui\components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_root.c">
|
||||||
|
<Filter>Source Files\src\pc\djui\components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\pc\djui\djui_button.c">
|
||||||
|
<Filter>Source Files\src\pc\djui\components</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\actors\common0.h">
|
<ClCompile Include="..\actors\common0.h">
|
||||||
|
@ -16117,5 +16147,35 @@
|
||||||
<ClInclude Include="..\src\pc\network\reservation_area.h">
|
<ClInclude Include="..\src\pc\network\reservation_area.h">
|
||||||
<Filter>Header Files\src\pc\network</Filter>
|
<Filter>Header Files\src\pc\network</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui.h">
|
||||||
|
<Filter>Source Files\src\pc\djui</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_gfx.h">
|
||||||
|
<Filter>Source Files\src\pc\djui</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_types.h">
|
||||||
|
<Filter>Source Files\src\pc\djui</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_gbi.h">
|
||||||
|
<Filter>Source Files\src\pc\djui</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_image.h">
|
||||||
|
<Filter>Source Files\src\pc\djui\components</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_rect.h">
|
||||||
|
<Filter>Source Files\src\pc\djui\components</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_text.h">
|
||||||
|
<Filter>Source Files\src\pc\djui\components</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_base.h">
|
||||||
|
<Filter>Source Files\src\pc\djui\components</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_root.h">
|
||||||
|
<Filter>Source Files\src\pc\djui\components</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\pc\djui\djui_button.h">
|
||||||
|
<Filter>Source Files\src\pc\djui\components</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -1,2 +1,4 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here' -ex 'run' -ex 'quit'
|
#make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here' -ex 'run' -ex 'quit'
|
||||||
|
#make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_server.txt' -ex 'quit'
|
||||||
|
make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && ./build/us_pc/sm64.us.f3dex2e.exe --server 27015 --configfile sm64config_server.txt
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here'
|
make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here'
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define _GBI_H_
|
#define _GBI_H_
|
||||||
|
|
||||||
#include <PR/ultratypes.h>
|
#include <PR/ultratypes.h>
|
||||||
|
#include "src/pc/djui/djui_gbi.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To use the F3DEX ucodes, define F3DEX_GBI before include this file.
|
* To use the F3DEX ucodes, define F3DEX_GBI before include this file.
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "macros.h"
|
#include "macros.h"
|
||||||
#include "pc/cheats.h"
|
#include "pc/cheats.h"
|
||||||
#include "pc/network/network.h"
|
#include "pc/network/network.h"
|
||||||
|
#include "pc/djui/djui.h"
|
||||||
#ifdef BETTERCAMERA
|
#ifdef BETTERCAMERA
|
||||||
#include "bettercamera.h"
|
#include "bettercamera.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -414,26 +415,31 @@ void render_multi_text_string(s16 *xPos, s16 *yPos, s8 multiTextID)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
u8 str_ascii_char_to_dialog(char c) {
|
||||||
|
switch (c) {
|
||||||
|
case '\'': return 0x3E;
|
||||||
|
case '.': return 0x3F;
|
||||||
|
case ',': return DIALOG_CHAR_COMMA;
|
||||||
|
case '-': return 0x9F;
|
||||||
|
case '(': return 0xE1;
|
||||||
|
case ')': return 0xE3;
|
||||||
|
case '&': return 0xE5;
|
||||||
|
case '!': return 0xF2;
|
||||||
|
case '%': return 0xF3;
|
||||||
|
case '?': return 0xF4;
|
||||||
|
case '"': return 0xF6; // 0xF5 is opening quote
|
||||||
|
case '~': return 0xF7;
|
||||||
|
case '*': return 0xFB;
|
||||||
|
case ' ': return DIALOG_CHAR_SPACE;
|
||||||
|
case '\n': return DIALOG_CHAR_NEWLINE;
|
||||||
|
case '\0': return DIALOG_CHAR_TERMINATOR;
|
||||||
|
default: return ((u8)c < 0xF0) ? ASCII_TO_DIALOG(c) : c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void str_ascii_to_dialog(const char* string, u8* dialog, u16 length) {
|
void str_ascii_to_dialog(const char* string, u8* dialog, u16 length) {
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
switch (string[i]) {
|
dialog[i] = str_ascii_char_to_dialog(string[i]);
|
||||||
case '\'': dialog[i] = 0x3E; break;
|
|
||||||
case '.': dialog[i] = 0x3F; break;
|
|
||||||
case ',': dialog[i] = DIALOG_CHAR_COMMA; break;
|
|
||||||
case '-': dialog[i] = 0x9F; break;
|
|
||||||
case '(': dialog[i] = 0xE1; break;
|
|
||||||
case ')': dialog[i] = 0xE3; break;
|
|
||||||
case '&': dialog[i] = 0xE5; break;
|
|
||||||
case '!': dialog[i] = 0xF2; break;
|
|
||||||
case '%': dialog[i] = 0xF3; break;
|
|
||||||
case '?': dialog[i] = 0xF4; break;
|
|
||||||
case '"': dialog[i] = 0xF6; break; // 0xF5 is opening quote
|
|
||||||
case '~': dialog[i] = 0xF7; break;
|
|
||||||
case '*': dialog[i] = 0xFB; break;
|
|
||||||
case ' ': dialog[i] = DIALOG_CHAR_SPACE; break;
|
|
||||||
case '\n': dialog[i] = DIALOG_CHAR_NEWLINE; break;
|
|
||||||
default: dialog[i] = ((u8)string[i] < 0xF0) ? ASCII_TO_DIALOG(string[i]) : string[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dialog[length] = DIALOG_CHAR_TERMINATOR;
|
dialog[length] = DIALOG_CHAR_TERMINATOR;
|
||||||
}
|
}
|
||||||
|
@ -3196,6 +3202,7 @@ s16 render_menus_and_dialogs() {
|
||||||
create_dl_ortho_matrix();
|
create_dl_ortho_matrix();
|
||||||
|
|
||||||
render_chat();
|
render_chat();
|
||||||
|
djui_render();
|
||||||
|
|
||||||
if (gMenuMode != -1) {
|
if (gMenuMode != -1) {
|
||||||
switch (gMenuMode) {
|
switch (gMenuMode) {
|
||||||
|
|
|
@ -30,6 +30,10 @@
|
||||||
#define RENDER_COURSE_DONE_SCREEN 2
|
#define RENDER_COURSE_DONE_SCREEN 2
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(VERSION_JP) && !defined(VERSION_SH)
|
||||||
|
extern u8 gDialogCharWidths[];
|
||||||
|
#endif
|
||||||
|
|
||||||
extern s8 gDialogCourseActNum;
|
extern s8 gDialogCourseActNum;
|
||||||
extern s8 gHudFlash;
|
extern s8 gHudFlash;
|
||||||
|
|
||||||
|
@ -117,6 +121,7 @@ void create_dl_identity_matrix(void);
|
||||||
void create_dl_translation_matrix(s8 pushOp, f32 x, f32 y, f32 z);
|
void create_dl_translation_matrix(s8 pushOp, f32 x, f32 y, f32 z);
|
||||||
void create_dl_ortho_matrix(void);
|
void create_dl_ortho_matrix(void);
|
||||||
void render_generic_char(u8 c);
|
void render_generic_char(u8 c);
|
||||||
|
u8 str_ascii_char_to_dialog(char c);
|
||||||
void str_ascii_to_dialog(const char* string, u8* dialog, u16 length);
|
void str_ascii_to_dialog(const char* string, u8* dialog, u16 length);
|
||||||
f32 get_generic_dialog_width(u8* dialog);
|
f32 get_generic_dialog_width(u8* dialog);
|
||||||
f32 get_generic_ascii_string_width(const char* ascii);
|
f32 get_generic_ascii_string_width(const char* ascii);
|
||||||
|
|
89
src/pc/djui/djui.c
Normal file
89
src/pc/djui/djui.c
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#include "djui.h"
|
||||||
|
|
||||||
|
struct DjuiRoot* gDjuiRoot = NULL;
|
||||||
|
|
||||||
|
ALIGNED8 static const u8 texture32x32[] = {
|
||||||
|
#include "actors/bubble/mr_i_bubble.rgba16.inc.c"
|
||||||
|
};
|
||||||
|
ALIGNED8 static const u8 texture16x16[] = {
|
||||||
|
#include "textures/segment2/custom_luigi_head.rgba16.inc.c"
|
||||||
|
};
|
||||||
|
|
||||||
|
void djui_render(void) {
|
||||||
|
static struct DjuiRect* sDjuiRect = NULL;
|
||||||
|
static struct DjuiRect* sDjuiRect2 = NULL;
|
||||||
|
static struct DjuiText* sDjuiText = NULL;
|
||||||
|
static struct DjuiImage* sDjuiImage = NULL;
|
||||||
|
static struct DjuiButton* sDjuiButton = NULL;
|
||||||
|
|
||||||
|
if (gDjuiRoot == NULL) {
|
||||||
|
gDjuiRoot = djui_root_create();
|
||||||
|
|
||||||
|
struct DjuiRect* imageContainer = djui_rect_create(&gDjuiRoot->base);
|
||||||
|
imageContainer->base.x = 32;
|
||||||
|
imageContainer->base.y = 32;
|
||||||
|
imageContainer->base.width = 64;
|
||||||
|
imageContainer->base.height = 64;
|
||||||
|
|
||||||
|
sDjuiImage = djui_image_create(&imageContainer->base, texture16x16, 16, 16);
|
||||||
|
sDjuiImage->base.x = 16;
|
||||||
|
sDjuiImage->base.y = 16;
|
||||||
|
sDjuiImage->base.width = 32;
|
||||||
|
sDjuiImage->base.height = 32;
|
||||||
|
sDjuiImage->base.color.r = 255;
|
||||||
|
|
||||||
|
//////////////
|
||||||
|
|
||||||
|
sDjuiRect = djui_rect_create(&gDjuiRoot->base);
|
||||||
|
sDjuiRect->base.x = 64;
|
||||||
|
sDjuiRect->base.y = 64;
|
||||||
|
sDjuiRect->base.width = 188;
|
||||||
|
sDjuiRect->base.height = 64;
|
||||||
|
sDjuiRect->base.color.a = 200;
|
||||||
|
sDjuiRect->base.hAlign = DJUI_HALIGN_LEFT;
|
||||||
|
sDjuiRect->base.vAlign = DJUI_VALIGN_BOTTOM;
|
||||||
|
|
||||||
|
sDjuiRect2 = djui_rect_create(&sDjuiRect->base);
|
||||||
|
sDjuiRect2->base.x = 0;
|
||||||
|
sDjuiRect2->base.y = 0;
|
||||||
|
//sDjuiRect2->base.color.r = 0;
|
||||||
|
sDjuiRect2->base.hAlign = DJUI_HALIGN_CENTER;
|
||||||
|
sDjuiRect2->base.vAlign = DJUI_VALIGN_CENTER;
|
||||||
|
sDjuiRect2->base.color.a = 255;
|
||||||
|
sDjuiRect2->base.width = 188 - 8;
|
||||||
|
sDjuiRect2->base.height = 64 - 8;
|
||||||
|
|
||||||
|
sDjuiText = djui_text_create(&sDjuiRect2->base, "Host");
|
||||||
|
sDjuiText->base.color.r = 111;
|
||||||
|
sDjuiText->base.color.g = 111;
|
||||||
|
sDjuiText->base.color.b = 111;
|
||||||
|
sDjuiText->fontSize = 2;
|
||||||
|
sDjuiText->base.color.a = 255;
|
||||||
|
sDjuiText->base.width = 188 - 8;
|
||||||
|
sDjuiText->base.height = 64 - 8;
|
||||||
|
sDjuiText->base.x = 0;
|
||||||
|
sDjuiText->base.y = 0;
|
||||||
|
sDjuiText->textHAlign = DJUI_HALIGN_CENTER;
|
||||||
|
sDjuiText->textVAlign = DJUI_VALIGN_CENTER;
|
||||||
|
|
||||||
|
sDjuiButton = djui_button_create(&gDjuiRoot->base, "button");
|
||||||
|
}
|
||||||
|
|
||||||
|
djui_base_render(&gDjuiRoot->base);
|
||||||
|
|
||||||
|
if (sDjuiRect2 != NULL) {
|
||||||
|
static u32 sTimer = 0;
|
||||||
|
sTimer++;
|
||||||
|
sDjuiImage->base.x = 16.0f + cos((sTimer) / 10.0f) * 24.0f;
|
||||||
|
sDjuiImage->base.y = 16.0f + sin((sTimer) / 31.0f) * 24.0f;
|
||||||
|
sDjuiImage->base.color.r = 127.0 + sin((sTimer) / 13.0f) * 127.0f;
|
||||||
|
sDjuiImage->base.color.g = 127.0 + sin((sTimer) / 17.0f) * 127.0f;
|
||||||
|
sDjuiImage->base.color.b = 127.0 + sin((sTimer) / 23.0f) * 127.0f;
|
||||||
|
|
||||||
|
sDjuiRect2->base.x = 32.0f + cos((sTimer) / 10.0f) * 64.0f;
|
||||||
|
sDjuiRect2->base.y = 32.0f + sin((sTimer) / 31.0f) * 64.0f;
|
||||||
|
|
||||||
|
sDjuiButton->base.width = 200 + cos((sTimer) / 10.0f) * 64.0f;
|
||||||
|
sDjuiButton->base.height = 64 + sin((sTimer) / 10.0f) * 16.0f;
|
||||||
|
}
|
||||||
|
}
|
24
src/pc/djui/djui.h
Normal file
24
src/pc/djui/djui.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
#include <PR/gbi.h>
|
||||||
|
#include <PR/ultratypes.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "djui_types.h"
|
||||||
|
#include "djui_gfx.h"
|
||||||
|
#include "djui_base.h"
|
||||||
|
|
||||||
|
#include "djui_root.h"
|
||||||
|
#include "djui_rect.h"
|
||||||
|
#include "djui_text.h"
|
||||||
|
#include "djui_image.h"
|
||||||
|
|
||||||
|
#include "djui_button.h"
|
||||||
|
|
||||||
|
#include "game/game_init.h"
|
||||||
|
#include "game/ingame_menu.h"
|
||||||
|
|
||||||
|
extern struct DjuiRoot* gDjuiRoot;
|
||||||
|
|
||||||
|
void djui_render(void);
|
209
src/pc/djui/djui_base.c
Normal file
209
src/pc/djui/djui_base.c
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
#include "djui.h"
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// properties //
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
void djui_base_set_location(struct DjuiBase* base, f32 x, f32 y) {
|
||||||
|
base->x = x;
|
||||||
|
base->y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void djui_base_set_size(struct DjuiBase* base, f32 width, f32 height) {
|
||||||
|
base->width = width;
|
||||||
|
base->height = height;
|
||||||
|
base->widthFill = false;
|
||||||
|
base->heightFill = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void djui_base_set_size_fill(struct DjuiBase* base, f32 widthScale, f32 heightScale) {
|
||||||
|
base->width = widthScale;
|
||||||
|
base->height = heightScale;
|
||||||
|
base->widthFill = true;
|
||||||
|
base->heightFill = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void djui_base_set_color(struct DjuiBase* base, u8 r, u8 g, u8 b, u8 a) {
|
||||||
|
base->color.r = r;
|
||||||
|
base->color.g = g;
|
||||||
|
base->color.b = b;
|
||||||
|
base->color.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void djui_base_set_alignment(struct DjuiBase* base, enum DjuiHAlign hAlign, enum DjuiVAlign vAlign) {
|
||||||
|
base->hAlign = hAlign;
|
||||||
|
base->vAlign = vAlign;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////
|
||||||
|
// utility //
|
||||||
|
/////////////
|
||||||
|
|
||||||
|
static void djui_base_clip(struct DjuiBase* base) {
|
||||||
|
struct DjuiBase* parent = base->parent;
|
||||||
|
struct DjuiBaseRect* comp = &base->comp;
|
||||||
|
struct DjuiBaseRect* clip = &base->clip;
|
||||||
|
|
||||||
|
clip->x = comp->x;
|
||||||
|
clip->y = comp->y;
|
||||||
|
clip->width = comp->width;
|
||||||
|
clip->height = comp->height;
|
||||||
|
|
||||||
|
if (parent == NULL) { return; }
|
||||||
|
|
||||||
|
clip->x = fmax(clip->x, parent->clip.x);
|
||||||
|
clip->y = fmax(clip->y, parent->clip.y);
|
||||||
|
|
||||||
|
clip->width = (comp->x + comp->width) - clip->x;
|
||||||
|
clip->height = (comp->y + comp->height) - clip->y;
|
||||||
|
|
||||||
|
clip->width = fmin(clip->width, (parent->clip.x + parent->clip.width) - clip->x);
|
||||||
|
clip->height = fmin(clip->height, (parent->clip.y + parent->clip.height) - clip->y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void djui_base_compute(struct DjuiBase* base) {
|
||||||
|
struct DjuiBase* parent = base->parent;
|
||||||
|
struct DjuiBaseRect* comp = &base->comp;
|
||||||
|
|
||||||
|
f32 x = base->x;
|
||||||
|
f32 y = base->y;
|
||||||
|
f32 width = base->widthFill ? (parent->comp.width - x) : base->width;
|
||||||
|
f32 height = base->heightFill ? (parent->comp.height - y) : base->height;
|
||||||
|
|
||||||
|
// horizontal alignment
|
||||||
|
if (base->hAlign == DJUI_HALIGN_CENTER) {
|
||||||
|
x += (parent->comp.width - width) / 2.0f;
|
||||||
|
} else if (base->hAlign == DJUI_HALIGN_RIGHT) {
|
||||||
|
x = parent->comp.width - width - x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// vertical alignment
|
||||||
|
if (base->vAlign == DJUI_VALIGN_CENTER) {
|
||||||
|
y += (parent->comp.height - height) / 2.0f;
|
||||||
|
} else if (base->vAlign == DJUI_VALIGN_BOTTOM) {
|
||||||
|
y = parent->comp.height - height - y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// offset comp on parent's location
|
||||||
|
if (base->parent != NULL) {
|
||||||
|
x += parent->comp.x;
|
||||||
|
y += parent->comp.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set computed values
|
||||||
|
comp->x = x;
|
||||||
|
comp->y = y;
|
||||||
|
comp->width = width;
|
||||||
|
comp->height = height;
|
||||||
|
|
||||||
|
djui_base_clip(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void djui_base_add_child(struct DjuiBase* parent, struct DjuiBase* base) {
|
||||||
|
if (parent == NULL) { return; }
|
||||||
|
|
||||||
|
// allocate linked list node
|
||||||
|
struct DjuiBaseChild* baseChild = malloc(sizeof(struct DjuiBaseChild));
|
||||||
|
baseChild->base = base;
|
||||||
|
baseChild->next = NULL;
|
||||||
|
|
||||||
|
// add it to the head
|
||||||
|
if (parent->child == NULL) {
|
||||||
|
parent->child = baseChild;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add it to the tail
|
||||||
|
struct DjuiBaseChild* parentChild = parent->child;
|
||||||
|
while (parentChild != NULL) {
|
||||||
|
if (parentChild->next == NULL) {
|
||||||
|
parentChild->next = baseChild;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parentChild = parentChild->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////
|
||||||
|
// events //
|
||||||
|
////////////
|
||||||
|
|
||||||
|
void djui_base_render(struct DjuiBase* base) {
|
||||||
|
if (!base->visible) { return; }
|
||||||
|
|
||||||
|
struct DjuiBaseRect* comp = &base->comp;
|
||||||
|
djui_base_compute(base);
|
||||||
|
if (comp->width <= 0) { return; }
|
||||||
|
if (comp->height <= 0) { return; }
|
||||||
|
|
||||||
|
if (base->render != NULL) {
|
||||||
|
base->render(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
// render all children
|
||||||
|
struct DjuiBaseChild* child = base->child;
|
||||||
|
while (child != NULL) {
|
||||||
|
djui_base_render(child->base);
|
||||||
|
child = child->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void djui_base_destroy(struct DjuiBase* base) {
|
||||||
|
// remove myself from parent's linked list
|
||||||
|
if (base->parent != NULL) {
|
||||||
|
struct DjuiBaseChild* child = base->parent->child;
|
||||||
|
struct DjuiBaseChild* lastChild = NULL;
|
||||||
|
while (child != NULL) {
|
||||||
|
if (child->base == base) {
|
||||||
|
// adjust linked list
|
||||||
|
if (lastChild == NULL) {
|
||||||
|
base->parent->child = child->next;
|
||||||
|
} else {
|
||||||
|
lastChild->next = child->next;
|
||||||
|
}
|
||||||
|
// deallocate child node
|
||||||
|
free(child);
|
||||||
|
base->parent = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate
|
||||||
|
lastChild = child;
|
||||||
|
child = child->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy all children and our linked list
|
||||||
|
struct DjuiBaseChild* child = base->child;
|
||||||
|
while (child != NULL) {
|
||||||
|
struct DjuiBaseChild* nextChild = child;
|
||||||
|
child->base->parent = NULL;
|
||||||
|
djui_base_destroy(child->base);
|
||||||
|
free(child);
|
||||||
|
child = nextChild->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy this
|
||||||
|
base->destroy(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void djui_base_init(struct DjuiBase* parent, struct DjuiBase* base, void(*render)(struct DjuiBase*), void (*destroy)(struct DjuiBase*)) {
|
||||||
|
base->parent = parent;
|
||||||
|
base->child = NULL;
|
||||||
|
base->visible = true;
|
||||||
|
base->x = 0;
|
||||||
|
base->y = 0;
|
||||||
|
base->width = 64;
|
||||||
|
base->height = 64;
|
||||||
|
base->widthFill = false;
|
||||||
|
base->heightFill = false;
|
||||||
|
base->color.r = 255;
|
||||||
|
base->color.g = 255;
|
||||||
|
base->color.b = 255;
|
||||||
|
base->color.a = 255;
|
||||||
|
base->hAlign = DJUI_HALIGN_LEFT;
|
||||||
|
base->vAlign = DJUI_VALIGN_TOP;
|
||||||
|
base->render = render;
|
||||||
|
base->destroy = destroy;
|
||||||
|
djui_base_add_child(parent, base);
|
||||||
|
}
|
48
src/pc/djui/djui_base.h
Normal file
48
src/pc/djui/djui_base.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#pragma once
|
||||||
|
#include "djui.h"
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct DjuiBaseRect {
|
||||||
|
f32 x;
|
||||||
|
f32 y;
|
||||||
|
f32 width;
|
||||||
|
f32 height;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct DjuiBaseChild {
|
||||||
|
struct DjuiBase* base;
|
||||||
|
struct DjuiBaseChild* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct DjuiBase {
|
||||||
|
struct DjuiBase* parent;
|
||||||
|
struct DjuiBaseChild* child;
|
||||||
|
bool visible;
|
||||||
|
f32 x;
|
||||||
|
f32 y;
|
||||||
|
f32 width;
|
||||||
|
f32 height;
|
||||||
|
bool widthFill;
|
||||||
|
bool heightFill;
|
||||||
|
struct DjuiColor color;
|
||||||
|
enum DjuiHAlign hAlign;
|
||||||
|
enum DjuiVAlign vAlign;
|
||||||
|
struct DjuiBaseRect comp;
|
||||||
|
struct DjuiBaseRect clip;
|
||||||
|
void (*render)(struct DjuiBase*);
|
||||||
|
void (*destroy)(struct DjuiBase*);
|
||||||
|
};
|
||||||
|
|
||||||
|
void djui_base_set_location(struct DjuiBase* base, f32 x, f32 y);
|
||||||
|
void djui_base_set_size(struct DjuiBase* base, f32 width, f32 height);
|
||||||
|
void djui_base_set_size_fill(struct DjuiBase* base, f32 widthScale, f32 heightScale);
|
||||||
|
void djui_base_set_color(struct DjuiBase* base, u8 r, u8 g, u8 b, u8 a);
|
||||||
|
void djui_base_set_alignment(struct DjuiBase* base, enum DjuiHAlign hAlign, enum DjuiVAlign vAlign);
|
||||||
|
|
||||||
|
void djui_base_compute(struct DjuiBase* base);
|
||||||
|
|
||||||
|
void djui_base_render(struct DjuiBase* base);
|
||||||
|
void djui_base_destroy(struct DjuiBase* base);
|
||||||
|
void djui_base_init(struct DjuiBase* parent, struct DjuiBase* base, void (*render)(struct DjuiBase*), void (*destroy)(struct DjuiBase*));
|
27
src/pc/djui/djui_button.c
Normal file
27
src/pc/djui/djui_button.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include "djui.h"
|
||||||
|
|
||||||
|
static void djui_button_destroy(struct DjuiBase* base) {
|
||||||
|
struct DjuiButton* button = (struct DjuiButton*)base;
|
||||||
|
free(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DjuiButton* djui_button_create(struct DjuiBase* parent, const char* message) {
|
||||||
|
struct DjuiButton* button = malloc(sizeof(struct DjuiButton));
|
||||||
|
struct DjuiBase* base = &button->base;
|
||||||
|
|
||||||
|
djui_base_init(parent, base, NULL, djui_button_destroy);
|
||||||
|
djui_base_set_size(base, 200, 64);
|
||||||
|
|
||||||
|
struct DjuiRect* rect = djui_rect_create(&button->base);
|
||||||
|
djui_base_set_size_fill(&rect->base, 1.0f, 1.0f);
|
||||||
|
djui_base_set_color(&rect->base, 225, 225, 225, 255);
|
||||||
|
button->rect = rect;
|
||||||
|
|
||||||
|
struct DjuiText* text = djui_text_create(&rect->base, message);
|
||||||
|
djui_base_set_size_fill(&text->base, 1.0f, 1.0f);
|
||||||
|
djui_base_set_color(&text->base, 11, 11, 11, 255);
|
||||||
|
djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
|
||||||
|
button->text = text;
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
11
src/pc/djui/djui_button.h
Normal file
11
src/pc/djui/djui_button.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
#include "djui.h"
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct DjuiButton {
|
||||||
|
struct DjuiBase base;
|
||||||
|
struct DjuiRect* rect;
|
||||||
|
struct DjuiText* text;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DjuiButton* djui_button_create(struct DjuiBase* parent, const char* message);
|
29
src/pc/djui/djui_gbi.h
Normal file
29
src/pc/djui/djui_gbi.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define G_TEXCLIP_DJUI 0xe1
|
||||||
|
#define G_TEXOVERRIDE_DJUI 0xe0
|
||||||
|
#define G_EXECUTE_DJUI 0xdd
|
||||||
|
|
||||||
|
#define gSetClippingDjui(pkt, cmd, rot, x1, y1, x2, y2) \
|
||||||
|
{ \
|
||||||
|
Gfx *_g = (Gfx *)(pkt); \
|
||||||
|
_g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL( x1, 16, 8) | \
|
||||||
|
_SHIFTL( y1, 8, 8) | _SHIFTL(rot, 0, 8); \
|
||||||
|
_g->words.w1 = _SHIFTL(x2, 16, 8) | _SHIFTL(y2, 8, 8); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define gSetOverrideDjui(pkt, cmd, texture, w, h) \
|
||||||
|
{ \
|
||||||
|
Gfx *_g = (Gfx *)(pkt); \
|
||||||
|
_g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL(w, 16, 8) | \
|
||||||
|
_SHIFTL(h, 8, 8); \
|
||||||
|
_g->words.w1 = (uintptr_t)(texture); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define gsSPExecuteDjui(word) \
|
||||||
|
{{ \
|
||||||
|
_SHIFTL(G_EXECUTE_DJUI, 24, 8), (unsigned int)(word) \
|
||||||
|
}}
|
||||||
|
|
||||||
|
#define gDPSetTextureClippingDjui(pkt, rot, x1, y1, x2, y2) gSetClippingDjui(pkt, G_TEXCLIP_DJUI, rot, x1, y1, x2, y2)
|
||||||
|
#define gDPSetTextureOverrideDjui(pkt, texture, w, h) gSetOverrideDjui(pkt, G_TEXOVERRIDE_DJUI, texture, w, h)
|
156
src/pc/djui/djui_gfx.c
Normal file
156
src/pc/djui/djui_gfx.c
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
#include <ultra64.h>
|
||||||
|
#include "sm64.h"
|
||||||
|
#include "djui.h"
|
||||||
|
#include "game/ingame_menu.h"
|
||||||
|
#include "game/segment2.h"
|
||||||
|
#include "src/pc/pc_main.h"
|
||||||
|
#include "src/pc/gfx/gfx_window_manager_api.h"
|
||||||
|
#include "gfx_dimensions.h"
|
||||||
|
|
||||||
|
static const Vtx vertex_djui_simple_rect[] = {
|
||||||
|
{{{ 0, -1, 0}, 0, { 0, 0 }, { 0xff, 0xff, 0xff, 0xff }}},
|
||||||
|
{{{ 1, -1, 0}, 0, { 0, 0 }, { 0xff, 0xff, 0xff, 0xff }}},
|
||||||
|
{{{ 1, 0, 0}, 0, { 0, 0 }, { 0xff, 0xff, 0xff, 0xff }}},
|
||||||
|
{{{ 0, 0, 0}, 0, { 0, 0 }, { 0xff, 0xff, 0xff, 0xff }}},
|
||||||
|
};
|
||||||
|
|
||||||
|
const Gfx dl_djui_simple_rect[] = {
|
||||||
|
gsDPPipeSync(),
|
||||||
|
gsSPClearGeometryMode(G_LIGHTING),
|
||||||
|
gsDPSetCombineMode(G_CC_FADE, G_CC_FADE),
|
||||||
|
gsDPSetRenderMode(G_RM_XLU_SURF, G_RM_XLU_SURF2),
|
||||||
|
gsSPVertex(vertex_djui_simple_rect, 4, 0),
|
||||||
|
gsSP2Triangles(0, 1, 2, 0x0, 0, 2, 3, 0x0),
|
||||||
|
gsSPEndDisplayList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
|
static Vtx vertex_djui_ia_char[] = {
|
||||||
|
{{{ 0, -16, 0}, 0, { 0, 256}, { 0xff, 0xff, 0xff, 0xff }}},
|
||||||
|
{{{ 8, -16, 0}, 0, { 0, 0}, { 0xff, 0xff, 0xff, 0xff }}},
|
||||||
|
{{{ 8, 0, 0}, 0, { 512, 0}, { 0xff, 0xff, 0xff, 0xff }}},
|
||||||
|
{{{ 0, 0, 0}, 0, { 512, 256}, { 0xff, 0xff, 0xff, 0xff }}},
|
||||||
|
};
|
||||||
|
|
||||||
|
const Gfx dl_djui_ia_text_begin[] = {
|
||||||
|
gsDPPipeSync(),
|
||||||
|
gsSPClearGeometryMode(G_LIGHTING),
|
||||||
|
gsDPSetCombineMode(G_CC_FADEA, G_CC_FADEA),
|
||||||
|
gsDPSetEnvColor(255, 255, 255, 255),
|
||||||
|
gsDPSetRenderMode(G_RM_XLU_SURF, G_RM_XLU_SURF2),
|
||||||
|
gsDPSetTextureFilter(G_TF_POINT),
|
||||||
|
gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON),
|
||||||
|
gsSPEndDisplayList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const Gfx dl_djui_ia_text_settings[] = {
|
||||||
|
gsDPSetTile(G_IM_FMT_IA, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, 3, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, 4, G_TX_NOLOD),
|
||||||
|
gsDPLoadSync(),
|
||||||
|
gsDPLoadBlock(G_TX_LOADTILE, 0, 0, ((16 * 8 + G_IM_SIZ_4b_INCR) >> G_IM_SIZ_4b_SHIFT) - 1, CALC_DXT(16, G_IM_SIZ_4b_BYTES)),
|
||||||
|
gsDPSetTile(G_IM_FMT_IA, G_IM_SIZ_4b, 1, 0, G_TX_RENDERTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, 3, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, 4, G_TX_NOLOD),
|
||||||
|
gsDPSetTileSize(0, 0, 0, (16 - 1) << G_TEXTURE_IMAGE_FRAC, (8 - 1) << G_TEXTURE_IMAGE_FRAC),
|
||||||
|
gsSPVertex(vertex_djui_ia_char, 4, 0),
|
||||||
|
gsSPExecuteDjui(G_TEXCLIP_DJUI),
|
||||||
|
gsSP2Triangles(0, 1, 2, 0x0, 0, 2, 3, 0x0),
|
||||||
|
gsSPEndDisplayList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
void djui_gfx_render_char(u8 c) {
|
||||||
|
void** fontLUT;
|
||||||
|
void* packedTexture;
|
||||||
|
|
||||||
|
fontLUT = segmented_to_virtual(main_font_lut);
|
||||||
|
packedTexture = segmented_to_virtual(fontLUT[c]);
|
||||||
|
|
||||||
|
gDPPipeSync(gDisplayListHead++);
|
||||||
|
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(packedTexture));
|
||||||
|
gSPDisplayList(gDisplayListHead++, dl_djui_ia_text_settings);
|
||||||
|
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
|
static const Vtx vertex_djui_image[] = {
|
||||||
|
{{{ 0, -1, 0 }, 0, { 0, 512 }, { 0xff, 0xff, 0xff, 0xff }}},
|
||||||
|
{{{ 1, -1, 0 }, 0, { 512, 512 }, { 0xff, 0xff, 0xff, 0xff }}},
|
||||||
|
{{{ 1, 0, 0 }, 0, { 512, 0 }, { 0xff, 0xff, 0xff, 0xff }}},
|
||||||
|
{{{ 0, 0, 0 }, 0, { 0, 0 }, { 0xff, 0xff, 0xff, 0xff }}},
|
||||||
|
};
|
||||||
|
|
||||||
|
const Gfx dl_djui_image[] = {
|
||||||
|
gsDPPipeSync(),
|
||||||
|
gsSPClearGeometryMode(G_LIGHTING),
|
||||||
|
gsDPSetCombineMode(G_CC_FADEA, G_CC_FADEA),
|
||||||
|
gsDPSetRenderMode(G_RM_XLU_SURF, G_RM_XLU_SURF2),
|
||||||
|
gsDPSetTextureFilter(G_TF_POINT),
|
||||||
|
gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON),
|
||||||
|
gsDPLoadTextureBlock(NULL, G_IM_FMT_RGBA, G_IM_SIZ_16b, 16, 16, 0, G_TX_CLAMP, G_TX_CLAMP, 5, 5, G_TX_NOLOD, G_TX_NOLOD),
|
||||||
|
gsSPExecuteDjui(G_TEXOVERRIDE_DJUI),
|
||||||
|
gsSPVertex(vertex_djui_image, 4, 0),
|
||||||
|
gsSPExecuteDjui(G_TEXCLIP_DJUI),
|
||||||
|
gsSP2Triangles(0, 1, 2, 0x0, 0, 2, 3, 0x0),
|
||||||
|
gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF),
|
||||||
|
gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
|
||||||
|
gsSPEndDisplayList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
void djui_gfx_render_texture(const u8* texture, u16 w, u16 h) {
|
||||||
|
gDPSetTextureOverrideDjui(gDisplayListHead++, texture, w, h);
|
||||||
|
gSPDisplayList(gDisplayListHead++, dl_djui_image);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
|
void djui_gfx_position_translate(f32* x, f32* y) {
|
||||||
|
u32 windowWidth, windowHeight;
|
||||||
|
wm_api->get_dimensions(&windowWidth, &windowHeight);
|
||||||
|
*x = GFX_DIMENSIONS_FROM_LEFT_EDGE(0) + *x * ((f32)SCREEN_HEIGHT / (f32)windowHeight);
|
||||||
|
*y = SCREEN_HEIGHT - *y * ((f32)SCREEN_HEIGHT / (f32)windowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void djui_gfx_scale_translate(f32* width, f32* height) {
|
||||||
|
u32 windowWidth, windowHeight;
|
||||||
|
wm_api->get_dimensions(&windowWidth, &windowHeight);
|
||||||
|
|
||||||
|
*width = *width * ((f32)SCREEN_HEIGHT / (f32)windowHeight);
|
||||||
|
*height = *height * ((f32)SCREEN_HEIGHT / (f32)windowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void djui_gfx_size_translate(f32* size) {
|
||||||
|
u32 windowWidth, windowHeight;
|
||||||
|
wm_api->get_dimensions(&windowWidth, &windowHeight);
|
||||||
|
|
||||||
|
*size = *size * ((f32)SCREEN_HEIGHT / (f32)windowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool djui_gfx_add_clipping_specific(struct DjuiBase* base, bool rotatedUV, f32 dX, f32 dY, f32 dW, f32 dH) {
|
||||||
|
struct DjuiBaseRect* clip = &base->clip;
|
||||||
|
|
||||||
|
f32 clipX2 = clip->x + clip->width;
|
||||||
|
f32 clipY2 = clip->y + clip->height;
|
||||||
|
|
||||||
|
f32 dX2 = dX + dW;
|
||||||
|
f32 dY2 = dY + dH;
|
||||||
|
|
||||||
|
// completely clipped
|
||||||
|
if (dX2 < clip->x) { return true; }
|
||||||
|
if (dX > clipX2) { return true; }
|
||||||
|
if (dY2 < clip->y) { return true; }
|
||||||
|
if (dY > clipY2) { return true; }
|
||||||
|
|
||||||
|
f32 dClipX1 = fmax((clip->x - dX) / dW, 0);
|
||||||
|
f32 dClipY1 = fmax((clip->y - dY) / dH, 0);
|
||||||
|
f32 dClipX2 = fmax((dX - (clipX2 - dW)) / dW, 0);
|
||||||
|
f32 dClipY2 = fmax((dY - (clipY2 - dH)) / dH, 0);
|
||||||
|
|
||||||
|
if ((dClipX1 != 0) || (dClipY1 != 0) || (dClipX2 != 0) || (dClipY2 != 0)) {
|
||||||
|
gDPSetTextureClippingDjui(gDisplayListHead++, rotatedUV, (u8)(dClipX1 * 255), (u8)(dClipY1 * 255), (u8)(dClipX2 * 255), (u8)(dClipY2 * 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool djui_gfx_add_clipping(struct DjuiBase* base) {
|
||||||
|
struct DjuiBaseRect* comp = &base->comp;
|
||||||
|
return djui_gfx_add_clipping_specific(base, false, comp->x, comp->y, comp->width, comp->height);
|
||||||
|
}
|
21
src/pc/djui/djui_gfx.h
Normal file
21
src/pc/djui/djui_gfx.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
#include "djui.h"
|
||||||
|
#include "djui_base.h"
|
||||||
|
|
||||||
|
#define DJUI_MTX_PUSH 1
|
||||||
|
#define DJUI_MTX_NOPUSH 2
|
||||||
|
|
||||||
|
extern const Gfx dl_djui_simple_rect[];
|
||||||
|
extern const Gfx dl_djui_ia_text_begin[];
|
||||||
|
extern const Gfx dl_djui_img_begin[];
|
||||||
|
extern const Gfx dl_djui_img_end[];
|
||||||
|
|
||||||
|
void djui_gfx_render_char(u8 c);
|
||||||
|
void djui_gfx_render_texture(const u8* texture, u16 w, u16 h);
|
||||||
|
|
||||||
|
void djui_gfx_position_translate(f32* x, f32* y);
|
||||||
|
void djui_gfx_scale_translate(f32* width, f32* height);
|
||||||
|
void djui_gfx_size_translate(f32* size);
|
||||||
|
|
||||||
|
bool djui_gfx_add_clipping_specific(struct DjuiBase* base, bool rotatedUV, f32 dX, f32 dY, f32 dW, f32 dH);
|
||||||
|
bool djui_gfx_add_clipping(struct DjuiBase* base);
|
59
src/pc/djui/djui_image.c
Normal file
59
src/pc/djui/djui_image.c
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#include "djui.h"
|
||||||
|
#include "game/segment2.h"
|
||||||
|
#include "src/pc/network/network.h"
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// properties //
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
void djui_image_set_image(struct DjuiImage* image, const u8* texture, u16 textureWidth, u16 textureHeight) {
|
||||||
|
image->texture = texture;
|
||||||
|
image->textureWidth = textureWidth;
|
||||||
|
image->textureHeight = textureHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////
|
||||||
|
// events //
|
||||||
|
////////////
|
||||||
|
|
||||||
|
static void djui_image_render(struct DjuiBase* base) {
|
||||||
|
struct DjuiImage* image = (struct DjuiImage*)base;
|
||||||
|
struct DjuiBaseRect* comp = &base->comp;
|
||||||
|
struct DjuiBaseRect* clip = &base->clip;
|
||||||
|
|
||||||
|
// translate position
|
||||||
|
f32 translatedX = comp->x;
|
||||||
|
f32 translatedY = comp->y;
|
||||||
|
djui_gfx_position_translate(&translatedX, &translatedY);
|
||||||
|
create_dl_translation_matrix(DJUI_MTX_PUSH, translatedX, translatedY, 0);
|
||||||
|
|
||||||
|
// translate size
|
||||||
|
f32 translatedWidth = comp->width;
|
||||||
|
f32 translatedHeight = comp->height;
|
||||||
|
djui_gfx_scale_translate(&translatedWidth, &translatedHeight);
|
||||||
|
create_dl_scale_matrix(DJUI_MTX_NOPUSH, translatedWidth, translatedHeight, 1.0f);
|
||||||
|
|
||||||
|
// render
|
||||||
|
if (!djui_gfx_add_clipping(base)) {
|
||||||
|
gDPSetEnvColor(gDisplayListHead++, base->color.r, base->color.g, base->color.b, base->color.a);
|
||||||
|
djui_gfx_render_texture(image->texture, image->textureWidth, image->textureHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void djui_image_destroy(struct DjuiBase* base) {
|
||||||
|
struct DjuiImage* image = (struct DjuiImage*)base;
|
||||||
|
free(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DjuiImage* djui_image_create(struct DjuiBase* parent, const u8* texture, u16 textureWidth, u16 textureHeight) {
|
||||||
|
struct DjuiImage* image = malloc(sizeof(struct DjuiImage));
|
||||||
|
struct DjuiBase* base = &image->base;
|
||||||
|
|
||||||
|
djui_base_init(parent, base, djui_image_render, djui_image_destroy);
|
||||||
|
|
||||||
|
djui_image_set_image(image, texture, textureWidth, textureHeight);
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
14
src/pc/djui/djui_image.h
Normal file
14
src/pc/djui/djui_image.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
#include "djui.h"
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct DjuiImage {
|
||||||
|
struct DjuiBase base;
|
||||||
|
const u8* texture;
|
||||||
|
u16 textureWidth;
|
||||||
|
u16 textureHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
void djui_image_set_image(struct DjuiImage* image, const u8* texture, u16 textureWidth, u16 textureHeight);
|
||||||
|
|
||||||
|
struct DjuiImage* djui_image_create(struct DjuiBase* parent, const u8* texture, u16 textureWidth, u16 textureHeight);
|
41
src/pc/djui/djui_rect.c
Normal file
41
src/pc/djui/djui_rect.c
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#include "djui.h"
|
||||||
|
|
||||||
|
////////////
|
||||||
|
// events //
|
||||||
|
////////////
|
||||||
|
|
||||||
|
static void djui_rect_render(struct DjuiBase* base) {
|
||||||
|
struct DjuiBaseRect* clip = &base->clip;
|
||||||
|
|
||||||
|
// translate position
|
||||||
|
f32 translatedX = clip->x;
|
||||||
|
f32 translatedY = clip->y;
|
||||||
|
djui_gfx_position_translate(&translatedX, &translatedY);
|
||||||
|
create_dl_translation_matrix(DJUI_MTX_PUSH, translatedX, translatedY, 0);
|
||||||
|
|
||||||
|
// translate size
|
||||||
|
f32 translatedWidth = clip->width;
|
||||||
|
f32 translatedHeight = clip->height;
|
||||||
|
djui_gfx_scale_translate(&translatedWidth, &translatedHeight);
|
||||||
|
create_dl_scale_matrix(DJUI_MTX_NOPUSH, translatedWidth, translatedHeight, 1.0f);
|
||||||
|
|
||||||
|
// render
|
||||||
|
gDPSetEnvColor(gDisplayListHead++, base->color.r, base->color.g, base->color.b, base->color.a);
|
||||||
|
gSPDisplayList(gDisplayListHead++, dl_djui_simple_rect);
|
||||||
|
|
||||||
|
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void djui_rect_destroy(struct DjuiBase* base) {
|
||||||
|
struct DjuiRect* rect = (struct DjuiRect*)base;
|
||||||
|
free(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DjuiRect* djui_rect_create(struct DjuiBase* parent) {
|
||||||
|
struct DjuiRect* rect = malloc(sizeof(struct DjuiRect));
|
||||||
|
struct DjuiBase* base = &rect->base;
|
||||||
|
|
||||||
|
djui_base_init(parent, base, djui_rect_render, djui_rect_destroy);
|
||||||
|
|
||||||
|
return rect;
|
||||||
|
}
|
9
src/pc/djui/djui_rect.h
Normal file
9
src/pc/djui/djui_rect.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
#include "djui.h"
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct DjuiRect {
|
||||||
|
struct DjuiBase base;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DjuiRect* djui_rect_create(struct DjuiBase* parent);
|
42
src/pc/djui/djui_root.c
Normal file
42
src/pc/djui/djui_root.c
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include "djui.h"
|
||||||
|
#include "src/pc/pc_main.h"
|
||||||
|
#include "src/pc/gfx/gfx_window_manager_api.h"
|
||||||
|
|
||||||
|
static void djui_root_render(struct DjuiBase* base) {
|
||||||
|
// grab window height
|
||||||
|
u32 windowWidth, windowHeight;
|
||||||
|
wm_api->get_dimensions(&windowWidth, &windowHeight);
|
||||||
|
|
||||||
|
// fill the screen
|
||||||
|
base->x = 0;
|
||||||
|
base->y = 0;
|
||||||
|
base->width = windowWidth;
|
||||||
|
base->height = windowHeight;
|
||||||
|
|
||||||
|
// compute base
|
||||||
|
djui_base_compute(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void djui_root_destroy(struct DjuiBase* base) {
|
||||||
|
struct DjuiRoot* root = (struct DjuiRoot*)base;
|
||||||
|
free(root);
|
||||||
|
gDjuiRoot = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DjuiRoot* djui_root_create(void) {
|
||||||
|
struct DjuiRoot* root = malloc(sizeof(struct DjuiRoot));
|
||||||
|
struct DjuiBase* base = &root->base;
|
||||||
|
|
||||||
|
djui_base_init(NULL, base, djui_root_render, djui_root_destroy);
|
||||||
|
|
||||||
|
u32 windowWidth, windowHeight;
|
||||||
|
wm_api->get_dimensions(&windowWidth, &windowHeight);
|
||||||
|
|
||||||
|
base->x = 0;
|
||||||
|
base->y = 0;
|
||||||
|
base->width = windowWidth;
|
||||||
|
base->height = windowHeight;
|
||||||
|
base->color.a = 0;
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
9
src/pc/djui/djui_root.h
Normal file
9
src/pc/djui/djui_root.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
#include "djui.h"
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct DjuiRoot {
|
||||||
|
struct DjuiBase base;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DjuiRoot* djui_root_create(void);
|
280
src/pc/djui/djui_text.c
Normal file
280
src/pc/djui/djui_text.c
Normal file
|
@ -0,0 +1,280 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include "djui.h"
|
||||||
|
#include "game/segment2.h"
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// properties //
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
void djui_text_set_text(struct DjuiText* text, const char* message) {
|
||||||
|
// deallocate old message
|
||||||
|
if (text->message != NULL) {
|
||||||
|
free(text->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate and set new message
|
||||||
|
u16 messageLen = strlen(message);
|
||||||
|
text->message = malloc(sizeof(char) * (messageLen + 1));
|
||||||
|
memcpy(text->message, message, sizeof(char) * (messageLen + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void djui_text_set_font_size(struct DjuiText* text, f32 fontSize) {
|
||||||
|
text->fontSize = fontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void djui_text_set_alignment(struct DjuiText* text, enum DjuiHAlign hAlign, enum DjuiVAlign vAlign) {
|
||||||
|
text->textHAlign = hAlign;
|
||||||
|
text->textVAlign = vAlign;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////
|
||||||
|
// rendering //
|
||||||
|
///////////////
|
||||||
|
|
||||||
|
#define DJUI_TEXT_CHAR_HEIGHT 16
|
||||||
|
#define DJUI_TEXT_CHAR_WIDTH 8
|
||||||
|
|
||||||
|
static f32 sTextRenderX = 0;
|
||||||
|
static f32 sTextRenderY = 0;
|
||||||
|
static f32 sTextRenderLastX = 0;
|
||||||
|
static f32 sTextRenderLastY = 0;
|
||||||
|
|
||||||
|
static void djui_text_translate(f32 x, f32 y) {
|
||||||
|
sTextRenderX += x;
|
||||||
|
sTextRenderY += y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void djui_text_render_char(struct DjuiText* text, u8 d) {
|
||||||
|
struct DjuiBaseRect* comp = &text->base.comp;
|
||||||
|
struct DjuiBaseRect* clip = &text->base.clip;
|
||||||
|
|
||||||
|
f32 dX = comp->x + sTextRenderX * text->fontSize;
|
||||||
|
f32 dY = comp->y + sTextRenderY * text->fontSize;
|
||||||
|
f32 dW = DJUI_TEXT_CHAR_WIDTH * text->fontSize;
|
||||||
|
f32 dH = DJUI_TEXT_CHAR_HEIGHT * text->fontSize;
|
||||||
|
|
||||||
|
if (djui_gfx_add_clipping_specific(&text->base, true, dX, dY, dW, dH)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
create_dl_translation_matrix(DJUI_MTX_NOPUSH, sTextRenderX - sTextRenderLastX, (sTextRenderY - sTextRenderLastY) * -1.0f, 0);
|
||||||
|
djui_gfx_render_char(d);
|
||||||
|
|
||||||
|
sTextRenderLastX = sTextRenderX;
|
||||||
|
sTextRenderLastY = sTextRenderY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static f32 djui_text_measure_word_width(char* message) {
|
||||||
|
f32 width = 0;
|
||||||
|
while (*message != '\0') {
|
||||||
|
u8 d = str_ascii_char_to_dialog(*message);
|
||||||
|
if (d == DIALOG_CHAR_SPACE) { return width; }
|
||||||
|
if (d == DIALOG_CHAR_NEWLINE) { return width; }
|
||||||
|
if (d == DIALOG_CHAR_TERMINATOR) { return width; }
|
||||||
|
width += gDialogCharWidths[d];
|
||||||
|
message++;
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void djui_text_read_line(char* message, u16* index, f32* lineWidth, f32 maxLineWidth, bool onLastLine, bool* ellipses) {
|
||||||
|
*lineWidth = 0;
|
||||||
|
u8 lastD = DIALOG_CHAR_TERMINATOR;
|
||||||
|
|
||||||
|
f32 ellipsesWidth = gDialogCharWidths[0x3F] * 3.0f;
|
||||||
|
u16 lastSafeEllipsesIndex = *index;
|
||||||
|
u16 lastSafeEllipsesLineWidth = *lineWidth + ellipsesWidth;
|
||||||
|
|
||||||
|
while (message[*index] != '\0') {
|
||||||
|
u8 d = str_ascii_char_to_dialog(message[*index]);
|
||||||
|
|
||||||
|
// check for newline
|
||||||
|
if (d == DIALOG_CHAR_NEWLINE) {
|
||||||
|
*index = *index + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check to see if this character would exceed size
|
||||||
|
if (*lineWidth + gDialogCharWidths[d] >= maxLineWidth) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check to see if this word exceeds size
|
||||||
|
if (!onLastLine && lastD == DIALOG_CHAR_SPACE && d != DIALOG_CHAR_SPACE) {
|
||||||
|
f32 wordWidth = djui_text_measure_word_width(&message[*index]);
|
||||||
|
if (*lineWidth + wordWidth >= maxLineWidth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*lineWidth += gDialogCharWidths[d];
|
||||||
|
|
||||||
|
// check for safe ellipses index
|
||||||
|
if (onLastLine && ((*lineWidth + ellipsesWidth) < maxLineWidth)) {
|
||||||
|
lastSafeEllipsesIndex = *index;
|
||||||
|
lastSafeEllipsesLineWidth = *lineWidth + ellipsesWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
*index = *index + 1;
|
||||||
|
lastD = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check to see if we should replace the end of the last line with ellipses
|
||||||
|
if (onLastLine && message[*index] != '\0') {
|
||||||
|
*index = lastSafeEllipsesIndex;
|
||||||
|
*lineWidth = lastSafeEllipsesLineWidth;
|
||||||
|
*ellipses = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void djui_text_render_line(struct DjuiText* text, u16 startIndex, u16 endIndex, f32 lineWidth, bool ellipses) {
|
||||||
|
struct DjuiBase* base = &text->base;
|
||||||
|
struct DjuiBaseRect* comp = &base->comp;
|
||||||
|
f32 curWidth = 0;
|
||||||
|
|
||||||
|
// horizontal alignment
|
||||||
|
if (text->textHAlign == DJUI_HALIGN_CENTER) {
|
||||||
|
// center text
|
||||||
|
f32 offset = (comp->width / text->fontSize) / 2.0f - lineWidth / 2.0f;
|
||||||
|
djui_text_translate(offset, 0);
|
||||||
|
curWidth = offset;
|
||||||
|
} else if (text->textHAlign == DJUI_HALIGN_RIGHT) {
|
||||||
|
// right align text
|
||||||
|
f32 offset = (comp->width / text->fontSize) - lineWidth;
|
||||||
|
djui_text_translate(offset, 0);
|
||||||
|
curWidth = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// render the line
|
||||||
|
for (int i = startIndex; i < endIndex; i++) {
|
||||||
|
u8 d = str_ascii_char_to_dialog(text->message[i]);
|
||||||
|
switch (d) {
|
||||||
|
case DIALOG_CHAR_SPACE:
|
||||||
|
break;
|
||||||
|
case DIALOG_CHAR_NEWLINE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
djui_text_render_char(text, d);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
djui_text_translate(gDialogCharWidths[d], 0);
|
||||||
|
curWidth += gDialogCharWidths[d];
|
||||||
|
}
|
||||||
|
|
||||||
|
// render ellipses
|
||||||
|
if (ellipses) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
u8 d = str_ascii_char_to_dialog('.');
|
||||||
|
djui_text_render_char(text, d);
|
||||||
|
djui_text_translate(gDialogCharWidths[d], 0);
|
||||||
|
curWidth += gDialogCharWidths[d];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset translation matrix
|
||||||
|
djui_text_translate(-curWidth, DJUI_TEXT_CHAR_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////
|
||||||
|
// events //
|
||||||
|
////////////
|
||||||
|
|
||||||
|
static void djui_text_render(struct DjuiBase* base) {
|
||||||
|
gSPDisplayList(gDisplayListHead++, dl_djui_ia_text_begin);
|
||||||
|
|
||||||
|
struct DjuiText* text = (struct DjuiText*)base;
|
||||||
|
struct DjuiBaseRect* comp = &base->comp;
|
||||||
|
|
||||||
|
// reset render location
|
||||||
|
sTextRenderX = 0;
|
||||||
|
sTextRenderY = 0;
|
||||||
|
sTextRenderLastX = 0;
|
||||||
|
sTextRenderLastY = 0;
|
||||||
|
|
||||||
|
// compute base
|
||||||
|
djui_base_compute(base);
|
||||||
|
|
||||||
|
// translate position
|
||||||
|
f32 translatedX = comp->x;
|
||||||
|
f32 translatedY = comp->y;
|
||||||
|
djui_gfx_position_translate(&translatedX, &translatedY);
|
||||||
|
create_dl_translation_matrix(DJUI_MTX_PUSH, translatedX, translatedY, 0);
|
||||||
|
|
||||||
|
// compute size
|
||||||
|
f32 translatedWidth = comp->width;
|
||||||
|
f32 translatedHeight = comp->height;
|
||||||
|
djui_gfx_scale_translate(&translatedWidth, &translatedHeight);
|
||||||
|
|
||||||
|
// compute font size
|
||||||
|
f32 translatedFontSize = text->fontSize;
|
||||||
|
djui_gfx_size_translate(&translatedFontSize);
|
||||||
|
create_dl_scale_matrix(DJUI_MTX_NOPUSH, translatedFontSize, translatedFontSize, 1.0f);
|
||||||
|
|
||||||
|
// set color
|
||||||
|
gDPSetEnvColor(gDisplayListHead++, base->color.r, base->color.g, base->color.b, base->color.a);
|
||||||
|
|
||||||
|
// count lines
|
||||||
|
u16 startIndex = 0;
|
||||||
|
u16 endIndex = 0;
|
||||||
|
f32 maxLineWidth = comp->width / text->fontSize;
|
||||||
|
u16 lineCount = 0;
|
||||||
|
u16 maxLines = comp->height / ((f32)DJUI_TEXT_CHAR_HEIGHT * text->fontSize);
|
||||||
|
while (text->message[startIndex] != '\0') {
|
||||||
|
bool onLastLine = lineCount + 1 >= maxLines;
|
||||||
|
f32 lineWidth;
|
||||||
|
bool ellipses;
|
||||||
|
djui_text_read_line(text->message, &endIndex, &lineWidth, maxLineWidth, onLastLine, &ellipses);
|
||||||
|
startIndex = endIndex;
|
||||||
|
lineCount++;
|
||||||
|
if (onLastLine) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// do vertical alignment
|
||||||
|
f32 vOffset = 0;
|
||||||
|
if (text->textVAlign == DJUI_VALIGN_CENTER) {
|
||||||
|
vOffset += (comp->height / text->fontSize) / 2.0f;
|
||||||
|
vOffset -= (lineCount * DJUI_TEXT_CHAR_HEIGHT) / 2.0f;
|
||||||
|
} else if (text->textVAlign == DJUI_VALIGN_BOTTOM) {
|
||||||
|
vOffset += (comp->height / text->fontSize);
|
||||||
|
vOffset -= (lineCount * DJUI_TEXT_CHAR_HEIGHT);
|
||||||
|
}
|
||||||
|
djui_text_translate(0, vOffset);
|
||||||
|
|
||||||
|
// render lines
|
||||||
|
startIndex = 0;
|
||||||
|
endIndex = 0;
|
||||||
|
f32 lineWidth;
|
||||||
|
u16 lineIndex = 0;
|
||||||
|
bool ellipses = false;
|
||||||
|
while (text->message[startIndex] != '\0') {
|
||||||
|
bool onLastLine = lineIndex + 1 >= maxLines;
|
||||||
|
djui_text_read_line(text->message, &endIndex, &lineWidth, maxLineWidth, onLastLine, &ellipses);
|
||||||
|
djui_text_render_line(text, startIndex, endIndex, lineWidth, ellipses);
|
||||||
|
startIndex = endIndex;
|
||||||
|
lineIndex++;
|
||||||
|
if (onLastLine) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
||||||
|
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void djui_text_destroy(struct DjuiBase* base) {
|
||||||
|
struct DjuiText* text = (struct DjuiText*)base;
|
||||||
|
free(text->message);
|
||||||
|
free(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DjuiText* djui_text_create(struct DjuiBase* parent, const char* message) {
|
||||||
|
struct DjuiText* text = malloc(sizeof(struct DjuiText));
|
||||||
|
struct DjuiBase* base = &text->base;
|
||||||
|
|
||||||
|
djui_base_init(parent, base, djui_text_render, djui_text_destroy);
|
||||||
|
|
||||||
|
text->message = NULL;
|
||||||
|
djui_text_set_text(text, message);
|
||||||
|
djui_text_set_font_size(text, 2.0f);
|
||||||
|
djui_text_set_alignment(text, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
17
src/pc/djui/djui_text.h
Normal file
17
src/pc/djui/djui_text.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
#include "djui.h"
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct DjuiText {
|
||||||
|
struct DjuiBase base;
|
||||||
|
char* message;
|
||||||
|
f32 fontSize;
|
||||||
|
enum DjuiHAlign textHAlign;
|
||||||
|
enum DjuiVAlign textVAlign;
|
||||||
|
};
|
||||||
|
|
||||||
|
void djui_text_set_text(struct DjuiText* text, const char* message);
|
||||||
|
void djui_text_set_font_size(struct DjuiText* text, f32 fontSize);
|
||||||
|
void djui_text_set_alignment(struct DjuiText* text, enum DjuiHAlign hAlign, enum DjuiVAlign vAlign);
|
||||||
|
|
||||||
|
struct DjuiText* djui_text_create(struct DjuiBase* parent, const char* message);
|
21
src/pc/djui/djui_types.h
Normal file
21
src/pc/djui/djui_types.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
#include "djui.h"
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct DjuiColor {
|
||||||
|
u8 r;
|
||||||
|
u8 g;
|
||||||
|
u8 b;
|
||||||
|
u8 a;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum DjuiScreenValueType { DJUI_SVT_ABSOLUTE, DJUI_SVT_RELATIVE };
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct DjuiScreenValue {
|
||||||
|
enum DjuiScreenValueType type;
|
||||||
|
f32 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum DjuiHAlign { DJUI_HALIGN_LEFT, DJUI_HALIGN_CENTER, DJUI_HALIGN_RIGHT };
|
||||||
|
enum DjuiVAlign { DJUI_VALIGN_TOP, DJUI_VALIGN_CENTER, DJUI_VALIGN_BOTTOM };
|
|
@ -186,6 +186,12 @@ static const uint8_t missing_texture[MISSING_W * MISSING_H * 4] = {
|
||||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
|
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
// forward declaration for djui //
|
||||||
|
//////////////////////////////////
|
||||||
|
void djui_gfx_run_dl(Gfx* cmd);
|
||||||
|
//////////////////////////////////
|
||||||
|
|
||||||
#ifdef EXTERNAL_DATA
|
#ifdef EXTERNAL_DATA
|
||||||
static inline size_t string_hash(const uint8_t *str) {
|
static inline size_t string_hash(const uint8_t *str) {
|
||||||
size_t h = 0;
|
size_t h = 0;
|
||||||
|
@ -1725,6 +1731,9 @@ static void gfx_run_dl(Gfx* cmd) {
|
||||||
case G_SETCIMG:
|
case G_SETCIMG:
|
||||||
gfx_dp_set_color_image(C0(21, 3), C0(19, 2), C0(0, 11), seg_addr(cmd->words.w1));
|
gfx_dp_set_color_image(C0(21, 3), C0(19, 2), C0(0, 11), seg_addr(cmd->words.w1));
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
djui_gfx_run_dl(cmd);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
++cmd;
|
++cmd;
|
||||||
}
|
}
|
||||||
|
@ -1839,3 +1848,144 @@ void gfx_shutdown(void) {
|
||||||
gfx_wapi = NULL;
|
gfx_wapi = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
// v custom for djui v //
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
static bool sDjuiClip = 0;
|
||||||
|
static bool sDjuiClipRotatedUV = 0;
|
||||||
|
static uint8_t sDjuiClipX1 = 0;
|
||||||
|
static uint8_t sDjuiClipY1 = 0;
|
||||||
|
static uint8_t sDjuiClipX2 = 0;
|
||||||
|
static uint8_t sDjuiClipY2 = 0;
|
||||||
|
|
||||||
|
static bool sDjuiOverride = false;
|
||||||
|
static void* sDjuiOverrideTexture = NULL;
|
||||||
|
static uint8_t sDjuiOverrideW = 0;
|
||||||
|
static uint8_t sDjuiOverrideH = 0;
|
||||||
|
|
||||||
|
static void djui_gfx_dp_set_clipping(bool rotatedUV, uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2) {
|
||||||
|
sDjuiClipRotatedUV = rotatedUV;
|
||||||
|
sDjuiClipX1 = x1;
|
||||||
|
sDjuiClipY1 = y1;
|
||||||
|
sDjuiClipX2 = x2;
|
||||||
|
sDjuiClipY2 = y2;
|
||||||
|
sDjuiClip = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void djui_gfx_dp_execute_clipping(void) {
|
||||||
|
if (!sDjuiClip) { return; }
|
||||||
|
sDjuiClip = 0;
|
||||||
|
|
||||||
|
size_t start_index = 0;
|
||||||
|
size_t dest_index = 4;
|
||||||
|
|
||||||
|
float minX = rsp.loaded_vertices[start_index].x;
|
||||||
|
float maxX = rsp.loaded_vertices[start_index].x;
|
||||||
|
float minY = rsp.loaded_vertices[start_index].y;
|
||||||
|
float maxY = rsp.loaded_vertices[start_index].y;
|
||||||
|
|
||||||
|
float minU = rsp.loaded_vertices[start_index].u;
|
||||||
|
float maxU = rsp.loaded_vertices[start_index].u;
|
||||||
|
float minV = rsp.loaded_vertices[start_index].v;
|
||||||
|
float maxV = rsp.loaded_vertices[start_index].v;
|
||||||
|
|
||||||
|
for (size_t i = start_index; i < dest_index; i++) {
|
||||||
|
struct LoadedVertex* d = &rsp.loaded_vertices[i];
|
||||||
|
minX = fmin(minX, d->x);
|
||||||
|
maxX = fmax(maxX, d->x);
|
||||||
|
minY = fmin(minY, d->y);
|
||||||
|
maxY = fmax(maxY, d->y);
|
||||||
|
|
||||||
|
minU = fmin(minU, d->u);
|
||||||
|
maxU = fmax(maxU, d->u);
|
||||||
|
minV = fmin(minV, d->v);
|
||||||
|
maxV = fmax(maxV, d->v);
|
||||||
|
}
|
||||||
|
|
||||||
|
float midY = (minY + maxY) / 2.0f;
|
||||||
|
float midX = (minX + maxX) / 2.0f;
|
||||||
|
float midU = (minU + maxU) / 2.0f;
|
||||||
|
float midV = (minV + maxV) / 2.0f;
|
||||||
|
for (size_t i = start_index; i < dest_index; i++) {
|
||||||
|
struct LoadedVertex* d = &rsp.loaded_vertices[i];
|
||||||
|
if (d->x <= midX) {
|
||||||
|
d->x += (maxX - minX) * (sDjuiClipX1 / 255.0f);
|
||||||
|
} else {
|
||||||
|
d->x -= (maxX - minX) * (sDjuiClipX2 / 255.0f);
|
||||||
|
}
|
||||||
|
if (d->y <= midY) {
|
||||||
|
d->y += (maxY - minY) * (sDjuiClipY2 / 255.0f);
|
||||||
|
} else {
|
||||||
|
d->y -= (maxY - minY) * (sDjuiClipY1 / 255.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sDjuiClipRotatedUV) {
|
||||||
|
if (d->u <= midU) {
|
||||||
|
d->u += (maxU - minU) * (sDjuiClipY2 / 255.0f);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d->u -= (maxU - minU) * (sDjuiClipY1 / 255.0f);
|
||||||
|
}
|
||||||
|
if (d->v <= midV) {
|
||||||
|
d->v += (maxV - minV) * (sDjuiClipX2 / 255.0f);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d->v -= (maxV - minV) * (sDjuiClipX1 / 255.0f);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (d->u <= midU) {
|
||||||
|
d->u += (maxU - minU) * (sDjuiClipX1 / 255.0f);
|
||||||
|
} else {
|
||||||
|
d->u -= (maxU - minU) * (sDjuiClipX2 / 255.0f);
|
||||||
|
}
|
||||||
|
if (d->v <= midV) {
|
||||||
|
d->v += (maxV - minV) * (sDjuiClipY1 / 255.0f);
|
||||||
|
} else {
|
||||||
|
d->v -= (maxV - minV) * (sDjuiClipY2 / 255.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void djui_gfx_dp_set_override(void* texture, uint8_t w, uint8_t h) {
|
||||||
|
sDjuiOverrideTexture = texture;
|
||||||
|
sDjuiOverrideW = w;
|
||||||
|
sDjuiOverrideH = h;
|
||||||
|
sDjuiOverride = (texture != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void djui_gfx_dp_execute_override(void) {
|
||||||
|
if (!sDjuiOverride) { return; }
|
||||||
|
sDjuiOverride = false;
|
||||||
|
|
||||||
|
rdp.texture_to_load.addr = sDjuiOverrideTexture;
|
||||||
|
rdp.loaded_texture[rdp.texture_to_load.tile_number].addr = rdp.texture_to_load.addr;
|
||||||
|
uint32_t line = (((sDjuiOverrideW * 2) + 7) >> 3);
|
||||||
|
rdp.texture_tile.line_size_bytes = line * 8;
|
||||||
|
uint32_t lrs = (sDjuiOverrideW * sDjuiOverrideH) - 1;
|
||||||
|
rdp.loaded_texture[rdp.texture_to_load.tile_number].size_bytes = (lrs + 1) << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void djui_gfx_dp_execute_djui(uint32_t opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case G_TEXOVERRIDE_DJUI: djui_gfx_dp_execute_override(); break;
|
||||||
|
case G_TEXCLIP_DJUI: djui_gfx_dp_execute_clipping(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void djui_gfx_run_dl(Gfx* cmd) {
|
||||||
|
uint32_t opcode = cmd->words.w0 >> 24;
|
||||||
|
switch (opcode) {
|
||||||
|
case G_TEXCLIP_DJUI:
|
||||||
|
djui_gfx_dp_set_clipping(C0(0, 8), C0(16, 8), C0(8, 8), C1(16, 8), C1(8, 8));
|
||||||
|
break;
|
||||||
|
case G_TEXOVERRIDE_DJUI:
|
||||||
|
djui_gfx_dp_set_override(seg_addr(cmd->words.w1), C0(16, 8), C0(8, 8));
|
||||||
|
break;
|
||||||
|
case G_EXECUTE_DJUI:
|
||||||
|
djui_gfx_dp_execute_djui(cmd->words.w1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue