From c0b093b11f8c9bbed2301dd45e606253bbc5c9ad Mon Sep 17 00:00:00 2001 From: MysterD Date: Sun, 20 Jun 2021 23:34:14 -0700 Subject: [PATCH] DJUI: Created main menu panel Added ability to make a DjuiBase keep its aspect ration Added on_render_pre callback Added ability to display 32b images Added DjuiFlowLayout Added logo --- build-windows-visual-studio/sm64ex.vcxproj | 2 + .../sm64ex.vcxproj.filters | 50 +++++--- src/pc/djui/djui.c | 113 ++++++++---------- src/pc/djui/djui.h | 6 +- src/pc/djui/djui_base.c | 14 ++- src/pc/djui/djui_base.h | 2 + src/pc/djui/djui_flow_layout.c | 61 ++++++++++ src/pc/djui/djui_flow_layout.h | 15 +++ src/pc/djui/djui_gbi.h | 8 +- src/pc/djui/djui_gfx.c | 20 +++- src/pc/djui/djui_gfx.h | 2 +- src/pc/djui/djui_image.c | 9 +- src/pc/djui/djui_image.h | 5 +- src/pc/djui/djui_panel_main.c | 70 +++++++++++ src/pc/djui/djui_panel_main.h | 4 + src/pc/djui/djui_rect.c | 2 +- src/pc/djui/djui_rect.h | 1 + src/pc/djui/djui_types.h | 3 +- src/pc/gfx/gfx_pc.c | 65 ++++++---- textures/segment2/custom_title.rgba32.png | Bin 0 -> 16739 bytes 20 files changed, 331 insertions(+), 121 deletions(-) create mode 100644 src/pc/djui/djui_flow_layout.c create mode 100644 src/pc/djui/djui_flow_layout.h create mode 100644 src/pc/djui/djui_panel_main.c create mode 100644 src/pc/djui/djui_panel_main.h create mode 100644 textures/segment2/custom_title.rgba32.png diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj index 8fb030cb..f42b2aea 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj +++ b/build-windows-visual-studio/sm64ex.vcxproj @@ -3944,6 +3944,7 @@ + @@ -4364,6 +4365,7 @@ + diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters index 7ad6a2fc..24040d78 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj.filters +++ b/build-windows-visual-studio/sm64ex.vcxproj.filters @@ -3448,9 +3448,15 @@ {0e1e4798-796e-4801-be6e-69d0c3b05ad7} - + + {2401a619-ee3f-4637-9926-a619a5e65bcb} + + {471ac819-ed6b-4a33-8952-50a8e0d2d839} + + {a7515004-4574-4bc0-9288-f716100c8a43} + @@ -15154,22 +15160,19 @@ Source Files\src\pc\djui - Source Files\src\pc\djui\components + Source Files\src\pc\djui\component - Source Files\src\pc\djui\components + Source Files\src\pc\djui\component - Source Files\src\pc\djui\components + Source Files\src\pc\djui\component - Source Files\src\pc\djui\components + Source Files\src\pc\djui\component - Source Files\src\pc\djui\components - - - Source Files\src\pc\djui\components + Source Files\src\pc\djui\component Source Files\src\pc\controller @@ -15178,7 +15181,13 @@ Source Files\src\pc\controller - Source Files\src\pc\djui\components + Source Files\src\pc\djui\component + + + Source Files\src\pc\djui\component\compound + + + Source Files\src\pc\djui\component\compound @@ -16166,25 +16175,28 @@ Source Files\src\pc\djui - Source Files\src\pc\djui\components + Source Files\src\pc\djui\component - Source Files\src\pc\djui\components + Source Files\src\pc\djui\component - Source Files\src\pc\djui\components + Source Files\src\pc\djui\component - Source Files\src\pc\djui\components + Source Files\src\pc\djui\component - Source Files\src\pc\djui\components - - - Source Files\src\pc\djui\components + Source Files\src\pc\djui\component - Source Files\src\pc\djui\components + Source Files\src\pc\djui\component + + + Source Files\src\pc\djui\component\compound + + + Source Files\src\pc\djui\component\compound \ No newline at end of file diff --git a/src/pc/djui/djui.c b/src/pc/djui/djui.c index e13d180b..d09d7ebb 100644 --- a/src/pc/djui/djui.c +++ b/src/pc/djui/djui.c @@ -12,92 +12,79 @@ ALIGNED8 static const u8 texture16x16[] = { #include "textures/segment2/custom_luigi_head.rgba16.inc.c" }; -ALIGNED8 u8 texture_hand_open[] = { +ALIGNED8 static u8 texture_hand_open[] = { #include "textures/intro_raw/hand_open.rgba16.inc.c" }; -ALIGNED8 u8 texture_hand_closed[] = { +ALIGNED8 static u8 texture_hand_closed[] = { #include "textures/intro_raw/hand_closed.rgba16.inc.c" }; +ALIGNED8 static u8 texture_title[] = { +#include "textures/segment2/custom_title.rgba32.inc.c" +}; + static Gfx* sSavedDisplayListHead = NULL; struct DjuiRoot* gDjuiRoot = NULL; static struct DjuiImage* sMouseCursor = NULL; - -// v REMOVE ME v -static struct DjuiRect* sDjuiRect = NULL; -static struct DjuiRect* sDjuiRect2 = NULL; -static struct DjuiText* sDjuiText = NULL; -static struct DjuiImage* sDjuiImage = NULL; -// ^ REMOVE ME ^ +struct DjuiFlowLayout* buttonContainer; static void djui_init(void) { gDjuiRoot = djui_root_create(); - sMouseCursor = djui_image_create(NULL, texture_hand_open, 32, 32); + sMouseCursor = djui_image_create(NULL, texture_hand_open, 32, 32, 16); djui_base_set_location(&sMouseCursor->base, 0, 0); djui_base_set_size(&sMouseCursor->base, 64, 64); - //// - - struct DjuiRect* imageContainer = djui_rect_create(&gDjuiRoot->base); - djui_base_set_location(&imageContainer->base, 32, 32); - djui_base_set_size(&imageContainer->base, 128, 128); - djui_base_set_padding(&imageContainer->base, 48, 48, 48, 48); - - sDjuiImage = djui_image_create(&imageContainer->base, texture16x16, 16, 16); - djui_base_set_location(&sDjuiImage->base, 0, 0); - djui_base_set_size(&sDjuiImage->base, 32, 32); - djui_base_set_size_type(&sDjuiImage->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE); - djui_base_set_size(&sDjuiImage->base, 1.0f, 1.0f); - - ////////////// - - sDjuiRect = djui_rect_create(&gDjuiRoot->base); - djui_base_set_location(&sDjuiRect->base, 64, 64); - djui_base_set_size(&sDjuiRect->base, 188, 64); - djui_base_set_color(&sDjuiRect->base, 255, 255, 255, 200); - djui_base_set_alignment(&sDjuiRect->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM); - - sDjuiRect2 = djui_rect_create(&sDjuiRect->base); - djui_base_set_location(&sDjuiRect2->base, 0, 0); - djui_base_set_size(&sDjuiRect2->base, 188 - 8, 64 - 8); - djui_base_set_alignment(&sDjuiRect2->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); - - sDjuiText = djui_text_create(&sDjuiRect2->base, "Host"); - djui_base_set_location(&sDjuiText->base, 0, 0); - djui_base_set_size(&sDjuiText->base, 188 - 8, 64 - 8); - djui_base_set_color(&sDjuiText->base, 111, 111, 111, 255); - djui_text_set_font_size(sDjuiText, 2); - djui_text_set_alignment(sDjuiText, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); - - struct DjuiRect* buttonContainer = djui_rect_create(&gDjuiRoot->base); - djui_base_set_alignment(&buttonContainer->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_BOTTOM); - djui_base_set_location(&buttonContainer->base, 64, 64); - djui_base_set_size(&buttonContainer->base, 200 + 16, (64 + 16) * 2.0f + 16); - djui_base_set_color(&buttonContainer->base, 0, 0, 0, 64); - djui_base_set_padding(&buttonContainer->base, 16, 16, 16, 16); - - struct DjuiButton* button1 = djui_button_create(&buttonContainer->base, "one"); - djui_base_set_location(&button1->base, 0, 0); - djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); - djui_base_set_size(&button1->base, 1.0f, 64); - - struct DjuiButton* button2 = djui_button_create(&buttonContainer->base, "two"); - djui_base_set_location(&button2->base, 0, 64 + 16); - djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); - djui_base_set_size(&button2->base, 1.0f, 64); + djui_panel_main_create(); } static void djui_debug_update(void) { + /*static struct DjuiImage* sDjuiImage = NULL; + static struct DjuiRect* sDjuiRect = NULL;; + static struct DjuiRect* sDjuiRect2 = NULL;; + static struct DjuiText* sDjuiText = NULL;; + if (sDjuiImage == NULL) { + struct DjuiRect* imageContainer = djui_rect_create(&gDjuiRoot->base); + djui_base_set_location(&imageContainer->base, 32, 32); + djui_base_set_size(&imageContainer->base, 128, 128); + djui_base_set_padding(&imageContainer->base, 48, 48, 48, 48); + + sDjuiImage = djui_image_create(&imageContainer->base, texture16x16, 16, 16, 16); + djui_base_set_location(&sDjuiImage->base, 0, 0); + djui_base_set_size(&sDjuiImage->base, 32, 32); + djui_base_set_size_type(&sDjuiImage->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE); + djui_base_set_size(&sDjuiImage->base, 1.0f, 1.0f); + + sDjuiRect = djui_rect_create(&gDjuiRoot->base); + djui_base_set_location(&sDjuiRect->base, 64, 64); + djui_base_set_size(&sDjuiRect->base, 188, 64); + djui_base_set_color(&sDjuiRect->base, 255, 255, 255, 200); + djui_base_set_alignment(&sDjuiRect->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM); + + sDjuiRect2 = djui_rect_create(&sDjuiRect->base); + djui_base_set_location(&sDjuiRect2->base, 0, 0); + djui_base_set_size(&sDjuiRect2->base, 188 - 8, 64 - 8); + djui_base_set_alignment(&sDjuiRect2->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + + sDjuiText = djui_text_create(&sDjuiRect2->base, "Host"); + djui_base_set_location(&sDjuiText->base, 0, 0); + djui_base_set_size(&sDjuiText->base, 188 - 8, 64 - 8); + djui_base_set_color(&sDjuiText->base, 111, 111, 111, 255); + djui_text_set_font_size(sDjuiText, 2); + djui_text_set_alignment(sDjuiText, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + }*/ static u32 sTimer = 0; sTimer++; + /*djui_base_set_size(&buttonContainer->base, + 512.0f + cos((sTimer) / 20.0f) * 256.0f, + buttonContainer->base.height.value);*/ /*djui_base_set_location(&sDjuiImage->base, 0.0f + cos((sTimer) / 30.0f) * 128.0f, 0.0f + fabs(sin((sTimer) / 30.0f)) * 128.0f);*/ - djui_base_set_color(&sDjuiImage->base, + /*djui_base_set_color(&sDjuiImage->base, 127.0f + sin((sTimer) / 13.0f) * 127.0f, 127.0f + sin((sTimer) / 17.0f) * 127.0f, 127.0f + sin((sTimer) / 23.0f) * 127.0f, @@ -105,7 +92,7 @@ static void djui_debug_update(void) { djui_base_set_location(&sDjuiRect2->base, 32.0f + cos((sTimer) / 10.0f) * 64.0f, - 32.0f + sin((sTimer) / 31.0f) * 64.0f); + 32.0f + sin((sTimer) / 31.0f) * 64.0f);*/ } static void djui_mouse_update(void) { @@ -118,9 +105,9 @@ static void djui_mouse_update(void) { djui_base_set_location(&sMouseCursor->base, mouse_window_x - 13, mouse_window_y - 13); if (mouse_window_buttons & 0b0001) { - djui_image_set_image(sMouseCursor, texture_hand_closed, 32, 32); + djui_image_set_image(sMouseCursor, texture_hand_closed, 32, 32, 16); } else { - djui_image_set_image(sMouseCursor, texture_hand_open, 32, 32); + djui_image_set_image(sMouseCursor, texture_hand_open, 32, 32, 16); } #endif } diff --git a/src/pc/djui/djui.h b/src/pc/djui/djui.h index 75ee0808..e3900398 100644 --- a/src/pc/djui/djui.h +++ b/src/pc/djui/djui.h @@ -4,6 +4,8 @@ #include #include #include +#include "game/game_init.h" +#include "game/ingame_menu.h" #include "djui_types.h" #include "djui_gfx.h" @@ -16,9 +18,9 @@ #include "djui_image.h" #include "djui_button.h" +#include "djui_flow_layout.h" -#include "game/game_init.h" -#include "game/ingame_menu.h" +#include "djui_panel_main.h" extern struct DjuiRoot* gDjuiRoot; diff --git a/src/pc/djui/djui_base.c b/src/pc/djui/djui_base.c index 9c741833..5ecfc534 100644 --- a/src/pc/djui/djui_base.c +++ b/src/pc/djui/djui_base.c @@ -1,7 +1,7 @@ #include #include "djui.h" -//////////////// + //////////////// // properties // //////////////// @@ -121,6 +121,9 @@ void djui_base_compute(struct DjuiBase* base) { f32 width = (base->width.type == DJUI_SVT_RELATIVE) ? parent->comp.width * base->width.value : base->width.value; f32 height = (base->height.type == DJUI_SVT_RELATIVE) ? parent->comp.height * base->height.value : base->height.value; + width = (base->width.type == DJUI_SVT_ASPECT_RATIO) ? height * base->width.value : width; + height = (base->height.type == DJUI_SVT_ASPECT_RATIO) ? width * base->height.value : height; + // horizontal alignment if (base->hAlign == DJUI_HALIGN_CENTER) { x += (parent->comp.width - width) / 2.0f; @@ -252,6 +255,10 @@ static void djui_base_render_border(struct DjuiBase* base) { void djui_base_render(struct DjuiBase* base) { if (!base->visible) { return; } + if (base->on_render_pre != NULL) { + base->on_render_pre(base); + } + struct DjuiBaseRect* comp = &base->comp; struct DjuiBaseRect* clip = &base->clip; @@ -277,6 +284,11 @@ void djui_base_render(struct DjuiBase* base) { struct DjuiBaseChild* child = base->child; while (child != NULL) { djui_base_render(child->base); + + if (base->on_child_render != NULL) { + base->on_child_render(base, child->base); + } + child = child->next; } } diff --git a/src/pc/djui/djui_base.h b/src/pc/djui/djui_base.h index ff7fe906..d2fc592d 100644 --- a/src/pc/djui/djui_base.h +++ b/src/pc/djui/djui_base.h @@ -41,6 +41,8 @@ struct DjuiBase { struct DjuiBaseRect comp; struct DjuiBaseRect clip; struct DjuiInteractable* interactable; + void (*on_child_render)(struct DjuiBase*, struct DjuiBase*); + void (*on_render_pre)(struct DjuiBase*); void (*render)(struct DjuiBase*); void (*destroy)(struct DjuiBase*); }; diff --git a/src/pc/djui/djui_flow_layout.c b/src/pc/djui/djui_flow_layout.c new file mode 100644 index 00000000..da886ec8 --- /dev/null +++ b/src/pc/djui/djui_flow_layout.c @@ -0,0 +1,61 @@ +#include "djui.h" +#include + + //////////////// + // properties // +//////////////// + +void djui_flow_layout_set_flow_direction(struct DjuiFlowLayout* layout, enum DjuiFlowDirection flowDirection) { + layout->flowDirection = flowDirection; +} + +void djui_flow_layout_set_margin(struct DjuiFlowLayout* layout, f32 margin) { + layout->margin.value = margin; +} + +void djui_flow_layout_set_margin_type(struct DjuiFlowLayout* layout, enum DjuiScreenValueType marginType) { + layout->margin.type = marginType; +} + + //////////// + // events // +//////////// + +static void djui_flow_layout_on_child_render(struct DjuiBase* base, struct DjuiBase* child) { + struct DjuiFlowLayout* layout = (struct DjuiFlowLayout*)base; + switch (layout->flowDirection) { + case DJUI_FLOW_DIR_DOWN: + base->comp.y += (child->comp.height + layout->margin.value); + base->comp.height -= (child->comp.height + layout->margin.value); + break; + case DJUI_FLOW_DIR_UP: + base->comp.height -= (child->comp.height + layout->margin.value); + break; + case DJUI_FLOW_DIR_RIGHT: + base->comp.x += (child->comp.width + layout->margin.value); + base->comp.width -= (child->comp.width + layout->margin.value); + break; + case DJUI_FLOW_DIR_LEFT: + base->comp.width -= (child->comp.width + layout->margin.value); + break; + } +} + +static void djui_flow_layout_destroy(struct DjuiBase* base) { + struct DjuiFlowLayout* layout = (struct DjuiFlowLayout*)base; + free(layout); +} + +struct DjuiFlowLayout* djui_flow_layout_create(struct DjuiBase* parent) { + struct DjuiFlowLayout* layout = malloc(sizeof(struct DjuiFlowLayout)); + struct DjuiBase* base = &layout->base; + + djui_base_init(parent, base, djui_rect_render, djui_flow_layout_destroy); + djui_base_set_size(base, 256, 512); + + djui_flow_layout_set_flow_direction(layout, DJUI_FLOW_DIR_DOWN); + djui_flow_layout_set_margin(layout, 8); + + layout->base.on_child_render = djui_flow_layout_on_child_render; + return layout; +} diff --git a/src/pc/djui/djui_flow_layout.h b/src/pc/djui/djui_flow_layout.h new file mode 100644 index 00000000..733f7b58 --- /dev/null +++ b/src/pc/djui/djui_flow_layout.h @@ -0,0 +1,15 @@ +#pragma once +#include "djui.h" + +#pragma pack(1) +struct DjuiFlowLayout { + struct DjuiBase base; + enum DjuiFlowDirection flowDirection; + struct DjuiScreenValue margin; +}; + +void djui_flow_layout_set_flow_direction(struct DjuiFlowLayout* layout, enum DjuiFlowDirection flowDirection); +void djui_flow_layout_set_margin(struct DjuiFlowLayout* layout, f32 margin); +void djui_flow_layout_set_margin_type(struct DjuiFlowLayout* layout, enum DjuiScreenValueType marginType); + +struct DjuiFlowLayout* djui_flow_layout_create(struct DjuiBase* parent); diff --git a/src/pc/djui/djui_gbi.h b/src/pc/djui/djui_gbi.h index fa5c5e14..d718f929 100644 --- a/src/pc/djui/djui_gbi.h +++ b/src/pc/djui/djui_gbi.h @@ -12,11 +12,11 @@ _g->words.w1 = _SHIFTL(x2, 16, 8) | _SHIFTL(y2, 8, 8); \ } -#define gSetOverrideDjui(pkt, cmd, texture, w, h) \ +#define gSetOverrideDjui(pkt, cmd, texture, w, h, bitSize) \ { \ Gfx *_g = (Gfx *)(pkt); \ _g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL(w, 16, 8) | \ - _SHIFTL(h, 8, 8); \ + _SHIFTL(h, 8, 8) | _SHIFTL(bitSize, 0, 8); \ _g->words.w1 = (uintptr_t)(texture); \ } @@ -25,5 +25,5 @@ _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) +#define gDPSetTextureClippingDjui(pkt, rot, x1, y1, x2, y2) gSetClippingDjui(pkt, G_TEXCLIP_DJUI, rot, x1, y1, x2, y2) +#define gDPSetTextureOverrideDjui(pkt, texture, w, h, bitSize) gSetOverrideDjui(pkt, G_TEXOVERRIDE_DJUI, texture, w, h, bitSize) diff --git a/src/pc/djui/djui_gfx.c b/src/pc/djui/djui_gfx.c index 4804f8ef..e31060dd 100644 --- a/src/pc/djui/djui_gfx.c +++ b/src/pc/djui/djui_gfx.c @@ -94,8 +94,24 @@ const Gfx dl_djui_image[] = { gsSPEndDisplayList(), }; -void djui_gfx_render_texture(const u8* texture, u16 w, u16 h) { - gDPSetTextureOverrideDjui(gDisplayListHead++, texture, w, h); +static u8 djui_gfx_power_of_two(u32 value) { + switch (value) { + case 2: return 1; + case 4: return 2; + case 8: return 3; + case 16: return 4; + case 32: return 5; + case 64: return 6; + case 128: return 7; + case 256: return 8; + case 512: return 9; + case 1024: return 10; + default: return 11; + } +} + +void djui_gfx_render_texture(const u8* texture, u32 w, u32 h, u32 bitSize) { + gDPSetTextureOverrideDjui(gDisplayListHead++, texture, djui_gfx_power_of_two(w), djui_gfx_power_of_two(h), bitSize); gSPDisplayList(gDisplayListHead++, dl_djui_image); } diff --git a/src/pc/djui/djui_gfx.h b/src/pc/djui/djui_gfx.h index d6583fe0..e9184739 100644 --- a/src/pc/djui/djui_gfx.h +++ b/src/pc/djui/djui_gfx.h @@ -11,7 +11,7 @@ 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_render_texture(const u8* texture, u32 w, u32 h, u32 bitSize); void djui_gfx_position_translate(f32* x, f32* y); void djui_gfx_scale_translate(f32* width, f32* height); diff --git a/src/pc/djui/djui_image.c b/src/pc/djui/djui_image.c index cc43d4af..4de317ba 100644 --- a/src/pc/djui/djui_image.c +++ b/src/pc/djui/djui_image.c @@ -6,10 +6,11 @@ // properties // //////////////// -void djui_image_set_image(struct DjuiImage* image, const u8* texture, u16 textureWidth, u16 textureHeight) { +void djui_image_set_image(struct DjuiImage* image, const u8* texture, u16 textureWidth, u16 textureHeight, u16 textureBitSize) { image->texture = texture; image->textureWidth = textureWidth; image->textureHeight = textureHeight; + image->textureBitSize = textureBitSize; } //////////// @@ -36,7 +37,7 @@ static void djui_image_render(struct DjuiBase* base) { // 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); + djui_gfx_render_texture(image->texture, image->textureWidth, image->textureHeight, image->textureBitSize); } gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); @@ -47,13 +48,13 @@ static void djui_image_destroy(struct DjuiBase* base) { free(image); } -struct DjuiImage* djui_image_create(struct DjuiBase* parent, const u8* texture, u16 textureWidth, u16 textureHeight) { +struct DjuiImage* djui_image_create(struct DjuiBase* parent, const u8* texture, u16 textureWidth, u16 textureHeight, u16 textureBitSize) { 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); + djui_image_set_image(image, texture, textureWidth, textureHeight, textureBitSize); return image; } diff --git a/src/pc/djui/djui_image.h b/src/pc/djui/djui_image.h index 9bdecc19..0e640cdd 100644 --- a/src/pc/djui/djui_image.h +++ b/src/pc/djui/djui_image.h @@ -7,8 +7,9 @@ struct DjuiImage { const u8* texture; u16 textureWidth; u16 textureHeight; + u16 textureBitSize; }; -void djui_image_set_image(struct DjuiImage* image, const u8* texture, u16 textureWidth, u16 textureHeight); +void djui_image_set_image(struct DjuiImage* image, const u8* texture, u16 textureWidth, u16 textureHeight, u16 textureBitSize); -struct DjuiImage* djui_image_create(struct DjuiBase* parent, const u8* texture, u16 textureWidth, u16 textureHeight); +struct DjuiImage* djui_image_create(struct DjuiBase* parent, const u8* texture, u16 textureWidth, u16 textureHeight, u16 textureBitSize); diff --git a/src/pc/djui/djui_panel_main.c b/src/pc/djui/djui_panel_main.c new file mode 100644 index 00000000..b423e932 --- /dev/null +++ b/src/pc/djui/djui_panel_main.c @@ -0,0 +1,70 @@ +#include "djui.h" + +ALIGNED8 static u8 texture_title[] = { +#include "textures/segment2/custom_title.rgba32.inc.c" +}; + +struct DjuiRect* sTitleContainer = NULL; +struct DjuiFlowLayout* sButtonContainer = NULL; +struct DjuiText* sVersionText = NULL; + +static void djui_panel_main_render_pre(struct DjuiBase* base) { + sTitleContainer->base.height.value = sButtonContainer->base.clip.y - sTitleContainer->base.clip.y; + sVersionText->base.height.value = sTitleContainer->base.height.value; +} + +void djui_panel_main_create(void) { + struct DjuiRect* menuContainer = djui_rect_create(&gDjuiRoot->base); + djui_base_set_size_type(&menuContainer->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_RELATIVE); + djui_base_set_size(&menuContainer->base, 512.0f + (16 * 2.0f), 1.0f); + djui_base_set_color(&menuContainer->base, 0, 0, 0, 230); + djui_base_set_border_color(&menuContainer->base, 0, 0, 0, 200); + djui_base_set_border_width(&menuContainer->base, 8); + djui_base_set_padding(&menuContainer->base, 16, 16, 16, 16); + { + sButtonContainer = djui_flow_layout_create(&menuContainer->base); + djui_base_set_alignment(&sButtonContainer->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + djui_base_set_size_type(&sButtonContainer->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&sButtonContainer->base, 1.0f, 292); + djui_base_set_color(&sButtonContainer->base, 0, 0, 0, 0); + djui_flow_layout_set_margin(sButtonContainer, 16); + djui_flow_layout_set_flow_direction(sButtonContainer, DJUI_FLOW_DIR_DOWN); + { + struct DjuiButton* button1 = djui_button_create(&sButtonContainer->base, "Host"); + djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&button1->base, 1.0f, 64); + + struct DjuiButton* button2 = djui_button_create(&sButtonContainer->base, "Join"); + djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&button2->base, 1.0f, 64); + + struct DjuiButton* button3 = djui_button_create(&sButtonContainer->base, "Options"); + djui_base_set_size_type(&button3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&button3->base, 1.0f, 64); + + struct DjuiButton* button4 = djui_button_create(&sButtonContainer->base, "Quit"); + djui_base_set_size_type(&button4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&button4->base, 1.0f, 64); + } + + sTitleContainer = djui_rect_create(&menuContainer->base); + djui_base_set_size_type(&sTitleContainer->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&sTitleContainer->base, 1.0f, 1.0f); + djui_base_set_color(&sTitleContainer->base, 0, 0, 0, 0); + sTitleContainer->base.on_render_pre = djui_panel_main_render_pre; + { + struct DjuiImage* title = djui_image_create(&sTitleContainer->base, texture_title, 512, 128, 32); + djui_base_set_size(&title->base, 1.0f, 128.0f / 512.0f); + djui_base_set_size_type(&title->base, DJUI_SVT_RELATIVE, DJUI_SVT_ASPECT_RATIO); + djui_base_set_alignment(&title->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + } + + sVersionText = djui_text_create(&menuContainer->base, "version - unst 5"); + djui_base_set_alignment(&sVersionText->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM); + djui_base_set_size_type(&sVersionText->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&sVersionText->base, 1.0f, 1.0f); + djui_base_set_color(&sVersionText->base, 50, 50, 50, 255); + djui_text_set_alignment(sVersionText, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + } + +} diff --git a/src/pc/djui/djui_panel_main.h b/src/pc/djui/djui_panel_main.h new file mode 100644 index 00000000..495ad48b --- /dev/null +++ b/src/pc/djui/djui_panel_main.h @@ -0,0 +1,4 @@ +#pragma once +#include "djui.h" + +void djui_panel_main_create(void); diff --git a/src/pc/djui/djui_rect.c b/src/pc/djui/djui_rect.c index 595c96ff..a496a5e2 100644 --- a/src/pc/djui/djui_rect.c +++ b/src/pc/djui/djui_rect.c @@ -4,7 +4,7 @@ // events // //////////// -static void djui_rect_render(struct DjuiBase* base) { +void djui_rect_render(struct DjuiBase* base) { struct DjuiBaseRect* clip = &base->clip; // translate position diff --git a/src/pc/djui/djui_rect.h b/src/pc/djui/djui_rect.h index 2d958567..3b8f7fcd 100644 --- a/src/pc/djui/djui_rect.h +++ b/src/pc/djui/djui_rect.h @@ -6,4 +6,5 @@ struct DjuiRect { struct DjuiBase base; }; +void djui_rect_render(struct DjuiBase* base); struct DjuiRect* djui_rect_create(struct DjuiBase* parent); diff --git a/src/pc/djui/djui_types.h b/src/pc/djui/djui_types.h index 9d49717f..3c5bcbdb 100644 --- a/src/pc/djui/djui_types.h +++ b/src/pc/djui/djui_types.h @@ -9,7 +9,8 @@ struct DjuiColor { u8 a; }; -enum DjuiScreenValueType { DJUI_SVT_ABSOLUTE, DJUI_SVT_RELATIVE }; +enum DjuiScreenValueType { DJUI_SVT_ABSOLUTE, DJUI_SVT_RELATIVE, DJUI_SVT_ASPECT_RATIO }; +enum DjuiFlowDirection { DJUI_FLOW_DIR_DOWN, DJUI_FLOW_DIR_UP, DJUI_FLOW_DIR_RIGHT, DJUI_FLOW_DIR_LEFT }; #pragma pack(1) struct DjuiScreenValue { diff --git a/src/pc/gfx/gfx_pc.c b/src/pc/gfx/gfx_pc.c index 7aece14b..5e83bee2 100644 --- a/src/pc/gfx/gfx_pc.c +++ b/src/pc/gfx/gfx_pc.c @@ -1862,17 +1862,9 @@ 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 uint32_t sDjuiOverrideW = 0; +static uint32_t sDjuiOverrideH = 0; +static uint32_t sDjuiOverrideB = 0; static void djui_gfx_dp_execute_clipping(void) { if (!sDjuiClip) { return; } @@ -1949,23 +1941,37 @@ static void djui_gfx_dp_execute_clipping(void) { } } -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; + // gsDPSetTextureImage + uint8_t sizeLoadBlock = (sDjuiOverrideB == 32) ? 3 : 2; rdp.texture_to_load.addr = sDjuiOverrideTexture; + rdp.texture_to_load.siz = sizeLoadBlock; + + // gsDPSetTile + rdp.texture_tile.siz = sizeLoadBlock; + + // gsDPLoadBlock + uint32_t wordSizeShift = (sDjuiOverrideB == 32) ? 2 : 1; + uint32_t lrs = (sDjuiOverrideW * sDjuiOverrideH) - 1; + uint32_t sizeBytes = (lrs + 1) << wordSizeShift; + rdp.loaded_texture[rdp.texture_to_load.tile_number].size_bytes = sizeBytes; rdp.loaded_texture[rdp.texture_to_load.tile_number].addr = rdp.texture_to_load.addr; + rdp.textures_changed[rdp.texture_to_load.tile_number] = true; + + // gsDPSetTile 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; + + // gsDPSetTileSize + /*rdp.texture_tile.uls = 0; + rdp.texture_tile.ult = 0; + rdp.texture_tile.lrs = (sDjuiOverrideW - 1) << G_TEXTURE_IMAGE_FRAC; + rdp.texture_tile.lrt = (sDjuiOverrideH - 1) << G_TEXTURE_IMAGE_FRAC;*/ + rdp.textures_changed[0] = true; + rdp.textures_changed[1] = true; } static void djui_gfx_dp_execute_djui(uint32_t opcode) { @@ -1975,6 +1981,23 @@ static void djui_gfx_dp_execute_djui(uint32_t opcode) { } } +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_set_override(void* texture, uint32_t w, uint32_t h, uint32_t b) { + sDjuiOverrideTexture = texture; + sDjuiOverrideW = w; + sDjuiOverrideH = h; + sDjuiOverrideB = b; + sDjuiOverride = (texture != NULL); +} + void djui_gfx_run_dl(Gfx* cmd) { uint32_t opcode = cmd->words.w0 >> 24; switch (opcode) { @@ -1982,7 +2005,7 @@ void djui_gfx_run_dl(Gfx* cmd) { 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)); + djui_gfx_dp_set_override(seg_addr(cmd->words.w1), 1 << C0(16, 8), 1 << C0(8, 8), C0(0, 8)); break; case G_EXECUTE_DJUI: djui_gfx_dp_execute_djui(cmd->words.w1); diff --git a/textures/segment2/custom_title.rgba32.png b/textures/segment2/custom_title.rgba32.png new file mode 100644 index 0000000000000000000000000000000000000000..4300247468b8c33a46a106f43f3bd01ec0106f0b GIT binary patch literal 16739 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 literal 0 HcmV?d00001