From 5e9f8c7ee09e44c42bcea95bebb2419da97d1723 Mon Sep 17 00:00:00 2001 From: Lilaa3 <87947656+Lilaa3@users.noreply.github.com> Date: Tue, 29 Aug 2023 14:57:32 +0100 Subject: [PATCH] Improved transitions (#642) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Improved transitions Code quality improvements. Shape transitions now all scale down to 0 instead of 16 (mario and bowser). Ease in was added which leads to far smoother transitions. HD_TRANSITIONS define added, makes use of the tex edge render mode to deliver smooth transition textures. lerpf was added to math utils. * Cleaner textures, rounding only during vertex creation * Another attempt * cozies naming suggestion * Improvements and suggestions SHARP_TRANSITION_TEXTURES is now off by default (I still think the textures for it could be improved). lerpf, to_smoothstop, smoothstart, smoothstop and smoothstep have all been added. make_vertex has been inlined. make_simple_vertex has been added (colourless vertex). Transition colors (and canon colors) are now defined using primative colour instead of setting individual vertices color´s. Transition´s now use smoothstep (ease-in-out) instead of ease out only. Naming has been improved. * Proper function inling and removal of GBI_FLOATS variant of make_vertex and make_simple_vertex * More requested changes * Accidental final new line removal fixed * Comment about pop in fix. * Comment fix The issue with writing comments for stuff is when you want to change code later on. --- bin/segment2.c | 20 + include/config/config_graphics.h | 12 +- src/engine/math_util.h | 26 ++ src/game/area.c | 40 +- src/game/area.h | 2 +- src/game/geo_misc.c | 25 - src/game/geo_misc.h | 53 ++- src/game/screen_transition.c | 428 ++++++++++-------- src/game/screen_transition.h | 2 +- .../segment2/transition_bowser_half.i8.png | Bin 0 -> 2876 bytes .../segment2/transition_circle_half.i8.png | Bin 0 -> 1680 bytes textures/segment2/transition_mario.i8.png | Bin 0 -> 3036 bytes textures/segment2/transition_star_half.i8.png | Bin 0 -> 1607 bytes 13 files changed, 369 insertions(+), 239 deletions(-) create mode 100644 textures/segment2/transition_bowser_half.i8.png create mode 100644 textures/segment2/transition_circle_half.i8.png create mode 100644 textures/segment2/transition_mario.i8.png create mode 100644 textures/segment2/transition_star_half.i8.png diff --git a/bin/segment2.c b/bin/segment2.c index 6b66d0e1..56ac4adf 100644 --- a/bin/segment2.c +++ b/bin/segment2.c @@ -2673,6 +2673,25 @@ UNUSED ALIGNED8 static const Texture texture_radial_light[] = { #include "textures/segment2/light_quarter_circle.ia16.inc.c" }; +#ifdef SHARP_TRANSITION_TEXTURES +const Texture texture_transition_star_half[] = { +#include "textures/segment2/transition_star_half.i8.inc.c" +}; + +const Texture texture_transition_circle_half[] = { +#include "textures/segment2/transition_circle_half.i8.inc.c" +}; + +const Texture texture_transition_mario[] = { +#include "textures/segment2/transition_mario.i8.inc.c" +}; + +const Texture texture_transition_bowser_half[] = { +#include "textures/segment2/transition_bowser_half.i8.inc.c" +}; + +#else + const Texture texture_transition_star_half[] = { #include "textures/segment2/segment2.0F458.ia8.inc.c" }; @@ -2688,6 +2707,7 @@ const Texture texture_transition_mario[] = { const Texture texture_transition_bowser_half[] = { #include "textures/segment2/segment2.11458.ia8.inc.c" }; +#endif const Texture texture_waterbox_water[] = { #include "textures/segment2/segment2.11C58.rgba16.inc.c" diff --git a/include/config/config_graphics.h b/include/config/config_graphics.h index 7817e943..c252e991 100644 --- a/include/config/config_graphics.h +++ b/include/config/config_graphics.h @@ -138,7 +138,7 @@ /** * Limits the horizontal fov on emulator like on console. May break viewport widescreen hacks. */ -//#define HORIZONTAL_CULLING_ON_EMULATOR +// #define HORIZONTAL_CULLING_ON_EMULATOR /** * Makes objects bellow the screen be culled. @@ -150,3 +150,13 @@ * will be used instead. */ #define DEFAULT_CULLING_RADIUS 300 + +/** + * Eases the textured screen transitions to make them look smoother. + */ +#define EASE_IN_OUT_TRANSITIONS + +/** + * Makes use of the tex edge render mode to deliver smooth transition textures + */ +// #define SHARP_TRANSITION_TEXTURES diff --git a/src/engine/math_util.h b/src/engine/math_util.h index a9ca7229..7a80952b 100644 --- a/src/engine/math_util.h +++ b/src/engine/math_util.h @@ -598,4 +598,30 @@ ALWAYS_INLINE f32 remap(f32 x, f32 fromA, f32 toA, f32 fromB, f32 toB) { return (x - fromA) / (toA - fromA) * (toB - fromB) + fromB; } +ALWAYS_INLINE f32 lerpf(f32 from, f32 to, f32 amount) { + return (from + (to - from) * amount); +} + +ALWAYS_INLINE f32 to_smoothstop(f32 x) { + f32 sq = sqr(1.0f - x); + return 1.0f - sq; +} + +// Commonly known as ease-in +ALWAYS_INLINE f32 smoothstart(f32 from, f32 to, f32 amount) { + return lerpf(from, to, sqr(amount)); +} + +// Commonly known as ease-out +ALWAYS_INLINE f32 smoothstop(f32 from, f32 to, f32 amount) { + return lerpf(from, to, to_smoothstop(amount)); +} + +// Commonly known as ease-in-out +ALWAYS_INLINE f32 smoothstep(f32 from, f32 to, f32 amount) { + amount = sqr(amount) * (3.0f - 2.0f * amount); + + return lerpf(from, to, amount); +} + #endif // MATH_UTIL_H diff --git a/src/game/area.c b/src/game/area.c index 53b0ea2d..b917c14e 100644 --- a/src/game/area.c +++ b/src/game/area.c @@ -349,22 +349,34 @@ void play_transition(s16 transType, s16 time, Color red, Color green, Color blue gWarpTransition.data.endTexX = SCREEN_CENTER_X; gWarpTransition.data.endTexY = SCREEN_CENTER_Y; - gWarpTransition.data.texTimer = 0; + gWarpTransition.data.angleSpeed = DEGREES(0); + + s16 fullRadius = GFX_DIMENSIONS_FULL_RADIUS; + + // HackerSM64: this fixes the pop-in with texture transition, comment out this switch + // statement if you want to restore the original full radius. + switch (transType){ + case WARP_TRANSITION_TYPE_BOWSER: + case WARP_TRANSITION_FADE_INTO_BOWSER: + fullRadius *= 4; + break; + + case WARP_TRANSITION_FADE_FROM_MARIO: + case WARP_TRANSITION_FADE_INTO_MARIO: + + case WARP_TRANSITION_FADE_FROM_STAR: + case WARP_TRANSITION_FADE_INTO_STAR: + fullRadius *= 1.5f; + break; + } if (transType & WARP_TRANSITION_FADE_INTO) { // Is the image fading in? - gWarpTransition.data.startTexRadius = GFX_DIMENSIONS_FULL_RADIUS; - if (transType >= WARP_TRANSITION_FADES_INTO_LARGE) { - gWarpTransition.data.endTexRadius = 16; - } else { - gWarpTransition.data.endTexRadius = 0; - } + gWarpTransition.data.startTexRadius = fullRadius; + gWarpTransition.data.endTexRadius = 0; + } else { // The image is fading out. (Reverses start & end circles) - if (transType >= WARP_TRANSITION_FADES_FROM_LARGE) { - gWarpTransition.data.startTexRadius = 16; - } else { - gWarpTransition.data.startTexRadius = 0; - } - gWarpTransition.data.endTexRadius = GFX_DIMENSIONS_FULL_RADIUS; + gWarpTransition.data.startTexRadius = 0; + gWarpTransition.data.endTexRadius = fullRadius; } } #endif @@ -419,7 +431,7 @@ void render_game(void) { if (gWarpTransition.isActive) { if (gWarpTransDelay == 0) { - gWarpTransition.isActive = !render_screen_transition(0, gWarpTransition.type, gWarpTransition.time, + gWarpTransition.isActive = !render_screen_transition(gWarpTransition.type, gWarpTransition.time, &gWarpTransition.data); if (!gWarpTransition.isActive) { if (gWarpTransition.type & WARP_TRANSITION_FADE_INTO) { diff --git a/src/game/area.h b/src/game/area.h index 36cfdc3f..f6dd3610 100644 --- a/src/game/area.h +++ b/src/game/area.h @@ -93,7 +93,7 @@ struct WarpTransitionData { /*0x0C*/ s16 endTexX; /*0x0E*/ s16 endTexY; - /*0x10*/ s16 texTimer; // always 0, does seems to affect transition when disabled + /*0x10*/ s16 angleSpeed; }; enum WarpTransitionFadeDirections { diff --git a/src/game/geo_misc.c b/src/game/geo_misc.c index 4f793271..d78b0248 100644 --- a/src/game/geo_misc.c +++ b/src/game/geo_misc.c @@ -36,31 +36,6 @@ static s16 sFlyingCarpetRippleTimer = 0; s8 gFlyingCarpetState; -/** - * Create a vertex with the given parameters and insert it into `vtx` at - * position `n`. - * - * Texture coordinates are s10.5 fixed-point, which means you should left-shift the actual coordinates by 5. - */ -#ifndef GBI_FLOATS -void make_vertex(Vtx *vtx, s32 n, s16 x, s16 y, s16 z, s16 tx, s16 ty, u8 r, u8 g, u8 b, u8 a) { -#else -void make_vertex(Vtx *vtx, s32 n, f32 x, f32 y, f32 z, s16 tx, s16 ty, u8 r, u8 g, u8 b, u8 a) { -#endif - vtx[n].v.ob[0] = x; - vtx[n].v.ob[1] = y; - vtx[n].v.ob[2] = z; - - vtx[n].v.flag = 0; - - vtx[n].v.tc[0] = tx; - vtx[n].v.tc[1] = ty; - - vtx[n].v.cn[0] = r; - vtx[n].v.cn[1] = g; - vtx[n].v.cn[2] = b; - vtx[n].v.cn[3] = a; -} #define NUM_STARS_REQUIRED_FOR_WING_CAP_LIGHT 10 /** diff --git a/src/game/geo_misc.h b/src/game/geo_misc.h index 5e7c297e..8fcfde5e 100644 --- a/src/game/geo_misc.h +++ b/src/game/geo_misc.h @@ -12,15 +12,50 @@ enum FlyingCarpetState { extern s8 gFlyingCarpetState; -#ifndef GBI_FLOATS -extern void make_vertex( - Vtx *vtx, s32 n, s16 x, s16 y, s16 z, s16 tx, s16 ty, u8 r, u8 g, u8 b, u8 a -); -#else -extern void make_vertex( - Vtx *vtx, s32 n, f32 x, f32 y, f32 z, s16 tx, s16 ty, u8 r, u8 g, u8 b, u8 a -); -#endif +/** + * Create a vertex with the given parameters and insert it into `vtx` at + * position `n`. + * + * Texture coordinates are s10.5 fixed-point, which means you should left-shift the actual coordinates by 5. + */ +ALWAYS_INLINE void make_vertex(Vtx *vtx, s32 n, s16 x, s16 y, s16 z, s16 tx, s16 ty, u8 r, u8 g, u8 b, u8 a) { + vtx[n].v.ob[0] = x; + vtx[n].v.ob[1] = y; + vtx[n].v.ob[2] = z; + + vtx[n].v.flag = 0; + + vtx[n].v.tc[0] = tx; + vtx[n].v.tc[1] = ty; + + vtx[n].v.cn[0] = r; + vtx[n].v.cn[1] = g; + vtx[n].v.cn[2] = b; + vtx[n].v.cn[3] = a; +} + +/** + * Create a colourless vertex with the given parameters and insert it into `vtx` at + * position `n`. + * + * Texture coordinates are s10.5 fixed-point, which means you should left-shift the actual coordinates by 5. + */ +ALWAYS_INLINE void make_simple_vertex(Vtx *vtx, s32 n, s16 x, s16 y, s16 z, s16 tx, s16 ty) { + vtx[n].v.ob[0] = x; + vtx[n].v.ob[1] = y; + vtx[n].v.ob[2] = z; + + vtx[n].v.flag = 0; + + vtx[n].v.tc[0] = tx; + vtx[n].v.tc[1] = ty; + + vtx[n].v.cn[0] = 255; + vtx[n].v.cn[1] = 255; + vtx[n].v.cn[2] = 255; + vtx[n].v.cn[3] = 255; +} + extern Gfx *geo_exec_inside_castle_light(s32 callContext, struct GraphNode *node, UNUSED Mat4 mtx); extern Gfx *geo_exec_flying_carpet_timer_update(s32 callContext, struct GraphNode *node, UNUSED Mat4 mtx); extern Gfx *geo_exec_flying_carpet_create(s32 callContext, struct GraphNode *node, UNUSED Mat4 mtx); diff --git a/src/game/screen_transition.c b/src/game/screen_transition.c index 5a1b3c3a..0db3ae11 100644 --- a/src/game/screen_transition.c +++ b/src/game/screen_transition.c @@ -13,150 +13,8 @@ #include "segment2.h" #include "sm64.h" -u8 sTransitionColorFadeCount[4] = { 0 }; -u16 sTransitionTextureFadeCount[2] = { 0 }; - -s32 set_and_reset_transition_fade_timer(s8 fadeTimer, u8 transTime) { - s32 reset = FALSE; - - sTransitionColorFadeCount[fadeTimer]++; - - if (sTransitionColorFadeCount[fadeTimer] >= transTime) { - sTransitionColorFadeCount[fadeTimer] = 0; - sTransitionTextureFadeCount[fadeTimer] = 0; - reset = TRUE; - } - return reset; -} - -u8 set_transition_color_fade_alpha(s8 fadeType, s8 fadeTimer, u8 transTime) { - u8 time = 0; - - switch (fadeType) { - case COLOR_TRANS_FADE_INTO_COLOR: - time = (f32) sTransitionColorFadeCount[fadeTimer] * 255.0 / (f32)(transTime - 1) + 0.5; // fade in - break; - case COLOR_TRANS_FADE_FROM_COLOR: - time = (1.0 - sTransitionColorFadeCount[fadeTimer] / (f32)(transTime - 1)) * 255.0 + 0.5; // fade out - break; - } - return time; -} - -Vtx *vertex_transition_color(struct WarpTransitionData *transData, u8 alpha) { - Vtx *verts = alloc_display_list(4 * sizeof(*verts)); - u8 r = transData->red; - u8 g = transData->green; - u8 b = transData->blue; - - if (verts != NULL) { - make_vertex(verts, 0, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 0, -1, 0, 0, r, g, b, alpha); - make_vertex(verts, 1, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), 0, -1, 0, 0, r, g, b, alpha); - make_vertex(verts, 2, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0, r, g, b, alpha); - make_vertex(verts, 3, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0, r, g, b, alpha); - } - return verts; -} - -s32 dl_transition_color(s8 fadeTimer, u8 transTime, struct WarpTransitionData *transData, u8 alpha) { - Vtx *verts = vertex_transition_color(transData, alpha); - - if (verts != NULL) { - gSPDisplayList(gDisplayListHead++, dl_proj_mtx_fullscreen); - gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE); - gDPSetRenderMode(gDisplayListHead++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2); - gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(verts), 4, 0); - gSPDisplayList(gDisplayListHead++, dl_draw_quad_verts_0123); - gSPDisplayList(gDisplayListHead++, dl_screen_transition_end); - } - return set_and_reset_transition_fade_timer(fadeTimer, transTime); -} - -s32 render_fade_transition_from_color(s8 fadeTimer, u8 transTime, struct WarpTransitionData *transData) { - u8 alpha = set_transition_color_fade_alpha(COLOR_TRANS_FADE_FROM_COLOR, fadeTimer, transTime); - - return dl_transition_color(fadeTimer, transTime, transData, alpha); -} - -s32 render_fade_transition_into_color(s8 fadeTimer, u8 transTime, struct WarpTransitionData *transData) { - u8 alpha = set_transition_color_fade_alpha(COLOR_TRANS_FADE_INTO_COLOR, fadeTimer, transTime); - - return dl_transition_color(fadeTimer, transTime, transData, alpha); -} - -s16 calc_tex_transition_radius(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData) { - f32 texRadius = transData->endTexRadius - transData->startTexRadius; - f32 radiusTime = sTransitionColorFadeCount[fadeTimer] * texRadius / (f32)(transTime - 1); - f32 result = transData->startTexRadius + radiusTime; - - return (s16)(result + 0.5f); -} - -f32 calc_tex_transition_time(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData) { - f32 startX = transData->startTexX; - f32 startY = transData->startTexY; - f32 endX = transData->endTexX; - f32 endY = transData->endTexY; - f32 sqrtfXY = sqrtf((startX - endX) * (startX - endX) + (startY - endY) * (startY - endY)); - f32 result = (f32) sTransitionColorFadeCount[fadeTimer] * sqrtfXY / (f32)(transTime - 1); - - return result; -} - -u16 convert_tex_transition_angle_to_pos(struct WarpTransitionData *transData) { - f32 x = transData->endTexX - transData->startTexX; - f32 y = transData->endTexY - transData->startTexY; - - return atan2s(x, y); -} - -s16 center_tex_transition_x(struct WarpTransitionData *transData, f32 texTransTime, u16 texTransPos) { - f32 x = transData->startTexX + coss(texTransPos) * texTransTime; - - return (s16)(x + 0.5); -} - -s16 center_tex_transition_y(struct WarpTransitionData *transData, f32 texTransTime, u16 texTransPos) { - f32 y = transData->startTexY + sins(texTransPos) * texTransTime; - - return (s16)(y + 0.5); -} - -void make_tex_transition_vertex(Vtx *verts, s32 n, s8 fadeTimer, struct WarpTransitionData *transData, s16 centerTransX, s16 centerTransY, - s16 texRadius1, s16 texRadius2, s16 tx, s16 ty) { - u8 r = transData->red; - u8 g = transData->green; - u8 b = transData->blue; - u16 zeroTimer = sTransitionTextureFadeCount[fadeTimer]; - f32 centerX = texRadius1 * coss(zeroTimer) - texRadius2 * sins(zeroTimer) + centerTransX; - f32 centerY = texRadius1 * sins(zeroTimer) + texRadius2 * coss(zeroTimer) + centerTransY; - s16 x = roundf(centerX); - s16 y = roundf(centerY); - - make_vertex(verts, n, x, y, -1, tx * 32, ty * 32, r, g, b, 255); -} - -void load_tex_transition_vertex(Vtx *verts, s8 fadeTimer, struct WarpTransitionData *transData, s16 centerTransX, s16 centerTransY, - s16 texTransRadius, s8 transTexType) { - switch (transTexType) { - case TRANS_TYPE_MIRROR: - make_tex_transition_vertex(verts, 0, fadeTimer, transData, centerTransX, centerTransY, -texTransRadius, -texTransRadius, -31, 63); - make_tex_transition_vertex(verts, 1, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, -texTransRadius, 31, 63); - make_tex_transition_vertex(verts, 2, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, texTransRadius, 31, 0); - make_tex_transition_vertex(verts, 3, fadeTimer, transData, centerTransX, centerTransY, -texTransRadius, texTransRadius, -31, 0); - break; - case TRANS_TYPE_CLAMP: - make_tex_transition_vertex(verts, 0, fadeTimer, transData, centerTransX, centerTransY, -texTransRadius, -texTransRadius, 0, 63); - make_tex_transition_vertex(verts, 1, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, -texTransRadius, 63, 63); - make_tex_transition_vertex(verts, 2, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, texTransRadius, 63, 0); - make_tex_transition_vertex(verts, 3, fadeTimer, transData, centerTransX, centerTransY, -texTransRadius, texTransRadius, 0, 0); - break; - } - make_tex_transition_vertex(verts, 4, fadeTimer, transData, centerTransX, centerTransY, -2000, -2000, 0, 0); - make_tex_transition_vertex(verts, 5, fadeTimer, transData, centerTransX, centerTransY, 2000, -2000, 0, 0); - make_tex_transition_vertex(verts, 6, fadeTimer, transData, centerTransX, centerTransY, 2000, 2000, 0, 0); - make_tex_transition_vertex(verts, 7, fadeTimer, transData, centerTransX, centerTransY, -2000, 2000, 0, 0); -} +u8 sTransitionFadeTimer = 0; +u16 sTransitionTextureAngle = 0; void *sTextureTransitionID[] = { texture_transition_star_half, @@ -165,108 +23,302 @@ void *sTextureTransitionID[] = { texture_transition_bowser_half, }; -s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData, s8 texID, s8 transTexType) { - f32 texTransTime = calc_tex_transition_time(fadeTimer, transTime, transData); - u16 texTransPos = convert_tex_transition_angle_to_pos(transData); - s16 centerTransX = center_tex_transition_x(transData, texTransTime, texTransPos); - s16 centerTransY = center_tex_transition_y(transData, texTransTime, texTransPos); - s16 texTransRadius = calc_tex_transition_radius(fadeTimer, transTime, transData); - Vtx *verts = alloc_display_list(8 * sizeof(*verts)); +s32 set_and_reset_transition_fade_timer(u8 transTime) { + sTransitionFadeTimer++; + + if (sTransitionFadeTimer >= transTime) { + sTransitionFadeTimer = 0; + sTransitionTextureAngle = 0; + return TRUE; + } + + return FALSE; +} + +void make_tex_transition_vertex(Vtx *verts, s32 n, f32 centerTransX, f32 centerTransY, + f32 vertX, f32 vertY, s16 tx, s16 ty) { + // Rotate around the center + s16 angle = sTransitionTextureAngle; + f32 x = vertX * coss(angle) - vertY * sins(angle) + centerTransX; + f32 y = vertX * sins(angle) + vertY * coss(angle) + centerTransY; + + s16 roundedX = roundf(x); + s16 roundedY = roundf(y); + + make_simple_vertex(verts, n, roundedX, roundedY, -1, tx * 32, ty * 32); +} + +#define SOLID_COL_RADIUS 2000 +void make_tex_transition_vertices(Vtx *verts, f32 centerTransX, f32 centerTransY, f32 texTransRadius, + s8 transTexType) { + + s16 leftUV, rightUV, downUV, upUV; + + if (transTexType == TRANS_TYPE_MIRROR) { + leftUV = -31; + rightUV = 31; + downUV = 0; + upUV = 63; + } + else { + leftUV = 0; + rightUV = 63; + downUV = 0; + upUV = 63; + } + + // Shape texture + make_tex_transition_vertex(verts, 0, centerTransX, centerTransY, -texTransRadius, -texTransRadius, leftUV, upUV); + make_tex_transition_vertex(verts, 1, centerTransX, centerTransY, texTransRadius, -texTransRadius, rightUV, upUV); + make_tex_transition_vertex(verts, 2, centerTransX, centerTransY, texTransRadius, texTransRadius, rightUV, downUV); + make_tex_transition_vertex(verts, 3, centerTransX, centerTransY, -texTransRadius, texTransRadius, leftUV, downUV); + + // Solid color + make_tex_transition_vertex(verts, 4, centerTransX, centerTransY, -SOLID_COL_RADIUS, -SOLID_COL_RADIUS, 0, 0); + make_tex_transition_vertex(verts, 5, centerTransX, centerTransY, SOLID_COL_RADIUS, -SOLID_COL_RADIUS, 0, 0); + make_tex_transition_vertex(verts, 6, centerTransX, centerTransY, SOLID_COL_RADIUS, SOLID_COL_RADIUS, 0, 0); + make_tex_transition_vertex(verts, 7, centerTransX, centerTransY, -SOLID_COL_RADIUS, SOLID_COL_RADIUS, 0, 0); +} + +f32 calc_tex_transition_radius(s8 transTime, struct WarpTransitionData *transData) { + f32 amount = (f32) sTransitionFadeTimer / (f32) (transTime - 1); + +#ifdef EASE_IN_OUT_TRANSITIONS + return smoothstep(transData->startTexRadius, transData->endTexRadius, amount); +#else + return lerpf(transData->startTexRadius, transData->endTexRadius, amount); +#endif + +} + +f32 center_tex_transition_x(struct WarpTransitionData *transData, f32 posDistance, u16 texTransDir) { + f32 x = transData->startTexX + coss(texTransDir) * posDistance; + + return x; +} + +f32 center_tex_transition_y(struct WarpTransitionData *transData, f32 posDistance, u16 texTransDir) { + f32 y = transData->startTexY + sins(texTransDir) * posDistance; + + return y; +} + +f32 calc_tex_transition_pos_distance(s8 transTime, struct WarpTransitionData *transData) { + f32 startX = transData->startTexX; + f32 startY = transData->startTexY; + f32 endX = transData->endTexX; + f32 endY = transData->endTexY; + + f32 distance = sqrtf(sqr(startX - endX) + sqr(startY - endY)); + + f32 amount = (f32) sTransitionFadeTimer / (f32)(transTime - 1); + + return distance * amount; +} + +u16 calc_tex_transition_direction(struct WarpTransitionData *transData) { + f32 x = transData->endTexX - transData->startTexX; + f32 y = transData->endTexY - transData->startTexY; + + return atan2s(x, y); +} + +/* + * Called during render_screen_transition. + * Handles shape transitions (such as the star, circle and Mario and bowser´s heads). + */ +s32 render_textured_transition(s8 transTime, struct WarpTransitionData *transData, s8 texID, s8 transTexType) { + u16 texTransDir = calc_tex_transition_direction(transData); + + f32 posDistance = calc_tex_transition_pos_distance(transTime, transData); + f32 centerTransX = center_tex_transition_x(transData, posDistance, texTransDir); + f32 centerTransY = center_tex_transition_y(transData, posDistance, texTransDir); + + f32 texTransRadius = calc_tex_transition_radius(transTime, transData); + Vtx *verts = alloc_display_list(8 * sizeof(Vtx)); + if (verts != NULL) { - load_tex_transition_vertex(verts, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, transTexType); + make_tex_transition_vertices(verts, centerTransX, centerTransY, texTransRadius, transTexType); gSPDisplayList(gDisplayListHead++, dl_proj_mtx_fullscreen); - gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE); + + u8 r = transData->red; + u8 g = transData->green; + u8 b = transData->blue; + gDPSetPrimColor(gDisplayListHead++, 0, 0, r, g, b, 255); + + gDPSetCombineMode(gDisplayListHead++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); gDPSetRenderMode(gDisplayListHead++, G_RM_AA_OPA_SURF, G_RM_AA_OPA_SURF2); + gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(verts), 8, 0); gSPDisplayList(gDisplayListHead++, dl_transition_draw_filled_region); gDPPipeSync(gDisplayListHead++); - gDPSetCombineMode(gDisplayListHead++, G_CC_MODULATEIDECALA, G_CC_MODULATEIDECALA); + + gDPSetCombineLERP(gDisplayListHead++, 0, 0, 0, PRIMITIVE, 0, 0, 0, TEXEL0, + 0, 0, 0, PRIMITIVE, 0, 0, 0, TEXEL0); + +#ifdef SHARP_TRANSITION_TEXTURES + gDPSetRenderMode(gDisplayListHead++, G_RM_AA_TEX_EDGE, G_RM_AA_TEX_EDGE2); + s32 textureType = G_IM_FMT_I; +#else gDPSetRenderMode(gDisplayListHead++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2); + s32 textureType = G_IM_FMT_IA; +#endif + gDPSetTextureFilter(gDisplayListHead++, G_TF_BILERP); + switch (transTexType) { - case TRANS_TYPE_MIRROR: - gDPLoadTextureBlock(gDisplayListHead++, sTextureTransitionID[texID], G_IM_FMT_IA, G_IM_SIZ_8b, 32, 64, 0, - G_TX_WRAP | G_TX_MIRROR, G_TX_WRAP | G_TX_MIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD); - break; - case TRANS_TYPE_CLAMP: - gDPLoadTextureBlock(gDisplayListHead++, sTextureTransitionID[texID], G_IM_FMT_IA, G_IM_SIZ_8b, 64, 64, 0, - G_TX_CLAMP, G_TX_CLAMP, 6, 6, G_TX_NOLOD, G_TX_NOLOD); - break; + case TRANS_TYPE_MIRROR: + gDPLoadTextureBlock(gDisplayListHead++, sTextureTransitionID[texID], textureType, G_IM_SIZ_8b, 32, 64, 0, + G_TX_WRAP | G_TX_MIRROR, G_TX_WRAP | G_TX_MIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD); + break; + case TRANS_TYPE_CLAMP: + gDPLoadTextureBlock(gDisplayListHead++, sTextureTransitionID[texID], textureType, G_IM_SIZ_8b, 64, 64, 0, + G_TX_CLAMP, G_TX_CLAMP, 6, 6, G_TX_NOLOD, G_TX_NOLOD); + break; } gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(verts), 4, 0); gSPDisplayList(gDisplayListHead++, dl_draw_quad_verts_0123); gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF); gSPDisplayList(gDisplayListHead++, dl_screen_transition_end); - sTransitionTextureFadeCount[fadeTimer] += transData->texTimer; + sTransitionTextureAngle += transData->angleSpeed; } - return set_and_reset_transition_fade_timer(fadeTimer, transTime); + return set_and_reset_transition_fade_timer(transTime); } -s32 render_screen_transition(s8 fadeTimer, s8 transType, u8 transTime, struct WarpTransitionData *transData) { +Vtx *vertex_transition_color() { + Vtx *verts = alloc_display_list(4 * sizeof(Vtx)); + + if (verts != NULL) { + make_simple_vertex(verts, 0, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 0, -1, 0, 0); + make_simple_vertex(verts, 1, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), 0, -1, 0, 0); + make_simple_vertex(verts, 2, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0); + make_simple_vertex(verts, 3, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0); + } + return verts; +} + +s32 dl_transition_color(u8 transTime, struct WarpTransitionData *transData, u8 alpha) { + Vtx *verts = vertex_transition_color(); + + if (verts != NULL) { + u8 r = transData->red; + u8 g = transData->green; + u8 b = transData->blue; + gDPSetPrimColor(gDisplayListHead++, 0, 0, r, g, b, alpha); + + gSPDisplayList(gDisplayListHead++, dl_proj_mtx_fullscreen); + gDPSetCombineMode(gDisplayListHead++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); + gDPSetRenderMode(gDisplayListHead++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2); + gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(verts), 4, 0); + gSPDisplayList(gDisplayListHead++, dl_draw_quad_verts_0123); + gSPDisplayList(gDisplayListHead++, dl_screen_transition_end); + } + return set_and_reset_transition_fade_timer(transTime); +} + +u8 set_transition_color_fade_alpha(s8 fadeType, u8 transTime) { + u8 time = 0; + f32 amount = (f32) sTransitionFadeTimer / (f32) (transTime - 1); + switch (fadeType) { + case COLOR_TRANS_FADE_INTO_COLOR: + time = lerpf(0.f, 255.0f, amount); + break; + case COLOR_TRANS_FADE_FROM_COLOR: + time = lerpf(255.0f, 0.f, amount); + break; + } + return roundf(time); +} + +s32 render_fade_transition_from_color(u8 transTime, struct WarpTransitionData *transData) { + u8 alpha = set_transition_color_fade_alpha(COLOR_TRANS_FADE_FROM_COLOR, transTime); + + return dl_transition_color(transTime, transData, alpha); +} + +s32 render_fade_transition_into_color(u8 transTime, struct WarpTransitionData *transData) { + u8 alpha = set_transition_color_fade_alpha(COLOR_TRANS_FADE_INTO_COLOR, transTime); + + return dl_transition_color(transTime, transData, alpha); +} + +/* + * Called during rendering if gWarpTransition.isActive is on. + * Handles solid colour transitions and shape transitions + * (such as the star, circle and Mario and bowser´s heads). + */ +s32 render_screen_transition(s8 transType, u8 transTime, struct WarpTransitionData *transData) { switch (transType) { case WARP_TRANSITION_FADE_FROM_COLOR: - return render_fade_transition_from_color(fadeTimer, transTime, transData); + return render_fade_transition_from_color(transTime, transData); break; case WARP_TRANSITION_FADE_INTO_COLOR: - return render_fade_transition_into_color(fadeTimer, transTime, transData); + return render_fade_transition_into_color(transTime, transData); break; + case WARP_TRANSITION_FADE_FROM_STAR: - return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_STAR, TRANS_TYPE_MIRROR); + return render_textured_transition(transTime, transData, TEX_TRANS_STAR, TRANS_TYPE_MIRROR); break; case WARP_TRANSITION_FADE_INTO_STAR: - return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_STAR, TRANS_TYPE_MIRROR); + return render_textured_transition(transTime, transData, TEX_TRANS_STAR, TRANS_TYPE_MIRROR); break; + case WARP_TRANSITION_FADE_FROM_CIRCLE: - return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_CIRCLE, TRANS_TYPE_MIRROR); + return render_textured_transition(transTime, transData, TEX_TRANS_CIRCLE, TRANS_TYPE_MIRROR); break; case WARP_TRANSITION_FADE_INTO_CIRCLE: - return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_CIRCLE, TRANS_TYPE_MIRROR); + return render_textured_transition(transTime, transData, TEX_TRANS_CIRCLE, TRANS_TYPE_MIRROR); break; + case WARP_TRANSITION_FADE_FROM_MARIO: - return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_MARIO, TRANS_TYPE_CLAMP); + return render_textured_transition(transTime, transData, TEX_TRANS_MARIO, TRANS_TYPE_CLAMP); break; case WARP_TRANSITION_FADE_INTO_MARIO: - return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_MARIO, TRANS_TYPE_CLAMP); + return render_textured_transition(transTime, transData, TEX_TRANS_MARIO, TRANS_TYPE_CLAMP); break; + case WARP_TRANSITION_FADE_FROM_BOWSER: - return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_BOWSER, TRANS_TYPE_MIRROR); + return render_textured_transition(transTime, transData, TEX_TRANS_BOWSER, TRANS_TYPE_MIRROR); break; case WARP_TRANSITION_FADE_INTO_BOWSER: - return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_BOWSER, TRANS_TYPE_MIRROR); + return render_textured_transition(transTime, transData, TEX_TRANS_BOWSER, TRANS_TYPE_MIRROR); break; } return FALSE; } + Gfx *render_cannon_circle_base(void) { #ifdef WIDESCREEN - Vtx *verts = alloc_display_list(8 * sizeof(*verts)); - Gfx *dlist = alloc_display_list(20 * sizeof(*dlist)); + Vtx *verts = alloc_display_list(8 * sizeof(Vtx)); + Gfx *dlist = alloc_display_list(20 * sizeof(Gfx)); #else - Vtx *verts = alloc_display_list(4 * sizeof(*verts)); - Gfx *dlist = alloc_display_list(16 * sizeof(*dlist)); + Vtx *verts = alloc_display_list(4 * sizeof(Vtx)); + Gfx *dlist = alloc_display_list(16 * sizeof(Gfx)); #endif Gfx *g = dlist; if (verts != NULL && dlist != NULL) { - make_vertex(verts, 0, 0, 0, -1, -1152, 1824, 0, 0, 0, 255); - make_vertex(verts, 1, SCREEN_WIDTH, 0, -1, 1152, 1824, 0, 0, 0, 255); - make_vertex(verts, 2, SCREEN_WIDTH, SCREEN_HEIGHT, -1, 1152, 192, 0, 0, 0, 255); - make_vertex(verts, 3, 0, SCREEN_HEIGHT, -1, -1152, 192, 0, 0, 0, 255); + gDPSetPrimColor(gDisplayListHead++, 0, 0, 0, 0, 0, 255); + + make_simple_vertex(verts, 0, 0, 0, -1, -1152, 1824); + make_simple_vertex(verts, 1, SCREEN_WIDTH, 0, -1, 1152, 1824); + make_simple_vertex(verts, 2, SCREEN_WIDTH, SCREEN_HEIGHT, -1, 1152, 192); + make_simple_vertex(verts, 3, 0, SCREEN_HEIGHT, -1, -1152, 192); #ifdef WIDESCREEN // Render black rectangles outside the 4:3 area. - make_vertex(verts, 4, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 0, -1, 0, 0, 0, 0, 0, 255); - make_vertex(verts, 5, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), 0, -1, 0, 0, 0, 0, 0, 255); - make_vertex(verts, 6, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0, 0, 0, 0, 255); - make_vertex(verts, 7, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0, 0, 0, 0, 255); + make_simple_vertex(verts, 4, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 0, -1, 0, 0, 0); + make_simple_vertex(verts, 5, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), 0, -1, 0, 0, 0); + make_simple_vertex(verts, 6, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0); + make_simple_vertex(verts, 7, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0); #endif gSPDisplayList(g++, dl_proj_mtx_fullscreen); - gDPSetCombineMode(g++, G_CC_MODULATEIDECALA, G_CC_MODULATEIDECALA); + gDPSetCombineMode(g++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); gDPSetTextureFilter(g++, G_TF_BILERP); gDPLoadTextureBlock(g++, sTextureTransitionID[TEX_TRANS_CIRCLE], G_IM_FMT_IA, G_IM_SIZ_8b, 32, 64, 0, G_TX_WRAP | G_TX_MIRROR, G_TX_WRAP | G_TX_MIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD); diff --git a/src/game/screen_transition.h b/src/game/screen_transition.h index f78517f5..0bfb092a 100644 --- a/src/game/screen_transition.h +++ b/src/game/screen_transition.h @@ -24,7 +24,7 @@ enum ColorTransitionFade { COLOR_TRANS_FADE_FROM_COLOR, }; -s32 render_screen_transition(s8 fadeTimer, s8 transType, u8 transTime, struct WarpTransitionData *transData); +s32 render_screen_transition(s8 transType, u8 transTime, struct WarpTransitionData *transData); Gfx *geo_cannon_circle_base(s32 callContext, struct GraphNode *node, UNUSED Mat4 mtx); #endif // SCREEN_TRANSITION_H diff --git a/textures/segment2/transition_bowser_half.i8.png b/textures/segment2/transition_bowser_half.i8.png new file mode 100644 index 0000000000000000000000000000000000000000..7f321dc58e01493681fafc54abe5ced912b42ba2 GIT binary patch literal 2876 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 VcSQI+7#J8BJYD@<);T3K0RRMzk+T2* literal 0 HcmV?d00001 diff --git a/textures/segment2/transition_star_half.i8.png b/textures/segment2/transition_star_half.i8.png new file mode 100644 index 0000000000000000000000000000000000000000..f5843af042e5aead4fccea51290472467019d54f GIT binary patch literal 1607 zcmeAS@N?(olHy`uVBq!ia0y~yU{GLSU~u4IV_;yY?kio#z`&T7>FgYknVihPpfRy@ zqO~`(qe!d0u<0T}R$Y^boP|k(t|CW*lxCvnOA6vi$G+E}a#!_g(njfA_yX&+wAo#%IcVNO@PL<)P$58&i*m>`}b4 z?)jw5hqVtksIrUf3#dBv*!^f^f4pdP=MRe?A^y6*n}h8m&PTF7w0ro@Y2TXq`R;dB zGDOmsEp1CFOB7c3V(Ar0op$2!1^ulWGylGo{`1KzsJp7e+n*~=?7u=mL$C2Zhdb!k|FJ^lY$G>U|?XbV9Co{kJemT49 z+Fo|u?1G}Wt3kI5cJaxUr(N=@^Q@b>&xdVZ|H4YXTk94S9z6Z3dhX(Ak2R-+V-KCv z`*P~vw4?sI{u%O6&R-Q2Hw4YfBNCW z&O7(*oA&+t_e+d-&YbaSczEud-^;geuU2o3(mksl^PsQa} z>gt^g66s%@ot=#=EHq+cV}qt~y?gyy`@q|?KR$dYSgEz+!fR%?>`&4jky;uIl?^T} ze|%c+T3cCtsnni4h5IUhM{URf#!j}HMf>;1@7leam0g#WLDZ>U;CT!$14l#D%L%I( z{5THWzCC+c3eV*kU19C1ybYNNwhnnRo7QYt!?=J+;MoK*-nD$E|1(Os%uKu~a3Ewu z!Io<6Lq==@p$mI9_^@bb>qs*#aEeTv$q^71p~f^re}=Qrv?uI`CdoKy)WC9m6ekcCEfe&6OTwNyS0g_Lv_EVLrCl8%fYeA^XAY0ns-^iT)du%;aFs{ zo4b2zSy|Y7U&a@wLM$vSF6`X5Yu72A{cAU^u&}pZU&rF3#SoIP)W*_s;_>6|v5Ouj z=lp4zc)1|Pt@q6VgW8of2X-BO85bX4`re^EQ~%lALv3y>zJ7kIls^}1$#+OOaV}GS z+giva)w6Ehx>L7q&C=1=e=Q<#ZAF0Z?Z|82bDlgr=5A(YmQq|CeEZO$rk?)(>t6q- zF{nt!M@0ph&fvS3sKw3hVbu2}I5_wfx5fOQfeRTTdyUt&GX9Xz=Q(h_LXn}e=Q-Pn zY?+3Tl{3U&>l^!3sUD12qh4A4_xrbceRY+V69p|-A3a*MX3d%tzkcl!c;4%Dw#Rf= zHS>hyCo|UMiD+)yGbv?J;k^?XUuKFkWHUYY;^*hzWwwChEKl^LPARWnH>Debdc9sg zd*1%}IU^t)gD() zEOL5buJ^&I{iM&~xS>_d&w>9?@=mxUMyArW`SSImMNJY{xgqtd~Dvi(^5CiQqz%< z?a)-|0}-zrC)~?&`O}v1pk&QGPHyHE?1@jd?Gdi(v9c