DJUI: Rendering, interactable, and mouse adjustments

Made DJUI render at 60 fps
Added mouse cursor and hooks in SDL for capturing the window-relative mouse position
Started creating an interable system where elements can respond to events such as on_mouse_hover
This commit is contained in:
MysterD 2021-06-19 18:22:44 -07:00
parent 63e9621d56
commit 6e23c952f9
16 changed files with 265 additions and 69 deletions

View file

@ -71,7 +71,7 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>../;../include/;../src/;$(IncludePath)</IncludePath>
<IncludePath>../;../include/;../src/;C:/msys64/mingw64/include;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
@ -87,7 +87,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;WINSOCK;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;WINSOCK;DEBUG;CAPI_SDL2;WAPI_SDL2;RAPI_GL;F3DEX_GBI_2;_LANGUAGE_C;BETTERCAMERA;VERSION_US;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
@ -3938,13 +3938,15 @@
<ClCompile Include="..\src\pc\controller\controller_keyboard.c" />
<ClCompile Include="..\src\pc\controller\controller_keyboard_debug.c" />
<ClCompile Include="..\src\pc\controller\controller_recorded_tas.c" />
<ClCompile Include="..\src\pc\controller\controller_sdl.c" />
<ClCompile Include="..\src\pc\controller\controller_sdl1.c" />
<ClCompile Include="..\src\pc\controller\controller_sdl2.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_interactable.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" />
@ -4365,6 +4367,7 @@
<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_interactable.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" />

View file

@ -14811,9 +14811,6 @@
<ClCompile Include="..\src\pc\controller\controller_recorded_tas.c">
<Filter>Source Files\src\pc\controller</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\controller\controller_sdl.c">
<Filter>Source Files\src\pc\controller</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\discord\discordrpc.c">
<Filter>Source Files\src\pc\discord</Filter>
</ClCompile>
@ -15174,6 +15171,15 @@
<ClCompile Include="..\src\pc\djui\djui_button.c">
<Filter>Source Files\src\pc\djui\components</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\controller\controller_sdl1.c">
<Filter>Source Files\src\pc\controller</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\controller\controller_sdl2.c">
<Filter>Source Files\src\pc\controller</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_interactable.c">
<Filter>Source Files\src\pc\djui\components</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\actors\common0.h">
@ -16177,5 +16183,8 @@
<ClInclude Include="..\src\pc\djui\djui_button.h">
<Filter>Source Files\src\pc\djui\components</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_interactable.h">
<Filter>Source Files\src\pc\djui\components</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -259,6 +259,9 @@ void end_master_display_list(void) {
draw_profiler();
}
extern void djui_render(void);
djui_render();
gDPFullSync(gDisplayListHead++);
gSPEndDisplayList(gDisplayListHead++);

View file

@ -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) {

View file

@ -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;

View file

@ -7,4 +7,6 @@
extern struct ControllerAPI controller_sdl;
void controller_sdl_read_mouse_window(void);
#endif

View file

@ -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) { }

View file

@ -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));

View file

@ -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);*/
}
}
djui_base_render(&sMouseCursor->base);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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);

View file

@ -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);

View file

@ -0,0 +1,31 @@
#include <string.h>
#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;
}

View file

@ -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*));

View file

@ -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
}