mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2025-10-30 08:01:01 +00:00
- Add NULL checks to DynOS warps - Change checks for skipping interpolation on the original title screen for much better ones - Interactions are no longer processed if you are on the title screen - Re-add some of the legacy demo code for the original title screen - Fix disconnecting on the original title screen - Fix disconnecting on the act select screen - Fix interpolation crash
586 lines
20 KiB
C
586 lines
20 KiB
C
#include <PR/ultratypes.h>
|
|
|
|
#include "engine/math_util.h"
|
|
#include "game/memory.h"
|
|
#include "game/segment2.h"
|
|
#include "game/segment7.h"
|
|
#include "intro_geo.h"
|
|
#include "sm64.h"
|
|
#include "textures.h"
|
|
#include "types.h"
|
|
#include "buffers/framebuffers.h"
|
|
#include "game/game_init.h"
|
|
#include "audio/external.h"
|
|
#include "prevent_bss_reordering.h"
|
|
|
|
#include "gfx_dimensions.h"
|
|
#include "game/rendering_graph_node.h"
|
|
#include "pc/utils/misc.h"
|
|
|
|
// frame counts for the zoom in, hold, and zoom out of title model
|
|
#define INTRO_STEPS_ZOOM_IN 20
|
|
#define INTRO_STEPS_HOLD_1 75
|
|
#define INTRO_STEPS_ZOOM_OUT 91
|
|
|
|
// background types
|
|
#define INTRO_BACKGROUND_SUPER_MARIO 0
|
|
#define INTRO_BACKGROUND_GAME_OVER 1
|
|
|
|
struct GraphNodeMore {
|
|
/*0x00*/ struct GraphNode node;
|
|
/*0x14*/ void *todo;
|
|
/*0x18*/ u32 unk18;
|
|
};
|
|
|
|
// intro geo bss
|
|
#ifdef VERSION_SH
|
|
static u16 *sFrameBuffers[3];
|
|
#endif
|
|
static s32 sGameOverFrameCounter;
|
|
static s32 sGameOverTableIndex;
|
|
static s16 sIntroFrameCounter;
|
|
static s32 sTmCopyrightAlpha;
|
|
|
|
|
|
// intro screen background texture X offsets
|
|
float introBackgroundOffsetX[] = {
|
|
0.0, 80.0, 160.0, 240.0, 0.0, 80.0, 160.0, 240.0, 0.0, 80.0, 160.0, 240.0,
|
|
};
|
|
|
|
// intro screen background texture Y offsets
|
|
float introBackgroundOffsetY[] = {
|
|
160.0, 160.0, 160.0, 160.0, 80.0, 80.0, 80.0, 80.0, 0.0, 0.0, 0.0, 0.0,
|
|
};
|
|
|
|
// table that points to either the "Super Mario 64" or "Game Over" tables
|
|
const u8 *const *introBackgroundTextureType[] = { mario_title_texture_table, game_over_texture_table };
|
|
|
|
// order of tiles that are flipped from "Game Over" to "Super Mario 64"
|
|
s8 gameOverBackgroundFlipOrder[] = { 0x00, 0x01, 0x02, 0x03, 0x07, 0x0B,
|
|
0x0a, 0x09, 0x08, 0x04, 0x05, 0x06 };
|
|
|
|
static Gfx *sIntroScalePos;
|
|
static Vec3f sIntroScale;
|
|
static Vec3f sIntroScalePrev;
|
|
|
|
bool gSkipInterpolationTitleScreen = false;
|
|
|
|
void patch_title_screen_before(void) {
|
|
sIntroScalePos = NULL;
|
|
}
|
|
|
|
void patch_title_screen_interpolated(f32 delta) {
|
|
if (sIntroScalePos != NULL) {
|
|
Mtx *scaleMat = alloc_display_list(sizeof(*scaleMat));
|
|
if (scaleMat == NULL) { return; }
|
|
Vec3f scaleInterp;
|
|
delta_interpolate_vec3f(scaleInterp, sIntroScalePrev, sIntroScale, delta);
|
|
guScale(scaleMat, scaleInterp[0], scaleInterp[1], scaleInterp[2]);
|
|
gSPMatrix(sIntroScalePos, scaleMat, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
|
|
}
|
|
}
|
|
|
|
Gfx *geo_title_screen(s32 state, struct GraphNode *sp54, UNUSED void *context) {
|
|
struct GraphNode *graphNode; // sp4c
|
|
Gfx *dl; // sp48
|
|
Gfx *dlIter; // sp44
|
|
Mtx *scaleMat; // sp40
|
|
f32 *scaleTable1; // sp3c
|
|
f32 *scaleTable2; // sp38
|
|
f32 scaleX; // sp34
|
|
f32 scaleY; // sp30
|
|
f32 scaleZ; // sp2c
|
|
Vec3f scale;
|
|
graphNode = sp54;
|
|
dl = NULL;
|
|
dlIter = NULL;
|
|
scaleTable1 = segmented_to_virtual(intro_seg7_table_0700C790);
|
|
scaleTable2 = segmented_to_virtual(intro_seg7_table_0700C880);
|
|
if (state != 1) {
|
|
sIntroFrameCounter = 0;
|
|
} else if (state == 1) {
|
|
graphNode->flags = (graphNode->flags & 0xFF) | (LAYER_OPAQUE << 8);
|
|
scaleMat = alloc_display_list(sizeof(*scaleMat));
|
|
dl = alloc_display_list(4 * sizeof(*dl));
|
|
dlIter = dl;
|
|
if (scaleMat == NULL || dl == NULL) { return NULL; }
|
|
|
|
// determine scale based on the frame counter
|
|
if (sIntroFrameCounter >= 0 && sIntroFrameCounter < INTRO_STEPS_ZOOM_IN) {
|
|
// zooming in
|
|
scaleX = scaleTable1[sIntroFrameCounter * 3];
|
|
scaleY = scaleTable1[sIntroFrameCounter * 3 + 1];
|
|
scaleZ = scaleTable1[sIntroFrameCounter * 3 + 2];
|
|
} else if (sIntroFrameCounter >= INTRO_STEPS_ZOOM_IN && sIntroFrameCounter < INTRO_STEPS_HOLD_1) {
|
|
// holding
|
|
scaleX = 1.0f;
|
|
scaleY = 1.0f;
|
|
scaleZ = 1.0f;
|
|
} else if (sIntroFrameCounter >= INTRO_STEPS_HOLD_1 && sIntroFrameCounter < INTRO_STEPS_ZOOM_OUT) {
|
|
// zooming out
|
|
scaleX = scaleTable2[(sIntroFrameCounter - INTRO_STEPS_HOLD_1) * 3];
|
|
scaleY = scaleTable2[(sIntroFrameCounter - INTRO_STEPS_HOLD_1) * 3 + 1];
|
|
scaleZ = scaleTable2[(sIntroFrameCounter - INTRO_STEPS_HOLD_1) * 3 + 2];
|
|
} else {
|
|
// disappeared
|
|
scaleX = 0.0f;
|
|
scaleY = 0.0f;
|
|
scaleZ = 0.0f;
|
|
}
|
|
|
|
vec3f_copy(sIntroScalePrev, sIntroScale);
|
|
vec3f_set(scale, scaleX, scaleY, scaleZ);
|
|
vec3f_set(sIntroScale, scaleX, scaleY, scaleZ);
|
|
|
|
guScale(scaleMat, sIntroScalePrev[0], sIntroScalePrev[1], sIntroScalePrev[2]);
|
|
sIntroScalePos = dlIter;
|
|
gSPMatrix(dlIter++, scaleMat, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
|
|
gSPDisplayList(dlIter++, &intro_seg7_dl_0700B3A0); // draw model
|
|
gSPPopMatrix(dlIter++, G_MTX_MODELVIEW);
|
|
gSPEndDisplayList(dlIter);
|
|
|
|
sIntroFrameCounter++;
|
|
}
|
|
return dl;
|
|
}
|
|
|
|
/**
|
|
* Geo callback to render the "Super Mario 64" logo on the title screen
|
|
*/
|
|
Gfx *geo_intro_super_mario_64_logo(s32 state, struct GraphNode *node, UNUSED void *context) {
|
|
struct GraphNode *graphNode = node;
|
|
Gfx *dl = NULL;
|
|
Gfx *dlIter = NULL;
|
|
Mtx *scaleMat;
|
|
f32 *scaleTable1 = segmented_to_virtual(intro_seg7_table_0700C790);
|
|
f32 *scaleTable2 = segmented_to_virtual(intro_seg7_table_0700C880);
|
|
f32 scaleX;
|
|
f32 scaleY;
|
|
f32 scaleZ;
|
|
|
|
if (state != 1) {
|
|
sIntroFrameCounter = 0;
|
|
} else if (state == 1) {
|
|
graphNode->flags = (graphNode->flags & 0xFF) | (LAYER_OPAQUE << 8);
|
|
scaleMat = alloc_display_list(sizeof(*scaleMat));
|
|
dl = alloc_display_list(4 * sizeof(*dl));
|
|
if (scaleMat == NULL || dl == NULL) { return NULL; }
|
|
dlIter = dl;
|
|
|
|
// determine scale based on the frame counter
|
|
if (sIntroFrameCounter >= 0 && sIntroFrameCounter < INTRO_STEPS_ZOOM_IN) {
|
|
// zooming in
|
|
scaleX = scaleTable1[sIntroFrameCounter * 3];
|
|
scaleY = scaleTable1[sIntroFrameCounter * 3 + 1];
|
|
scaleZ = scaleTable1[sIntroFrameCounter * 3 + 2];
|
|
} else if (sIntroFrameCounter >= INTRO_STEPS_ZOOM_IN && sIntroFrameCounter < INTRO_STEPS_HOLD_1) {
|
|
// holding
|
|
scaleX = 1.0f;
|
|
scaleY = 1.0f;
|
|
scaleZ = 1.0f;
|
|
} else if (sIntroFrameCounter >= INTRO_STEPS_HOLD_1 && sIntroFrameCounter < INTRO_STEPS_ZOOM_OUT) {
|
|
// zooming out
|
|
scaleX = scaleTable2[(sIntroFrameCounter - INTRO_STEPS_HOLD_1) * 3];
|
|
scaleY = scaleTable2[(sIntroFrameCounter - INTRO_STEPS_HOLD_1) * 3 + 1];
|
|
scaleZ = scaleTable2[(sIntroFrameCounter - INTRO_STEPS_HOLD_1) * 3 + 2];
|
|
} else {
|
|
// disappeared
|
|
scaleX = 0.0f;
|
|
scaleY = 0.0f;
|
|
scaleZ = 0.0f;
|
|
}
|
|
guScale(scaleMat, scaleX, scaleY, scaleZ);
|
|
|
|
gSPMatrix(dlIter++, scaleMat, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
|
|
gSPDisplayList(dlIter++, &intro_seg7_dl_0700B3A0); // draw model
|
|
gSPPopMatrix(dlIter++, G_MTX_MODELVIEW);
|
|
gSPEndDisplayList(dlIter);
|
|
|
|
sIntroFrameCounter++;
|
|
}
|
|
return dl;
|
|
}
|
|
|
|
/**
|
|
* Geo callback to render TM and Copyright on the title screen
|
|
*/
|
|
Gfx *geo_intro_tm_copyright(s32 state, struct GraphNode *node, UNUSED void *context) {
|
|
struct GraphNode *graphNode = node;
|
|
Gfx *dl = NULL;
|
|
Gfx *dlIter = NULL;
|
|
|
|
if (state != 1) { // reset
|
|
sTmCopyrightAlpha = 0;
|
|
} else if (state == 1) { // draw
|
|
dl = alloc_display_list(5 * sizeof(*dl));
|
|
if (dl == NULL) { return NULL; }
|
|
dlIter = dl;
|
|
gSPDisplayList(dlIter++, dl_proj_mtx_fullscreen);
|
|
gDPSetEnvColor(dlIter++, 255, 255, 255, sTmCopyrightAlpha);
|
|
switch (sTmCopyrightAlpha) {
|
|
case 255: // opaque
|
|
graphNode->flags = (graphNode->flags & 0xFF) | (LAYER_OPAQUE << 8);
|
|
gDPSetRenderMode(dlIter++, G_RM_AA_OPA_SURF, G_RM_AA_OPA_SURF2);
|
|
break;
|
|
default: // blend
|
|
graphNode->flags = (graphNode->flags & 0xFF) | (LAYER_TRANSPARENT << 8);
|
|
gDPSetRenderMode(dlIter++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2);
|
|
break;
|
|
}
|
|
gSPDisplayList(dlIter++, &intro_seg7_dl_0700C6A0); // draw model
|
|
gSPEndDisplayList(dlIter);
|
|
|
|
// Once the "Super Mario 64" logo has just about zoomed fully, fade in the "TM" and copyright text
|
|
if (sIntroFrameCounter >= 19) {
|
|
sTmCopyrightAlpha += 26;
|
|
if (sTmCopyrightAlpha > 255) {
|
|
sTmCopyrightAlpha = 255;
|
|
}
|
|
}
|
|
}
|
|
return dl;
|
|
}
|
|
|
|
/**
|
|
* Generates a display list for a single background tile
|
|
*
|
|
* @param index which tile to render (value from 0 to 11)
|
|
* @param backgroundTable array describing which image to use for each tile (0 denotes a "Super Mario 64" image, and 1 denotes a "Game Over" image)
|
|
*/
|
|
static Gfx *intro_backdrop_one_image(s32 index, s8 *backgroundTable) {
|
|
// intro screen background display lists for each of four 80x20 textures
|
|
static const Gfx *introBackgroundDlRows[] = { title_screen_bg_dl_0A000130, title_screen_bg_dl_0A000148,
|
|
title_screen_bg_dl_0A000160, title_screen_bg_dl_0A000178 };
|
|
|
|
// intro screen background texture X offsets
|
|
static float xCoords[] = {
|
|
0, 80, 160, 240,
|
|
0, 80, 160, 240,
|
|
0, 80, 160, 240,
|
|
};
|
|
|
|
// intro screen background texture Y offsets
|
|
static float yCoords[] = {
|
|
160, 160, 160, 160,
|
|
80, 80, 80, 80,
|
|
0, 0, 0, 0,
|
|
};
|
|
|
|
// table that points to either the "Super Mario 64" or "Game Over" tables
|
|
static const u8 *const *textureTables[] = { mario_title_texture_table, game_over_texture_table };
|
|
|
|
Mtx *mtx = alloc_display_list(sizeof(*mtx));
|
|
Gfx *displayList = alloc_display_list(36 * sizeof(*displayList));
|
|
if (mtx == NULL || displayList == NULL) { return NULL; }
|
|
Gfx *displayListIter = displayList;
|
|
const u8 *const *vIntroBgTable = segmented_to_virtual(textureTables[backgroundTable[index]]);
|
|
s32 i;
|
|
|
|
guTranslate(mtx, xCoords[index], yCoords[index], 0.0f);
|
|
gSPMatrix(displayListIter++, mtx, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_PUSH);
|
|
gSPDisplayList(displayListIter++, &title_screen_bg_dl_0A000118);
|
|
for (i = 0; i < 4; ++i) {
|
|
gDPLoadTextureBlock(displayListIter++, vIntroBgTable[i], G_IM_FMT_RGBA, G_IM_SIZ_16b, 80, 20, 0,
|
|
G_TX_CLAMP, G_TX_CLAMP, 7, 6, G_TX_NOLOD, G_TX_NOLOD)
|
|
gSPDisplayList(displayListIter++, introBackgroundDlRows[i]);
|
|
}
|
|
gSPPopMatrix(displayListIter++, G_MTX_MODELVIEW);
|
|
gSPEndDisplayList(displayListIter);
|
|
return displayList;
|
|
}
|
|
|
|
static s8 introBackgroundIndexTable[] = {
|
|
INTRO_BACKGROUND_SUPER_MARIO, INTRO_BACKGROUND_SUPER_MARIO, INTRO_BACKGROUND_SUPER_MARIO,
|
|
INTRO_BACKGROUND_SUPER_MARIO, INTRO_BACKGROUND_SUPER_MARIO, INTRO_BACKGROUND_SUPER_MARIO,
|
|
INTRO_BACKGROUND_SUPER_MARIO, INTRO_BACKGROUND_SUPER_MARIO, INTRO_BACKGROUND_SUPER_MARIO,
|
|
INTRO_BACKGROUND_SUPER_MARIO, INTRO_BACKGROUND_SUPER_MARIO, INTRO_BACKGROUND_SUPER_MARIO,
|
|
};
|
|
|
|
// only one table of indexes listed
|
|
static s8 *introBackgroundTables[] = { introBackgroundIndexTable };
|
|
|
|
/**
|
|
* Geo callback to render the intro background tiles
|
|
*/
|
|
Gfx *geo_intro_regular_backdrop(s32 state, struct GraphNode *node, UNUSED void *context) {
|
|
struct GraphNodeMore *graphNode = (struct GraphNodeMore *) node;
|
|
s32 index = graphNode->unk18 & 0xff; // TODO: word at offset 0x18 of struct GraphNode (always ends up being 0)
|
|
s8 *backgroundTable = introBackgroundTables[index];
|
|
Gfx *dl = NULL;
|
|
Gfx *dlIter = NULL;
|
|
s32 i;
|
|
f32 aspect = GFX_DIMENSIONS_ASPECT_RATIO;
|
|
s32 num_tiles_h = (((aspect*SCREEN_HEIGHT)+79)/80);
|
|
|
|
if (state == 1) { // draw
|
|
dl = alloc_display_list(((num_tiles_h*3)+4) * sizeof(*dl));
|
|
if (dl == NULL) { return NULL; }
|
|
dlIter = dl;
|
|
graphNode->node.flags = (graphNode->node.flags & 0xFF) | (LAYER_OPAQUE << 8);
|
|
gSPDisplayList(dlIter++, &dl_proj_mtx_fullscreen);
|
|
gSPDisplayList(dlIter++, &title_screen_bg_dl_0A000100);
|
|
for (i = 0; i < num_tiles_h*3; ++i) {
|
|
gSPDisplayList(dlIter++, intro_backdrop_one_image(i, backgroundTable));
|
|
}
|
|
gSPDisplayList(dlIter++, &title_screen_bg_dl_0A000190);
|
|
gSPEndDisplayList(dlIter);
|
|
}
|
|
return dl;
|
|
}
|
|
|
|
static s8 gameOverBackgroundTable[] = {
|
|
INTRO_BACKGROUND_GAME_OVER, INTRO_BACKGROUND_GAME_OVER, INTRO_BACKGROUND_GAME_OVER,
|
|
INTRO_BACKGROUND_GAME_OVER, INTRO_BACKGROUND_GAME_OVER, INTRO_BACKGROUND_GAME_OVER,
|
|
INTRO_BACKGROUND_GAME_OVER, INTRO_BACKGROUND_GAME_OVER, INTRO_BACKGROUND_GAME_OVER,
|
|
INTRO_BACKGROUND_GAME_OVER, INTRO_BACKGROUND_GAME_OVER, INTRO_BACKGROUND_GAME_OVER,
|
|
};
|
|
|
|
/**
|
|
* Geo callback to render the Game Over background tiles
|
|
*/
|
|
Gfx *geo_intro_gameover_backdrop(s32 state, struct GraphNode *node, UNUSED void *context) {
|
|
struct GraphNode *graphNode = node;
|
|
Gfx *dl = NULL;
|
|
Gfx *dlIter = NULL;
|
|
f32 aspect = GFX_DIMENSIONS_ASPECT_RATIO;
|
|
s32 num_tiles_h = (((aspect*SCREEN_HEIGHT)+79)/80);
|
|
s32 j;
|
|
s32 i;
|
|
|
|
if (state != 1) { // reset
|
|
sGameOverFrameCounter = 0;
|
|
sGameOverTableIndex = -2;
|
|
for (i = 0; i < ARRAY_COUNT(gameOverBackgroundTable); ++i)
|
|
gameOverBackgroundTable[i] = INTRO_BACKGROUND_GAME_OVER;
|
|
} else { // draw
|
|
dl = alloc_display_list(((num_tiles_h*3)+4) * sizeof(*dl));
|
|
if (dl == NULL) { return NULL; }
|
|
dlIter = dl;
|
|
if (sGameOverTableIndex == -2) {
|
|
if (sGameOverFrameCounter == 180) {
|
|
sGameOverTableIndex++;
|
|
sGameOverFrameCounter = 0;
|
|
}
|
|
} else {
|
|
// transition tile from "Game Over" to "Super Mario 64"
|
|
if (sGameOverTableIndex != 11 && !(sGameOverFrameCounter & 0x1)) {
|
|
// order of tiles that are flipped from "Game Over" to "Super Mario 64"
|
|
static s8 flipOrder[] = { 0, 1, 2, 3, 7, 11, 10, 9, 8, 4, 5, 6 };
|
|
|
|
sGameOverTableIndex++;
|
|
gameOverBackgroundTable[flipOrder[sGameOverTableIndex]] =
|
|
INTRO_BACKGROUND_SUPER_MARIO;
|
|
}
|
|
}
|
|
if (sGameOverTableIndex != 11) {
|
|
sGameOverFrameCounter++;
|
|
}
|
|
graphNode->flags = (graphNode->flags & 0xFF) | (LAYER_OPAQUE << 8);
|
|
|
|
// draw all the tiles
|
|
gSPDisplayList(dlIter++, &dl_proj_mtx_fullscreen);
|
|
gSPDisplayList(dlIter++, &title_screen_bg_dl_0A000100);
|
|
for (j = 0; j < num_tiles_h*3; ++j) {
|
|
gSPDisplayList(dlIter++, intro_backdrop_one_image(j, gameOverBackgroundTable));
|
|
}
|
|
gSPDisplayList(dlIter++, &title_screen_bg_dl_0A000190);
|
|
gSPEndDisplayList(dlIter);
|
|
}
|
|
return dl;
|
|
}
|
|
|
|
#ifdef VERSION_SH
|
|
extern Gfx title_screen_bg_dl_0A0065E8[];
|
|
extern Gfx title_screen_bg_dl_0A006618[];
|
|
extern Gfx title_screen_bg_dl_0A007548[];
|
|
|
|
//Data
|
|
s8 sFaceVisible[] = {
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 0, 0, 0, 0, 1, 1,
|
|
1, 1, 0, 0, 0, 0, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
};
|
|
|
|
s8 sFaceToggleOrder[] = {
|
|
0, 1, 2, 3, 4, 5, 6, 7,
|
|
15, 23, 31, 39, 47, 46, 45, 44,
|
|
43, 42, 41, 40, 32, 24, 16, 8,
|
|
9, 10, 11, 12, 13, 14, 22, 30,
|
|
38, 37, 36, 35, 34, 33, 25, 17,
|
|
};
|
|
|
|
s8 sFaceCounter = 0;
|
|
|
|
void intro_gen_face_texrect(Gfx **dlIter)
|
|
{
|
|
s32 x;
|
|
s32 y;
|
|
|
|
for (y = 0; y < 6; y++) {
|
|
for (x = 0; x < 8; x++) {
|
|
if (sFaceVisible[y*8 + x] != 0) {
|
|
gSPTextureRectangle((*dlIter)++, (x * 40) << 2, (y * 40) << 2, (x * 40 + 39) << 2, (y * 40 + 39) << 2, 0,
|
|
0, 0, 4 << 10, 1 << 10);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Gfx *intro_draw_face(u16 *image, s32 imageW, s32 imageH)
|
|
{
|
|
Gfx *dl;
|
|
Gfx *dlIter;
|
|
|
|
dl = alloc_display_list(110 * sizeof(Gfx));
|
|
|
|
if (dl == NULL) {
|
|
return dl;
|
|
} else {
|
|
dlIter = dl;
|
|
}
|
|
|
|
gSPDisplayList(dlIter++, title_screen_bg_dl_0A0065E8);
|
|
|
|
gDPLoadTextureBlock(dlIter++, VIRTUAL_TO_PHYSICAL(image), G_IM_FMT_RGBA, G_IM_SIZ_16b, imageW, imageH, 0, G_TX_CLAMP | G_TX_NOMIRROR, G_TX_CLAMP | G_TX_NOMIRROR, 6, 6, G_TX_NOLOD, G_TX_NOLOD);
|
|
|
|
intro_gen_face_texrect(&dlIter);
|
|
|
|
gSPDisplayList(dlIter++, title_screen_bg_dl_0A006618);
|
|
|
|
gSPEndDisplayList(dlIter++);
|
|
|
|
return dl;
|
|
}
|
|
|
|
u16 *intro_sample_frame_buffer(s32 imageW, s32 imageH, s32 sampleW, s32 sampleH) {
|
|
u16 *fb;
|
|
u16 *image;
|
|
s32 pixel;
|
|
f32 size;
|
|
f32 r, g, b;
|
|
s32 iy, ix, sy, sx;
|
|
|
|
s32 xOffset = 120;
|
|
s32 yOffset = 80;
|
|
|
|
fb = sFrameBuffers[frameBufferIndex];
|
|
image = alloc_display_list(imageW * imageH * sizeof(u16));
|
|
|
|
if (image == NULL) {
|
|
return image;
|
|
}
|
|
|
|
for (iy = 0; iy < imageH; iy++) {
|
|
for (ix = 0; ix < imageW; ix++) {
|
|
r = 0;
|
|
g = 0;
|
|
b = 0;
|
|
|
|
for (sy = 0; sy < sampleH; sy++) {
|
|
for (sx = 0; sx < sampleW; sx++) {
|
|
u16 fbr, fbg, fbb;
|
|
f32 f1, f2, f3;
|
|
pixel = 320 * (sampleH * iy + sy + yOffset) + (sampleW * ix + xOffset) + sx;
|
|
|
|
fbr = fb[pixel];
|
|
fbg = fb[pixel];
|
|
fbb = fb[pixel];
|
|
|
|
f1 = ((fbr >> 0xB) & 0x1F);
|
|
f2 = ((fbg >> 0x6) & 0x1F);
|
|
f3 = ((fbb >> 0x1) & 0x1F);
|
|
|
|
r += f1;
|
|
g += f2;
|
|
b += f3;
|
|
}
|
|
}
|
|
|
|
size = sampleW * sampleH;
|
|
image[imageH * iy + ix] = ((((u16) (r / size + 0.5) << 0xB) & 0xF800) & 0xffff) +
|
|
((((u16) (g / size + 0.5) << 0x6) & 0x7C0) & 0xffff) +
|
|
((((u16) (b / size + 0.5) << 0x1) & 0x3E) & 0xffff) + 1;
|
|
}
|
|
}
|
|
|
|
return image;
|
|
}
|
|
|
|
Gfx *geo_intro_face_easter_egg(s32 state, struct GraphNode *node, UNUSED void *context) {
|
|
struct GraphNodeGenerated *genNode = (struct GraphNodeGenerated *)node;
|
|
u16 *image;
|
|
Gfx *dl = NULL;
|
|
s32 i;
|
|
|
|
if (state != 1) {
|
|
sFrameBuffers[0] = gFrameBuffer0;
|
|
sFrameBuffers[1] = gFrameBuffer1;
|
|
sFrameBuffers[2] = gFrameBuffer2;
|
|
|
|
for (i = 0; i < 48; i++) {
|
|
sFaceVisible[i] = 0;
|
|
}
|
|
|
|
} else if (state == 1) {
|
|
if (sFaceCounter == 0) {
|
|
if (gPlayer1Controller->buttonPressed & Z_TRIG) {
|
|
play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource);
|
|
sFaceVisible[0] ^= 1;
|
|
sFaceCounter++;
|
|
}
|
|
} else {
|
|
sFaceVisible[sFaceToggleOrder[sFaceCounter++]] ^= 1;
|
|
if (sFaceCounter >= 40) {
|
|
sFaceCounter = 0;
|
|
}
|
|
}
|
|
|
|
// Draw while the first or last face is visible.
|
|
if (sFaceVisible[0] == 1 || sFaceVisible[17] == 1) {
|
|
image = intro_sample_frame_buffer(40, 40, 2, 2);
|
|
if (image != NULL) {
|
|
genNode->fnNode.node.flags = (genNode->fnNode.node.flags & 0xFF) | (LAYER_OPAQUE << 8);
|
|
dl = intro_draw_face(image, 40, 40);
|
|
}
|
|
}
|
|
}
|
|
|
|
return dl;
|
|
}
|
|
|
|
Gfx *geo_intro_rumble_pak_graphic(s32 state, struct GraphNode *node, UNUSED void *context) {
|
|
struct GraphNodeGenerated *genNode = (struct GraphNodeGenerated *)node;
|
|
Gfx *dlIter;
|
|
Gfx *dl;
|
|
s32 introContext;
|
|
s8 backgroundTileSix;
|
|
|
|
if (state != 1) {
|
|
dl = NULL;
|
|
} else if (state == 1) {
|
|
genNode->fnNode.node.flags = (genNode->fnNode.node.flags & 0xFF) | (LAYER_OPAQUE << 8);
|
|
introContext = genNode->parameter & 0xFF;
|
|
if (introContext == 0) {
|
|
backgroundTileSix = introBackgroundIndexTable[6];
|
|
} else if (introContext == 1) {
|
|
backgroundTileSix = gameOverBackgroundTable[6];
|
|
}
|
|
if (backgroundTileSix == INTRO_BACKGROUND_SUPER_MARIO) {
|
|
dl = alloc_display_list(3 * sizeof(*dl));
|
|
if (dl != NULL) {
|
|
dlIter = dl;
|
|
gSPDisplayList(dlIter++, &title_screen_bg_dl_0A007548);
|
|
gSPEndDisplayList(dlIter);
|
|
}
|
|
} else {
|
|
dl = NULL;
|
|
}
|
|
}
|
|
return dl;
|
|
}
|
|
|
|
#endif
|
|
|