diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj index 8c66ea60..8fb030cb 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj +++ b/build-windows-visual-studio/sm64ex.vcxproj @@ -71,7 +71,7 @@ true - ../;../include/;../src/;$(IncludePath) + ../;../include/;../src/;C:/msys64/mingw64/include;$(IncludePath) true @@ -87,7 +87,7 @@ Level3 true - _DEBUG;_CONSOLE;WINSOCK;DEBUG;%(PreprocessorDefinitions) + _DEBUG;_CONSOLE;WINSOCK;DEBUG;CAPI_SDL2;WAPI_SDL2;RAPI_GL;F3DEX_GBI_2;_LANGUAGE_C;BETTERCAMERA;VERSION_US;%(PreprocessorDefinitions) true @@ -3938,13 +3938,15 @@ - + + + @@ -4365,6 +4367,7 @@ + diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters index 8ef0b86e..7ad6a2fc 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj.filters +++ b/build-windows-visual-studio/sm64ex.vcxproj.filters @@ -14811,9 +14811,6 @@ Source Files\src\pc\controller - - Source Files\src\pc\controller - Source Files\src\pc\discord @@ -15174,6 +15171,15 @@ Source Files\src\pc\djui\components + + Source Files\src\pc\controller + + + Source Files\src\pc\controller + + + Source Files\src\pc\djui\components + @@ -16177,5 +16183,8 @@ Source Files\src\pc\djui\components + + Source Files\src\pc\djui\components + \ No newline at end of file diff --git a/src/game/game_init.c b/src/game/game_init.c index c08f3547..8f518ad4 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -259,6 +259,9 @@ void end_master_display_list(void) { draw_profiler(); } + extern void djui_render(void); + djui_render(); + gDPFullSync(gDisplayListHead++); gSPEndDisplayList(gDisplayListHead++); diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index 427466d3..1b120d67 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -26,7 +26,6 @@ #include "macros.h" #include "pc/cheats.h" #include "pc/network/network.h" -#include "pc/djui/djui.h" #ifdef BETTERCAMERA #include "bettercamera.h" #endif @@ -3202,7 +3201,6 @@ s16 render_menus_and_dialogs() { create_dl_ortho_matrix(); render_chat(); - djui_render(); if (gMenuMode != -1) { switch (gMenuMode) { diff --git a/src/pc/controller/controller_mouse.h b/src/pc/controller/controller_mouse.h index 8ef01196..43566330 100644 --- a/src/pc/controller/controller_mouse.h +++ b/src/pc/controller/controller_mouse.h @@ -6,6 +6,11 @@ extern int mouse_x; extern int mouse_y; +extern int mouse_window_buttons; +extern int mouse_window_x; +extern int mouse_window_y; + + #define VK_BASE_MOUSE 0x2000 extern struct ControllerAPI controller_mouse; diff --git a/src/pc/controller/controller_sdl.h b/src/pc/controller/controller_sdl.h index bbe8a62c..d858af6c 100644 --- a/src/pc/controller/controller_sdl.h +++ b/src/pc/controller/controller_sdl.h @@ -7,4 +7,6 @@ extern struct ControllerAPI controller_sdl; +void controller_sdl_read_mouse_window(void); + #endif diff --git a/src/pc/controller/controller_sdl1.c b/src/pc/controller/controller_sdl1.c index 37316674..d944b177 100644 --- a/src/pc/controller/controller_sdl1.c +++ b/src/pc/controller/controller_sdl1.c @@ -41,6 +41,10 @@ enum { int mouse_x; int mouse_y; +int mouse_window_buttons; +int mouse_window_x; +int mouse_window_y; + #ifdef BETTERCAMERA extern u8 newcam_mouse; #endif @@ -238,6 +242,11 @@ static void controller_sdl_read(OSContPad *pad) { } } +void controller_sdl_read_mouse_window(void) { + if (!init_ok) { return; } + mouse_window_buttons = SDL_GetMouseState(&mouse_window_x, &mouse_window_y); +} + static void controller_sdl_rumble_play(f32 strength, f32 length) { } static void controller_sdl_rumble_stop(void) { } diff --git a/src/pc/controller/controller_sdl2.c b/src/pc/controller/controller_sdl2.c index a71a82eb..8bdf9648 100644 --- a/src/pc/controller/controller_sdl2.c +++ b/src/pc/controller/controller_sdl2.c @@ -31,6 +31,10 @@ int mouse_x; int mouse_y; +int mouse_window_buttons; +int mouse_window_x; +int mouse_window_y; + #ifdef BETTERCAMERA extern u8 newcam_mouse; #endif @@ -156,7 +160,7 @@ static void controller_sdl_read(OSContPad *pad) { SDL_SetRelativeMouseMode(SDL_TRUE); else SDL_SetRelativeMouseMode(SDL_FALSE); - + u32 mouse = SDL_GetRelativeMouseState(&mouse_x, &mouse_y); for (u32 i = 0; i < num_mouse_binds; ++i) @@ -262,6 +266,11 @@ static void controller_sdl_read(OSContPad *pad) { } } +void controller_sdl_read_mouse_window(void) { + if (!init_ok) { return; } + mouse_window_buttons = SDL_GetMouseState(&mouse_window_x, &mouse_window_y); +} + static void controller_sdl_rumble_play(f32 strength, f32 length) { if (sdl_haptic) SDL_HapticRumblePlay(sdl_haptic, strength, (u32)(length * 1000.0f)); diff --git a/src/pc/djui/djui.c b/src/pc/djui/djui.c index 23e2d798..bd3272f8 100644 --- a/src/pc/djui/djui.c +++ b/src/pc/djui/djui.c @@ -1,81 +1,160 @@ #include "djui.h" +#include "../debuglog.h" -struct DjuiRoot* gDjuiRoot = NULL; +#include "src/pc/controller/controller_sdl.h" +#include "src/pc/controller/controller_mouse.h" 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; +ALIGNED8 u8 texture_hand_open[] = { +#include "textures/intro_raw/hand_open.rgba16.inc.c" +}; - if (gDjuiRoot == NULL) { - gDjuiRoot = djui_root_create(); +static Gfx* sSavedDisplayListHead = 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, 32, 32, 32, 32); +struct DjuiRoot* gDjuiRoot = NULL; +struct DjuiBase* gDjuiBaseHovered = NULL; +static struct DjuiImage* sMouseCursor = NULL; - 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); +// v REMOVE ME v +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; +// ^ REMOVE ME ^ - ////////////// +static void djui_init(void) { + gDjuiRoot = djui_root_create(); - 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); + sMouseCursor = djui_image_create(NULL, texture_hand_open, 32, 32); + djui_base_set_location(&sMouseCursor->base, 0, 0); + djui_base_set_size(&sMouseCursor->base, 64, 64); - 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* 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); - sDjuiButton = djui_button_create(&gDjuiRoot->base, "button"); - djui_base_set_alignment(&sDjuiButton->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_BOTTOM); - djui_base_set_location(&sDjuiButton->base, 64, 64); + 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); + + sDjuiButton = djui_button_create(&gDjuiRoot->base, "button"); + djui_base_set_alignment(&sDjuiButton->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_BOTTOM); + djui_base_set_location(&sDjuiButton->base, 64, 64); +} + +static void djui_debug_update(void) { + static u32 sTimer = 0; + sTimer++; + /*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, + 127.0f + sin((sTimer) / 13.0f) * 127.0f, + 127.0f + sin((sTimer) / 17.0f) * 127.0f, + 127.0f + sin((sTimer) / 23.0f) * 127.0f, + 255); + + djui_base_set_location(&sDjuiRect2->base, + 32.0f + cos((sTimer) / 10.0f) * 64.0f, + 32.0f + sin((sTimer) / 31.0f) * 64.0f); + + /*djui_base_set_size(&sDjuiButton->base, + 200.0f + cos((sTimer) / 10.0f) * 64.0f, + 64.0f + sin((sTimer) / 10.0f) * 77.0f);*/ + //sDjuiButton->base.visible = (sTimer % 10) < 5; +} + +static void djui_mouse_update_active(struct DjuiBase* base) { + if (!base->visible) { return; } + + struct DjuiBaseRect* clip = &base->clip; + if (mouse_window_x < clip->x) { return; } + if (mouse_window_x > clip->x + clip->width) { return; } + if (mouse_window_y < clip->y) { return; } + if (mouse_window_y > clip->y + clip->height) { return; } + + if (base->interactable != NULL) { gDjuiBaseHovered = base; } + + // check all children + struct DjuiBaseChild* child = base->child; + while (child != NULL) { + djui_mouse_update_active(child->base); + child = child->next; } +} + +static void djui_mouse_update(void) { +#if defined(CAPI_SDL2) || defined(CAPI_SDL1) + controller_sdl_read_mouse_window(); + + struct DjuiBase* lastHovered = gDjuiBaseHovered; + gDjuiBaseHovered = NULL; + djui_mouse_update_active(&gDjuiRoot->base); + if (lastHovered != gDjuiBaseHovered) { + djui_interactable_on_hover_end(lastHovered); + } + djui_interactable_on_hover_begin(gDjuiBaseHovered); + + djui_base_set_location(&sMouseCursor->base, mouse_window_x - 13, mouse_window_y - 13); + if (gDjuiBaseHovered) { + djui_base_set_color(&sMouseCursor->base, 255, 255, 255, 255); + } else { + djui_base_set_color(&sMouseCursor->base, 233, 233, 255, 255); + } +#endif +} + +void djui_render_patch(void) { + // reset the head and re-render DJUI + if (sSavedDisplayListHead == NULL) { return; } + gDisplayListHead = sSavedDisplayListHead; + djui_render(); + gDPFullSync(gDisplayListHead++); + gSPEndDisplayList(gDisplayListHead++); +} + +void djui_render(void) { + if (gDjuiRoot == NULL) { djui_init(); } + sSavedDisplayListHead = gDisplayListHead; + create_dl_ortho_matrix(); + + djui_mouse_update(); + djui_debug_update(); djui_base_render(&gDjuiRoot->base); - - if (sDjuiRect2 != NULL) { - static u32 sTimer = 0; - sTimer++; - /*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, - 127.0f + sin((sTimer) / 13.0f) * 127.0f, - 127.0f + sin((sTimer) / 17.0f) * 127.0f, - 127.0f + sin((sTimer) / 23.0f) * 127.0f, - 255); - - djui_base_set_location(&sDjuiRect2->base, - 32.0f + cos((sTimer) / 10.0f) * 64.0f, - 32.0f + sin((sTimer) / 31.0f) * 64.0f); - - /*djui_base_set_size(&sDjuiButton->base, - 200.0f + cos((sTimer) / 10.0f) * 64.0f, - 64.0f + sin((sTimer) / 10.0f) * 77.0f);*/ - } -} \ No newline at end of file + djui_base_render(&sMouseCursor->base); +} diff --git a/src/pc/djui/djui.h b/src/pc/djui/djui.h index 5d6c3148..3a270fa2 100644 --- a/src/pc/djui/djui.h +++ b/src/pc/djui/djui.h @@ -8,6 +8,7 @@ #include "djui_types.h" #include "djui_gfx.h" #include "djui_base.h" +#include "djui_interactable.h" #include "djui_root.h" #include "djui_rect.h" @@ -20,5 +21,7 @@ #include "game/ingame_menu.h" extern struct DjuiRoot* gDjuiRoot; +extern struct DjuiBase* gDjuiBaseHovered; +void djui_render_patch(void); void djui_render(void); diff --git a/src/pc/djui/djui_base.c b/src/pc/djui/djui_base.c index 48a8658d..9c741833 100644 --- a/src/pc/djui/djui_base.c +++ b/src/pc/djui/djui_base.c @@ -5,6 +5,10 @@ // properties // //////////////// +void djui_base_set_visible(struct DjuiBase* base, bool visible) { + base->visible = visible; +} + void djui_base_set_location(struct DjuiBase* base, f32 x, f32 y) { base->x.value = x; base->y.value = y; @@ -312,6 +316,12 @@ void djui_base_destroy(struct DjuiBase* base) { child = nextChild->next; } + // deallocate interactable + if (base->interactable != NULL) { + free(base->interactable); + base->interactable = NULL; + } + // destroy this base->destroy(base); } diff --git a/src/pc/djui/djui_base.h b/src/pc/djui/djui_base.h index c0058136..ff7fe906 100644 --- a/src/pc/djui/djui_base.h +++ b/src/pc/djui/djui_base.h @@ -40,10 +40,12 @@ struct DjuiBase { enum DjuiVAlign vAlign; struct DjuiBaseRect comp; struct DjuiBaseRect clip; + struct DjuiInteractable* interactable; void (*render)(struct DjuiBase*); void (*destroy)(struct DjuiBase*); }; +void djui_base_set_visible(struct DjuiBase* base, bool visible); void djui_base_set_location(struct DjuiBase* base, f32 x, f32 y); void djui_base_set_location_type(struct DjuiBase* base, enum DjuiScreenValueType xType, enum DjuiScreenValueType yType); void djui_base_set_size(struct DjuiBase* base, f32 width, f32 height); diff --git a/src/pc/djui/djui_button.c b/src/pc/djui/djui_button.c index 36649d2c..51fe5192 100644 --- a/src/pc/djui/djui_button.c +++ b/src/pc/djui/djui_button.c @@ -1,5 +1,17 @@ #include "djui.h" +static void djui_button_on_hover_begin(struct DjuiBase* base) { + struct DjuiButton* button = (struct DjuiButton*)base; + djui_base_set_border_color(base, 0, 120, 215, 255); + djui_base_set_color(&button->rect->base, 229, 241, 251, 255); +} + +static void djui_button_on_hover_end(struct DjuiBase* base) { + struct DjuiButton* button = (struct DjuiButton*)base; + djui_base_set_border_color(base, 173, 173, 173, 255); + djui_base_set_color(&button->rect->base, 200, 200, 200, 255); +} + static void djui_button_destroy(struct DjuiBase* base) { struct DjuiButton* button = (struct DjuiButton*)base; free(button); @@ -13,6 +25,7 @@ struct DjuiButton* djui_button_create(struct DjuiBase* parent, const char* messa djui_base_set_size(base, 200, 64); djui_base_set_border_width(base, 2); djui_base_set_border_color(base, 173, 173, 173, 255); + djui_interactable_create(base, djui_button_on_hover_begin, djui_button_on_hover_end); struct DjuiRect* rect = djui_rect_create(&button->base); djui_base_set_size_type(&rect->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE); diff --git a/src/pc/djui/djui_interactable.c b/src/pc/djui/djui_interactable.c new file mode 100644 index 00000000..b285c9dc --- /dev/null +++ b/src/pc/djui/djui_interactable.c @@ -0,0 +1,31 @@ +#include +#include "djui.h" + +void djui_interactable_on_hover_begin(struct DjuiBase* base) { + if (base == NULL) { return; } + if (base->interactable == NULL) { return; } + if (base->interactable->on_hover_begin == NULL) { return; } + base->interactable->on_hover_begin(base); +} + +void djui_interactable_on_hover_end(struct DjuiBase* base) { + if (base == NULL) { return; } + if (base->interactable == NULL) { return; } + if (base->interactable->on_hover_begin == NULL) { return; } + base->interactable->on_hover_end(base); +} + +void djui_interactable_create(struct DjuiBase* base, + void (*on_hover_begin)(struct DjuiBase*), + void (*on_hover_end)(struct DjuiBase*)) { + + if (base->interactable != NULL) { + free(base->interactable); + } + + struct DjuiInteractable* interactable = malloc(sizeof(struct DjuiInteractable)); + interactable->on_hover_begin = on_hover_begin; + interactable->on_hover_end = on_hover_end; + + base->interactable = interactable; +} \ No newline at end of file diff --git a/src/pc/djui/djui_interactable.h b/src/pc/djui/djui_interactable.h new file mode 100644 index 00000000..057844f2 --- /dev/null +++ b/src/pc/djui/djui_interactable.h @@ -0,0 +1,16 @@ +#pragma once +#include "djui.h" +#include "djui_base.h" + +#pragma pack(1) +struct DjuiInteractable { + void (*on_hover_begin)(struct DjuiBase*); + void (*on_hover_end)(struct DjuiBase*); +}; + +void djui_interactable_on_hover_begin(struct DjuiBase* base); +void djui_interactable_on_hover_end(struct DjuiBase* base); + +void djui_interactable_create(struct DjuiBase* base, + void (*on_hover_begin)(struct DjuiBase*), + void (*on_hover_end)(struct DjuiBase*)); diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index fcb0bbea..198bda37 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -97,6 +97,7 @@ static inline void patch_interpolations(void) { extern void patch_interpolated_paintings(void); extern void patch_interpolated_bubble_particles(void); extern void patch_interpolated_snow_particles(void); + extern void djui_render_patch(void); mtx_patch_interpolated(); patch_screen_transition_interpolated(); patch_title_screen_scales(); @@ -105,6 +106,7 @@ static inline void patch_interpolations(void) { patch_interpolated_paintings(); patch_interpolated_bubble_particles(); patch_interpolated_snow_particles(); + djui_render_patch(); } void produce_one_frame(void) { @@ -311,7 +313,9 @@ void main_func(void) { #ifdef DISCORDRPC discord_update_rich_presence(); #endif +#ifdef DEBUG fflush(stdout); +#endif } #endif }