sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

screen_transition.c (14354B)


      1 #include <PR/ultratypes.h>
      2 #include <PR/gbi.h>
      3 
      4 #include "area.h"
      5 #include "camera.h"
      6 #include "engine/graph_node.h"
      7 #include "engine/math_util.h"
      8 #include "game/game_init.h"
      9 #include "geo_misc.h"
     10 #include "gfx_dimensions.h"
     11 #include "memory.h"
     12 #include "screen_transition.h"
     13 #include "segment2.h"
     14 #include "sm64.h"
     15 
     16 u8 sTransitionColorFadeCount[4] = { 0 };
     17 u16 sTransitionTextureFadeCount[2] = { 0 };
     18 
     19 s32 set_and_reset_transition_fade_timer(s8 fadeTimer, u8 transTime) {
     20     s32 reset = FALSE;
     21 
     22     sTransitionColorFadeCount[fadeTimer]++;
     23 
     24     if (sTransitionColorFadeCount[fadeTimer] == transTime) {
     25         sTransitionColorFadeCount[fadeTimer] = 0;
     26         sTransitionTextureFadeCount[fadeTimer] = 0;
     27         reset = TRUE;
     28     }
     29     return reset;
     30 }
     31 
     32 u8 set_transition_color_fade_alpha(s8 fadeType, s8 fadeTimer, u8 transTime) {
     33     u8 time;
     34 
     35     switch (fadeType) {
     36         case 0:
     37             time = (f32) sTransitionColorFadeCount[fadeTimer] * 255.0 / (f32)(transTime - 1) + 0.5; // fade in
     38             break;
     39         case 1:
     40             time = (1.0 - sTransitionColorFadeCount[fadeTimer] / (f32)(transTime - 1)) * 255.0 + 0.5; // fade out
     41             break;
     42     }
     43     return time;
     44 }
     45 
     46 Vtx *vertex_transition_color(struct WarpTransitionData *transData, u8 alpha) {
     47     Vtx *verts = alloc_display_list(4 * sizeof(*verts));
     48     u8 r = transData->red;
     49     u8 g = transData->green;
     50     u8 b = transData->blue;
     51 
     52     if (verts != NULL) {
     53         make_vertex(verts, 0, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 0, -1, 0, 0, r, g, b, alpha);
     54         make_vertex(verts, 1, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), 0, -1, 0, 0, r, g, b, alpha);
     55         make_vertex(verts, 2, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0, r, g, b, alpha);
     56         make_vertex(verts, 3, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0, r, g, b, alpha);
     57     } else {
     58     }
     59     return verts;
     60 }
     61 
     62 s32 dl_transition_color(s8 fadeTimer, u8 transTime, struct WarpTransitionData *transData, u8 alpha) {
     63     Vtx *verts = vertex_transition_color(transData, alpha);
     64 
     65     if (verts != NULL) {
     66         gSPDisplayList(gDisplayListHead++, dl_proj_mtx_fullscreen);
     67         gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE);
     68         gDPSetRenderMode(gDisplayListHead++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2);
     69         gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(verts), 4, 0);
     70         gSPDisplayList(gDisplayListHead++, dl_draw_quad_verts_0123);
     71         gSPDisplayList(gDisplayListHead++, dl_screen_transition_end);
     72     }
     73     return set_and_reset_transition_fade_timer(fadeTimer, transTime);
     74 }
     75 
     76 s32 render_fade_transition_from_color(s8 fadeTimer, u8 transTime, struct WarpTransitionData *transData) {
     77     u8 alpha = set_transition_color_fade_alpha(1, fadeTimer, transTime);
     78 
     79     return dl_transition_color(fadeTimer, transTime, transData, alpha);
     80 }
     81 
     82 s32 render_fade_transition_into_color(s8 fadeTimer, u8 transTime, struct WarpTransitionData *transData) {
     83     u8 alpha = set_transition_color_fade_alpha(0, fadeTimer, transTime);
     84 
     85     return dl_transition_color(fadeTimer, transTime, transData, alpha);
     86 }
     87 
     88 s16 calc_tex_transition_radius(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData) {
     89     f32 texRadius = transData->endTexRadius - transData->startTexRadius;
     90     f32 radiusTime = sTransitionColorFadeCount[fadeTimer] * texRadius / (f32)(transTime - 1);
     91     f32 result = transData->startTexRadius + radiusTime;
     92 
     93     return (s16)(result + 0.5);
     94 }
     95 
     96 f32 calc_tex_transition_time(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData) {
     97     f32 startX = transData->startTexX;
     98     f32 startY = transData->startTexY;
     99     f32 endX = transData->endTexX;
    100     f32 endY = transData->endTexY;
    101     f32 sqrtfXY = sqrtf((startX - endX) * (startX - endX) + (startY - endY) * (startY - endY));
    102     f32 result = (f32) sTransitionColorFadeCount[fadeTimer] * sqrtfXY / (f32)(transTime - 1);
    103 
    104     return result;
    105 }
    106 
    107 u16 convert_tex_transition_angle_to_pos(struct WarpTransitionData *transData) {
    108     f32 x = transData->endTexX - transData->startTexX;
    109     f32 y = transData->endTexY - transData->startTexY;
    110 
    111     return atan2s(x, y);
    112 }
    113 
    114 s16 center_tex_transition_x(struct WarpTransitionData *transData, f32 texTransTime, u16 texTransPos) {
    115     f32 x = transData->startTexX + coss(texTransPos) * texTransTime;
    116 
    117     return (s16)(x + 0.5);
    118 }
    119 
    120 s16 center_tex_transition_y(struct WarpTransitionData *transData, f32 texTransTime, u16 texTransPos) {
    121     f32 y = transData->startTexY + sins(texTransPos) * texTransTime;
    122 
    123     return (s16)(y + 0.5);
    124 }
    125 
    126 void make_tex_transition_vertex(Vtx *verts, s32 n, s8 fadeTimer, struct WarpTransitionData *transData, s16 centerTransX, s16 centerTransY,
    127                    s16 texRadius1, s16 texRadius2, s16 tx, s16 ty) {
    128     u8 r = transData->red;
    129     u8 g = transData->green;
    130     u8 b = transData->blue;
    131     u16 zeroTimer = sTransitionTextureFadeCount[fadeTimer];
    132     f32 centerX = texRadius1 * coss(zeroTimer) - texRadius2 * sins(zeroTimer) + centerTransX;
    133     f32 centerY = texRadius1 * sins(zeroTimer) + texRadius2 * coss(zeroTimer) + centerTransY;
    134     s16 x = round_float(centerX);
    135     s16 y = round_float(centerY);
    136 
    137     make_vertex(verts, n, x, y, -1, tx * 32, ty * 32, r, g, b, 255);
    138 }
    139 
    140 void load_tex_transition_vertex(Vtx *verts, s8 fadeTimer, struct WarpTransitionData *transData, s16 centerTransX, s16 centerTransY,
    141                    s16 texTransRadius, s8 transTexType) {
    142     switch (transTexType) {
    143         case TRANS_TYPE_MIRROR:
    144             make_tex_transition_vertex(verts, 0, fadeTimer, transData, centerTransX, centerTransY, -texTransRadius, -texTransRadius, -31, 63);
    145             make_tex_transition_vertex(verts, 1, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, -texTransRadius, 31, 63);
    146             make_tex_transition_vertex(verts, 2, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, texTransRadius, 31, 0);
    147             make_tex_transition_vertex(verts, 3, fadeTimer, transData, centerTransX, centerTransY, -texTransRadius, texTransRadius, -31, 0);
    148             break;
    149         case TRANS_TYPE_CLAMP:
    150             make_tex_transition_vertex(verts, 0, fadeTimer, transData, centerTransX, centerTransY, -texTransRadius, -texTransRadius, 0, 63);
    151             make_tex_transition_vertex(verts, 1, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, -texTransRadius, 63, 63);
    152             make_tex_transition_vertex(verts, 2, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, texTransRadius, 63, 0);
    153             make_tex_transition_vertex(verts, 3, fadeTimer, transData, centerTransX, centerTransY, -texTransRadius, texTransRadius, 0, 0);
    154             break;
    155     }
    156     make_tex_transition_vertex(verts, 4, fadeTimer, transData, centerTransX, centerTransY, -2000, -2000, 0, 0);
    157     make_tex_transition_vertex(verts, 5, fadeTimer, transData, centerTransX, centerTransY, 2000, -2000, 0, 0);
    158     make_tex_transition_vertex(verts, 6, fadeTimer, transData, centerTransX, centerTransY, 2000, 2000, 0, 0);
    159     make_tex_transition_vertex(verts, 7, fadeTimer, transData, centerTransX, centerTransY, -2000, 2000, 0, 0);
    160 }
    161 
    162 void *sTextureTransitionID[] = {
    163     texture_transition_star_half,
    164     texture_transition_circle_half,
    165     texture_transition_mario,
    166     texture_transition_bowser_half,
    167 };
    168 
    169 s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData, s8 texID, s8 transTexType) {
    170     f32 texTransTime = calc_tex_transition_time(fadeTimer, transTime, transData);
    171     u16 texTransPos = convert_tex_transition_angle_to_pos(transData);
    172     s16 centerTransX = center_tex_transition_x(transData, texTransTime, texTransPos);
    173     s16 centerTransY = center_tex_transition_y(transData, texTransTime, texTransPos);
    174     s16 texTransRadius = calc_tex_transition_radius(fadeTimer, transTime, transData);
    175     Vtx *verts = alloc_display_list(8 * sizeof(*verts));
    176 
    177     if (verts != NULL) {
    178         load_tex_transition_vertex(verts, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, transTexType);
    179         gSPDisplayList(gDisplayListHead++, dl_proj_mtx_fullscreen)
    180         gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE);
    181         gDPSetRenderMode(gDisplayListHead++, G_RM_AA_OPA_SURF, G_RM_AA_OPA_SURF2);
    182         gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(verts), 8, 0);
    183         gSPDisplayList(gDisplayListHead++, dl_transition_draw_filled_region);
    184         gDPPipeSync(gDisplayListHead++);
    185         gDPSetCombineMode(gDisplayListHead++, G_CC_MODULATEIDECALA, G_CC_MODULATEIDECALA);
    186         gDPSetRenderMode(gDisplayListHead++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2);
    187         gDPSetTextureFilter(gDisplayListHead++, G_TF_BILERP);
    188         switch (transTexType) {
    189         case TRANS_TYPE_MIRROR:
    190             gDPLoadTextureBlock(gDisplayListHead++, sTextureTransitionID[texID], G_IM_FMT_IA, G_IM_SIZ_8b, 32, 64, 0,
    191                 G_TX_WRAP | G_TX_MIRROR, G_TX_WRAP | G_TX_MIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD);
    192             break;
    193         case TRANS_TYPE_CLAMP:
    194             gDPLoadTextureBlock(gDisplayListHead++, sTextureTransitionID[texID], G_IM_FMT_IA, G_IM_SIZ_8b, 64, 64, 0,
    195                 G_TX_CLAMP, G_TX_CLAMP, 6, 6, G_TX_NOLOD, G_TX_NOLOD);
    196             break;
    197         }
    198         gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON);
    199         gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(verts), 4, 0);
    200         gSPDisplayList(gDisplayListHead++, dl_draw_quad_verts_0123);
    201         gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF);
    202         gSPDisplayList(gDisplayListHead++, dl_screen_transition_end);
    203         sTransitionTextureFadeCount[fadeTimer] += transData->texTimer;
    204     } else {
    205     }
    206     return set_and_reset_transition_fade_timer(fadeTimer, transTime);
    207 }
    208 
    209 s32 render_screen_transition(s8 fadeTimer, s8 transType, u8 transTime, struct WarpTransitionData *transData) {
    210     switch (transType) {
    211         case WARP_TRANSITION_FADE_FROM_COLOR:
    212             return render_fade_transition_from_color(fadeTimer, transTime, transData);
    213             break;
    214         case WARP_TRANSITION_FADE_INTO_COLOR:
    215             return render_fade_transition_into_color(fadeTimer, transTime, transData);
    216             break;
    217         case WARP_TRANSITION_FADE_FROM_STAR:
    218             return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_STAR, TRANS_TYPE_MIRROR);
    219             break;
    220         case WARP_TRANSITION_FADE_INTO_STAR:
    221             return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_STAR, TRANS_TYPE_MIRROR);
    222             break;
    223         case WARP_TRANSITION_FADE_FROM_CIRCLE:
    224             return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_CIRCLE, TRANS_TYPE_MIRROR);
    225             break;
    226         case WARP_TRANSITION_FADE_INTO_CIRCLE:
    227             return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_CIRCLE, TRANS_TYPE_MIRROR);
    228             break;
    229         case WARP_TRANSITION_FADE_FROM_MARIO:
    230             return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_MARIO, TRANS_TYPE_CLAMP);
    231             break;
    232         case WARP_TRANSITION_FADE_INTO_MARIO:
    233             return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_MARIO, TRANS_TYPE_CLAMP);
    234             break;
    235         case WARP_TRANSITION_FADE_FROM_BOWSER:
    236             return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_BOWSER, TRANS_TYPE_MIRROR);
    237             break;
    238         case WARP_TRANSITION_FADE_INTO_BOWSER:
    239             return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_BOWSER, TRANS_TYPE_MIRROR);
    240             break;
    241     }
    242 #ifdef AVOID_UB
    243     return 0;
    244 #endif
    245 }
    246 
    247 Gfx *render_cannon_circle_base(void) {
    248 #ifdef WIDESCREEN
    249     Vtx *verts = alloc_display_list(8 * sizeof(*verts));
    250     Gfx *dlist = alloc_display_list(20 * sizeof(*dlist));
    251 #else
    252     Vtx *verts = alloc_display_list(4 * sizeof(*verts));
    253     Gfx *dlist = alloc_display_list(16 * sizeof(*dlist));
    254 #endif
    255     Gfx *g = dlist;
    256 
    257     if (verts != NULL && dlist != NULL) {
    258         make_vertex(verts, 0, 0, 0, -1, -1152, 1824, 0, 0, 0, 255);
    259         make_vertex(verts, 1, SCREEN_WIDTH, 0, -1, 1152, 1824, 0, 0, 0, 255);
    260         make_vertex(verts, 2, SCREEN_WIDTH, SCREEN_HEIGHT, -1, 1152, 192, 0, 0, 0, 255);
    261         make_vertex(verts, 3, 0, SCREEN_HEIGHT, -1, -1152, 192, 0, 0, 0, 255);
    262 
    263 #ifdef WIDESCREEN
    264         // Render black rectangles outside the 4:3 area.
    265         make_vertex(verts, 4, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 0, -1, 0, 0, 0, 0, 0, 255);
    266         make_vertex(verts, 5, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), 0, -1, 0, 0, 0, 0, 0, 255);
    267         make_vertex(verts, 6, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0, 0, 0, 0, 255);
    268         make_vertex(verts, 7, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0, 0, 0, 0, 255);
    269 #endif
    270 
    271         gSPDisplayList(g++, dl_proj_mtx_fullscreen);
    272         gDPSetCombineMode(g++, G_CC_MODULATEIDECALA, G_CC_MODULATEIDECALA);
    273         gDPSetTextureFilter(g++, G_TF_BILERP);
    274         gDPLoadTextureBlock(g++, sTextureTransitionID[TEX_TRANS_CIRCLE], G_IM_FMT_IA, G_IM_SIZ_8b, 32, 64, 0,
    275             G_TX_WRAP | G_TX_MIRROR, G_TX_WRAP | G_TX_MIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD);
    276         gSPTexture(g++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON);
    277         gSPVertex(g++, VIRTUAL_TO_PHYSICAL(verts), 4, 0);
    278         gSPDisplayList(g++, dl_draw_quad_verts_0123);
    279         gSPTexture(g++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF);
    280 #ifdef WIDESCREEN
    281         gDPSetCombineMode(g++, G_CC_SHADE, G_CC_SHADE);
    282         gSPVertex(g++, VIRTUAL_TO_PHYSICAL(verts + 4), 4, 4);
    283         gSP2Triangles(g++, 4, 0, 3, 0, 4, 3, 7, 0);
    284         gSP2Triangles(g++, 1, 5, 6, 0, 1, 6, 2, 0);
    285 #endif
    286         gSPDisplayList(g++, dl_screen_transition_end);
    287         gSPEndDisplayList(g);
    288     } else {
    289         return NULL;
    290     }
    291     return dlist;
    292 }
    293 
    294 Gfx *geo_cannon_circle_base(s32 callContext, struct GraphNode *node, UNUSED Mat4 mtx) {
    295     struct GraphNodeGenerated *graphNode = (struct GraphNodeGenerated *) node;
    296     Gfx *dlist = NULL;
    297 
    298     if (callContext == GEO_CONTEXT_RENDER && gCurrentArea != NULL
    299         && gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON) {
    300         graphNode->fnNode.node.flags = (graphNode->fnNode.node.flags & 0xFF) | 0x500;
    301         dlist = render_cannon_circle_base();
    302     }
    303     return dlist;
    304 }