From 2fe543a60315675d271b3c6a541875d41b62c570 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Fri, 26 Jun 2026 08:44:26 -0500 Subject: [PATCH] UI Transition --- src/dusk/rpg/item/inventory.h | 2 +- src/dusk/ui/CMakeLists.txt | 1 + src/dusk/ui/transition/CMakeLists.txt | 10 +++ src/dusk/ui/transition/uitransition.c | 81 +++++++++++++++++++++++ src/dusk/ui/transition/uitransition.h | 74 +++++++++++++++++++++ src/dusk/ui/transition/uitransitiondata.h | 23 +++++++ src/dusk/ui/transition/uitransitionfade.c | 56 ++++++++++++++++ src/dusk/ui/transition/uitransitionfade.h | 29 ++++++++ src/dusk/ui/uielement.c | 7 ++ 9 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 src/dusk/ui/transition/CMakeLists.txt create mode 100644 src/dusk/ui/transition/uitransition.c create mode 100644 src/dusk/ui/transition/uitransition.h create mode 100644 src/dusk/ui/transition/uitransitiondata.h create mode 100644 src/dusk/ui/transition/uitransitionfade.c create mode 100644 src/dusk/ui/transition/uitransitionfade.h diff --git a/src/dusk/rpg/item/inventory.h b/src/dusk/rpg/item/inventory.h index a56d93f4..ba559dfe 100644 --- a/src/dusk/rpg/item/inventory.h +++ b/src/dusk/rpg/item/inventory.h @@ -8,7 +8,7 @@ #pragma once #include "rpg/item/item.h" -#define ITEM_STACK_QUANTITY_MAX UINT8_MAX +#define ITEM_STACK_QUANTITY_MAX 99 typedef enum { INVENTORY_SORT_BY_ID, diff --git a/src/dusk/ui/CMakeLists.txt b/src/dusk/ui/CMakeLists.txt index d6a0d06f..26754f0d 100644 --- a/src/dusk/ui/CMakeLists.txt +++ b/src/dusk/ui/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(frame) add_subdirectory(focus) add_subdirectory(overlay) add_subdirectory(rpg) +add_subdirectory(transition) add_subdirectory(widget) # Sources diff --git a/src/dusk/ui/transition/CMakeLists.txt b/src/dusk/ui/transition/CMakeLists.txt new file mode 100644 index 00000000..0e365038 --- /dev/null +++ b/src/dusk/ui/transition/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2026 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +target_sources(${DUSK_LIBRARY_TARGET_NAME} + PUBLIC + uitransition.c + uitransitionfade.c +) diff --git a/src/dusk/ui/transition/uitransition.c b/src/dusk/ui/transition/uitransition.c new file mode 100644 index 00000000..4ed0026e --- /dev/null +++ b/src/dusk/ui/transition/uitransition.c @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "uitransition.h" +#include "uitransitionfade.h" +#include "assert/assert.h" +#include "util/memory.h" +#include "time/time.h" +#include "util/math.h" + +uitransition_t UI_TRANSITION; + +uitransitiondrawfunc_t UI_TRANSITION_TYPE_DRAW[UI_TRANSITION_TYPE_COUNT] = { + [UI_TRANSITION_TYPE_FADE] = uiTransitionFadeDraw +}; + +errorret_t uiTransitionInit(void) { + memoryZero(&UI_TRANSITION, sizeof(uitransition_t)); + + // uiTransitionStart((uitransitionstartparams_t){ + // .duration = 5.0f, + // .type = UI_TRANSITION_TYPE_FADE, + // .params = { + // .fade = { + // .easing = EASING_OUT_QUART, + // .fromColor = COLOR_TRANSPARENT_BLACK, + // .toColor = COLOR_BLACK + // } + // }, + // .finished = NULL, + // .user = NULL + // }); + + errorOk(); +} + +errorret_t uiTransitionUpdate(void) { + // Update time. + float_t newTime = UI_TRANSITION.data.time + TIME.delta; + + UI_TRANSITION.data.time = mathClamp( + newTime, + 0.0f, + UI_TRANSITION.data.duration + ); + UI_TRANSITION.data.t = ( + (UI_TRANSITION.data.duration <= 0.0f) ? + 1.0f : + (UI_TRANSITION.data.time / UI_TRANSITION.data.duration) + ); + + if(UI_TRANSITION.data.t >= 1.0f && UI_TRANSITION.finished) { + UI_TRANSITION.finished(UI_TRANSITION.user); + } + + errorOk(); +} + +errorret_t uiTransitionDraw(void) { + uitransitiondrawfunc_t draw = UI_TRANSITION_TYPE_DRAW[UI_TRANSITION.type]; + if(!draw) errorOk(); + return draw(&UI_TRANSITION.data); +} + +void uiTransitionStart(const uitransitionstartparams_t info) { + assertTrue(info.type > UI_TRANSITION_TYPE_NULL, "Invalid type"); + assertTrue(info.type < UI_TRANSITION_TYPE_COUNT, "Invalid type"); + assertTrue(info.duration >= 0.0f, "Duration must be non-negative"); + + memoryZero(&UI_TRANSITION, sizeof(uitransition_t)); + + UI_TRANSITION.data.duration = info.duration; + UI_TRANSITION.type = info.type; + UI_TRANSITION.data.params = info.params; + UI_TRANSITION.finished = info.finished; + UI_TRANSITION.user = info.user; +} \ No newline at end of file diff --git a/src/dusk/ui/transition/uitransition.h b/src/dusk/ui/transition/uitransition.h new file mode 100644 index 00000000..305ec5c3 --- /dev/null +++ b/src/dusk/ui/transition/uitransition.h @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "error/error.h" +#include "display/color.h" +#include "animation/easing.h" +#include "uitransitiondata.h" + +typedef void (*uitransitioncallback_t)(void *user); + +typedef enum { + UI_TRANSITION_TYPE_NULL, + + UI_TRANSITION_TYPE_FADE, + + UI_TRANSITION_TYPE_COUNT +} uitransitiontype_t; + +extern uitransitiondrawfunc_t UI_TRANSITION_TYPE_DRAW[UI_TRANSITION_TYPE_COUNT]; + + +typedef struct { + uitransitiondata_t data; + uitransitiontype_t type; + uitransitioncallback_t finished; + void *user; +} uitransition_t; + +extern uitransition_t UI_TRANSITION; + +/** + * Initializes the transition overlay, zeroing all fields and wiring the + * onTransitionEnd event. + * + * @return Any error that occurs. + */ +errorret_t uiTransitionInit(void); + +/** + * Advances the transition. Fires onTransitionEnd once when it completes. + * Safe to call when no transition is running. + * + * @return Any error that occurs. + */ +errorret_t uiTransitionUpdate(void); + +/** + * Renders the transition overlay. Skipped entirely when the current alpha + * is zero. + * + * @return Any error that occurs. + */ +errorret_t uiTransitionDraw(void); + +typedef struct { + float_t duration; + uitransitiontype_t type; + uitransitionparams_t params; + uitransitioncallback_t finished; + void *user; +} uitransitionstartparams_t; + +/** + * Starts a transition described by an info struct. + * + * @param info Transition parameters. + */ +void uiTransitionStart(const uitransitionstartparams_t info); + diff --git a/src/dusk/ui/transition/uitransitiondata.h b/src/dusk/ui/transition/uitransitiondata.h new file mode 100644 index 00000000..37e8430f --- /dev/null +++ b/src/dusk/ui/transition/uitransitiondata.h @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "error/error.h" +#include "uitransitionfade.h" + +typedef union uitransitionparams_u { + uitransitionfade_t fade; +} uitransitionparams_t; + +typedef struct uitransitiondata_s { + float_t time; + float_t duration; + float_t t; + uitransitionparams_t params; +} uitransitiondata_t; + +typedef errorret_t (*uitransitiondrawfunc_t)(const uitransitiondata_t *data); diff --git a/src/dusk/ui/transition/uitransitionfade.c b/src/dusk/ui/transition/uitransitionfade.c new file mode 100644 index 00000000..45e3168d --- /dev/null +++ b/src/dusk/ui/transition/uitransitionfade.c @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "uitransition.h" +#include "assert/assert.h" +#include "display/screen/screen.h" +#include "display/texture/texture.h" +#include "display/spritebatch/spritebatch.h" +#include "display/shader/shaderunlit.h" + +errorret_t uiTransitionFadeDraw(const uitransitiondata_t *data) { + assertNotNull(data, "data must not be NULL"); + + float_t e = easingApply(data->params.fade.easing, data->t); + + float_t r = (float_t)( + data->params.fade.toColor.r - data->params.fade.fromColor.r + ) * e; + float_t g = (float_t)( + data->params.fade.toColor.g - data->params.fade.fromColor.g + ) * e; + float_t b = (float_t)( + data->params.fade.toColor.b - data->params.fade.fromColor.b + ) * e; + float_t a = (float_t)( + data->params.fade.toColor.a - data->params.fade.fromColor.a + ) * e; + + color_t color = color4b( + data->params.fade.fromColor.r + (uint8_t)r, + data->params.fade.fromColor.g + (uint8_t)g, + data->params.fade.fromColor.b + (uint8_t)b, + data->params.fade.fromColor.a + (uint8_t)a + ); + + if(color.a == 0) errorOk(); + + spritebatchsprite_t sprite = { + .min = { 0.0f, 0.0f, 0.0f }, + .max = { (float_t)SCREEN.width, (float_t)SCREEN.height, 0.0f }, + .uvMin = { 0.0f, 0.0f }, + .uvMax = { 1.0f, 1.0f } + }; + shadermaterial_t material = { + .unlit = { + .color = color, + .texture = NULL + } + }; + errorChain(spriteBatchBuffer(&sprite, 1, &SHADER_UNLIT, material)); + return spriteBatchFlush(); +} diff --git a/src/dusk/ui/transition/uitransitionfade.h b/src/dusk/ui/transition/uitransitionfade.h new file mode 100644 index 00000000..a1b2475a --- /dev/null +++ b/src/dusk/ui/transition/uitransitionfade.h @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "error/error.h" +#include "display/color.h" +#include "animation/easing.h" + +typedef struct uitransitiondata_s uitransitiondata_t; + +typedef struct { + color_t fromColor; + color_t toColor; + easingtype_t easing; +} uitransitionfade_t; + +/** + * Renders a full-screen color overlay interpolated between fade->fromColor + * and fade->toColor using fade->easing. t is the raw normalized progress + * in [0, 1] before easing is applied. No-op when the resulting alpha is zero. + * + * @param fade The fade parameters. + * @return Any error that occurs. + */ +errorret_t uiTransitionFadeDraw(const uitransitiondata_t *fade); diff --git a/src/dusk/ui/uielement.c b/src/dusk/ui/uielement.c index 5c73e0bd..60eae45d 100644 --- a/src/dusk/ui/uielement.c +++ b/src/dusk/ui/uielement.c @@ -14,6 +14,7 @@ #include "ui/overlay/uiloading.h" #include "ui/debug/uiplayerpos.h" #include "ui/overlay/uicrop.h" +#include "ui/transition/uitransition.h" #include "ui/debug/uiconsole.h" #include "ui/frame/uisettings.h" #include "ui/rpg/uitextboxmain.h" @@ -44,6 +45,12 @@ uielement_t UI_ELEMENTS[] = { .draw = uiTextboxMainDraw }, + { + .init = uiTransitionInit, + .update = uiTransitionUpdate, + .draw = uiTransitionDraw + }, + // Fullbox over: above absolutely everything. { .init = uiFullboxOverInit,