From 100576edc9277c06db3ffcbb0ebf5e392f860d25 Mon Sep 17 00:00:00 2001 From: Tharo <17233964+Thar0@users.noreply.github.com> Date: Tue, 4 Jul 2023 03:30:53 +0100 Subject: [PATCH] Documentation for skybox drawing (#1515) --- include/z64skybox.h | 10 +- src/code/z_play.c | 5 +- src/code/z_vr_box.c | 673 ++++++++++++++++++++++----------------- src/code/z_vr_box_draw.c | 56 ++-- 4 files changed, 425 insertions(+), 319 deletions(-) diff --git a/include/z64skybox.h b/include/z64skybox.h index 7df2f56d77..d97efe4567 100644 --- a/include/z64skybox.h +++ b/include/z64skybox.h @@ -41,14 +41,20 @@ typedef enum { /* 0x27 */ SKYBOX_UNSET_27 = 39 } SkyboxId; +typedef enum { + /* 0 */ SKYBOX_DRAW_128, // 128x128 top/bottom faces, 128x64 side faces + /* 1 */ SKYBOX_DRAW_256_4FACE, // 256x256 all side faces with per-face palettes + /* 2 */ SKYBOX_DRAW_256_3FACE // 256x256 3/4 side faces with per-face palettes +} SkyboxDrawType; + typedef struct SkyboxContext { /* 0x000 */ char unk_00[0x128]; /* 0x128 */ void* staticSegments[2]; /* 0x130 */ u16 (*palettes)[256]; /* 0x134 */ Gfx (*dListBuf)[150]; - /* 0x138 */ Gfx* unk_138; + /* 0x138 */ Gfx* gfx; /* 0x13C */ Vtx* roomVtx; - /* 0x140 */ s16 unk_140; + /* 0x140 */ s16 drawType; /* 0x144 */ Vec3f rot; /* 0x150 */ char unk_150[0x10]; } SkyboxContext; // size = 0x160 diff --git a/src/code/z_play.c b/src/code/z_play.c index 4eeaa8111d..b3d4447f54 100644 --- a/src/code/z_play.c +++ b/src/code/z_play.c @@ -1151,7 +1151,7 @@ void Play_Draw(PlayState* this) { Environment_UpdateSkybox(this->skyboxId, &this->envCtx, &this->skyboxCtx); Skybox_Draw(&this->skyboxCtx, gfxCtx, this->skyboxId, this->envCtx.skyboxBlend, this->view.eye.x, this->view.eye.y, this->view.eye.z); - } else if (this->skyboxCtx.unk_140 == 0) { + } else if (this->skyboxCtx.drawType == SKYBOX_DRAW_128) { Skybox_Draw(&this->skyboxCtx, gfxCtx, this->skyboxId, 0, this->view.eye.x, this->view.eye.y, this->view.eye.z); } @@ -1193,7 +1193,8 @@ void Play_Draw(PlayState* this) { } if ((R_HREG_MODE != HREG_MODE_PLAY) || R_PLAY_DRAW_SKYBOX) { - if ((this->skyboxCtx.unk_140 != 0) && (GET_ACTIVE_CAM(this)->setting != CAM_SET_PREREND_FIXED)) { + if ((this->skyboxCtx.drawType != SKYBOX_DRAW_128) && + (GET_ACTIVE_CAM(this)->setting != CAM_SET_PREREND_FIXED)) { Vec3f quakeOffset; Camera_GetQuakeOffset(&quakeOffset, GET_ACTIVE_CAM(this)); diff --git a/src/code/z_vr_box.c b/src/code/z_vr_box.c index 56cd74cb38..1b10791480 100644 --- a/src/code/z_vr_box.c +++ b/src/code/z_vr_box.c @@ -2,371 +2,452 @@ #include "terminal.h" #include "z64environment.h" -u32 D_8012AC90[4] = { - 0x00000000, - 0x00010000, - 0x00020000, - 0x00030000, -}; - -u16 D_8012ACA0[2][0x20] = { - { 0x00, 0x02, 0x0A, 0x0C, 0x02, 0x04, 0x0C, 0x0E, 0x0A, 0x0C, 0x14, 0x16, 0x0C, 0x0E, 0x16, 0x18, - 0x01, 0x03, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0B, 0x0D, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x15, 0x17 }, - { 0x14, 0x16, 0x1E, 0x20, 0x16, 0x18, 0x20, 0x22, 0x1E, 0x20, 0x28, 0x2A, 0x20, 0x22, 0x2A, 0x2C, - 0x15, 0x17, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1F, 0x21, 0x23, 0x24, 0x25, 0x26, 0x27, 0x29, 0x2B }, -}; - -s16 D_8012AD20[5] = { - 0x0000, 0x0FC0, 0x1F80, 0x2F40, 0x3F00, -}; - -s16 D_8012AD2C[9] = { - 0x0000, 0x07C0, 0x0F80, 0x1740, 0x1F00, 0x26C0, 0x2E80, 0x3640, 0x3E00, -}; - -s16 D_8012AD40[0x40] = { - 0x00, 0x10, 0x13, 0x12, 0x10, 0x01, 0x14, 0x13, 0x01, 0x11, 0x15, 0x14, 0x11, 0x05, 0x16, 0x15, - 0x12, 0x13, 0x17, 0x02, 0x13, 0x14, 0x03, 0x17, 0x14, 0x15, 0x18, 0x03, 0x15, 0x16, 0x07, 0x18, - 0x02, 0x17, 0x1A, 0x19, 0x17, 0x03, 0x1B, 0x1A, 0x03, 0x18, 0x1C, 0x1B, 0x18, 0x07, 0x1D, 0x1C, - 0x19, 0x1A, 0x1E, 0x0A, 0x1A, 0x1B, 0x0B, 0x1E, 0x1B, 0x1C, 0x1F, 0x0B, 0x1C, 0x1D, 0x0F, 0x1F, -}; - -u32 D_8012ADC0[6] = { - 0x00000000, 0x00002000, 0x00004000, 0x00006000, 0x00008000, 0x0000C000, -}; - -u16 D_8012ADD8[0x20] = { - 0x00, 0x02, 0x0A, 0x0C, 0x02, 0x04, 0x0C, 0x0E, 0x0A, 0x0C, 0x14, 0x16, 0x0C, 0x0E, 0x16, 0x18, - 0x01, 0x03, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0B, 0x0D, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x15, 0x17, -}; - -s16 D_8012AE18[5] = { - 0x0000, 0x07C0, 0x0F80, 0x1740, 0x1F00, -}; - -s16 D_8012AE24[5] = { - 0x0000, 0x07C0, 0x0F80, 0x1740, 0x1F00, -}; - -s16 D_8012AE30[5] = { - 0x0000, 0x07C0, 0x0F80, 0x07C0, 0x0000, -}; - -s16 D_8012AE3C[0x40] = { - 0x00, 0x10, 0x13, 0x12, 0x10, 0x01, 0x14, 0x13, 0x01, 0x11, 0x15, 0x14, 0x11, 0x05, 0x16, 0x15, - 0x12, 0x13, 0x17, 0x02, 0x13, 0x14, 0x03, 0x17, 0x14, 0x15, 0x18, 0x03, 0x15, 0x16, 0x07, 0x18, - 0x02, 0x17, 0x1A, 0x19, 0x17, 0x03, 0x1B, 0x1A, 0x03, 0x18, 0x1C, 0x1B, 0x18, 0x07, 0x1D, 0x1C, - 0x19, 0x1A, 0x1E, 0x0A, 0x1A, 0x1B, 0x0B, 0x1E, 0x1B, 0x1C, 0x1F, 0x0B, 0x1C, 0x1D, 0x0F, 0x1F, -}; - typedef struct { - /* 0x000 */ s32 unk_0; - /* 0x004 */ s32 unk_4; - /* 0x008 */ s32 unk_8; - /* 0x00C */ s32 unk_C; - /* 0x010 */ s32 unk_10; -} Struct_8012AF0C; // size = 0x14 + /* 0x000 */ s32 xStart; + /* 0x004 */ s32 yStart; + /* 0x008 */ s32 zStart; + /* 0x00C */ s32 outerIncrVal; + /* 0x010 */ s32 innerIncrVal; +} SkyboxFaceParams; // size = 0x14 -Struct_8012AF0C D_8012AEBC[4] = { - { -0x7E, 0x7C, -0x7E, 0x3F, -0x1F }, - { 0x7E, 0x7C, -0x7E, 0x3F, -0x1F }, - { 0x7E, 0x7C, 0x7E, -0x3F, -0x1F }, - { -0x7E, 0x7C, 0x7E, -0x3F, -0x1F }, +// Converts texture coordinate values to s10.5 fixed point +#define TC(x) ((s16)((x)*32)) + +// Texture offsets for each face in the static segment buffer +u32 sSkybox256TexOffsets[4] = { + 256 * 256 * 0, + 256 * 256 * 1, + 256 * 256 * 2, + 256 * 256 * 3, }; -Struct_8012AF0C D_8012AF0C[6] = { - { -0x40, 0x40, -0x40, 0x20, -0x20 }, { 0x40, 0x40, 0x40, -0x20, -0x20 }, { -0x40, 0x40, 0x40, -0x20, -0x20 }, - { 0x40, 0x40, -0x40, 0x20, -0x20 }, { -0x40, 0x40, 0x40, 0x20, -0x20 }, { -0x40, -0x40, -0x40, 0x20, 0x20 }, +// Maps vertex buffer index to coordinate buffer index +u16 sSkybox256VtxBufIndices[2][32] = { + { + 0, 2, 10, 12, 2, 4, 12, 14, 10, 12, 20, 22, 12, 14, 22, 24, + 1, 3, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 21, 23, + }, + { + 20, 22, 30, 32, 22, 24, 32, 34, 30, 32, 40, 42, 32, 34, 42, 44, + 21, 23, 25, 26, 27, 28, 29, 31, 33, 35, 36, 37, 38, 39, 41, 43, + }, }; -s32 func_800ADBB0(SkyboxContext* skyboxCtx, Vtx* roomVtx, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6, s32 arg7, - s32 arg8, s32 arg9) { - u32 pad42C; - s32 pad428; - s32 sp424; +// S coordinates for all faces +s16 sSkybox256TexSCoords[5] = { + TC(126 * 0), TC(126 * 1), TC(126 * 2), TC(126 * 3), TC(126 * 4), +}; + +// T coordinates for all faces +s16 sSkybox256TexTCoords[9] = { + TC(62 * 0), TC(62 * 1), TC(62 * 2), TC(62 * 3), TC(62 * 4), TC(62 * 5), TC(62 * 6), TC(62 * 7), TC(62 * 8), +}; + +// Maps vertex index to vertex buffer index +s16 sSkybox256VtxIndices[64] = { + 0, 16, 19, 18, 16, 1, 20, 19, 1, 17, 21, 20, 17, 5, 22, 21, 18, 19, 23, 2, 19, 20, + 3, 23, 20, 21, 24, 3, 21, 22, 7, 24, 2, 23, 26, 25, 23, 3, 27, 26, 3, 24, 28, 27, + 24, 7, 29, 28, 25, 26, 30, 10, 26, 27, 11, 30, 27, 28, 31, 11, 28, 29, 15, 31, +}; + +/** + * Build the vertex and display list data for a skybox with 256x256 face textures. + * + * While the textures are nominally 256x256 the 4x8 tiles that cover it are only 63x31, therefore only a + * 253x249 area is ever sampled (253 = 4 * 63 + 1, the additional +1 accounts for bilinear filtering, + * similarly 249 = 8 * 31 + 1) + * + * Each texture dimension is padded to the next power of 2, resulting in a final size of 256x256. + */ +s32 Skybox_CalculateFace256(SkyboxContext* skyboxCtx, Vtx* roomVtx, s32 roomVtxStartIndex, s32 xStart, s32 yStart, + s32 zStart, s32 innerIncrVal, s32 outerIncrVal, s32 faceNum, s32 dlistBufStartIndex) { + u32 innerIncr; + s32 outerIncr; + s32 n; s32 i; s32 j; s32 k; u16 index; - s16 phi_t1; - s16 phi_a2_4; - s16 phi_a0_4; - s16 phi_t2_4; - s16 phi_ra; - s32 sp358[9 * 5]; - s32 sp2A4[9 * 5]; - s32 sp1F0[9 * 5]; - s32 sp13C[9 * 5]; - s32 sp88[9 * 5]; + s16 m; + s16 ult; + s16 uls; + s16 vtxIdx; + s16 l; + s32 xPoints[9 * 5]; + s32 yPoints[9 * 5]; + s32 zPoints[9 * 5]; + s32 tcS[9 * 5]; + s32 tcT[9 * 5]; s32 pad; - switch (arg8) { - case 0: + // Collect all vertex positions for this face + switch (faceNum) { + case 0: // xy plane case 2: - pad428 = arg4; + outerIncr = yStart; + + for (i = 0, k = 0; k < 9 * 5; i++) { + innerIncr = xStart; - for (i = 0, k = 0; k < 45; i++) { - pad42C = arg3; for (j = 0; j < 5; j++, k++) { - sp1F0[k] = arg5; - sp358[k] = pad42C; - sp2A4[k] = pad428; - sp13C[k] = D_8012AD20[j]; - sp88[k] = D_8012AD2C[i]; - pad42C += arg6; + zPoints[k] = zStart; + xPoints[k] = innerIncr; + yPoints[k] = outerIncr; + tcS[k] = sSkybox256TexSCoords[j]; + tcT[k] = sSkybox256TexTCoords[i]; + innerIncr += innerIncrVal; } - pad428 += arg7; + outerIncr += outerIncrVal; } break; - case 1: + case 1: // yz plane case 3: - pad428 = arg4; + outerIncr = yStart; + + for (i = 0, k = 0; k < 9 * 5; i++) { + innerIncr = zStart; - for (i = 0, k = 0; k < 45; i++) { - pad42C = arg5; for (j = 0; j < 5; j++, k++) { - sp358[k] = arg3; - sp2A4[k] = pad428; - sp1F0[k] = pad42C; - sp13C[k] = D_8012AD20[j]; - sp88[k] = D_8012AD2C[i]; - pad42C += arg6; + xPoints[k] = xStart; + yPoints[k] = outerIncr; + zPoints[k] = innerIncr; + tcS[k] = sSkybox256TexSCoords[j]; + tcT[k] = sSkybox256TexTCoords[i]; + innerIncr += innerIncrVal; } - pad428 += arg7; + outerIncr += outerIncrVal; } break; - case 4: + case 4: // xz plane case 5: - pad428 = arg5; + outerIncr = zStart; + + for (i = 0, k = 0; k < 9 * 5; i++) { + innerIncr = xStart; - for (i = 0, k = 0; k < 45; i++) { - pad42C = arg3; for (j = 0; j < 5; j++, k++) { - sp2A4[k] = arg4; - sp358[k] = pad42C; - sp1F0[k] = pad428; - sp13C[k] = D_8012AD20[j]; - sp88[k] = D_8012AD2C[i]; - pad42C += arg6; + yPoints[k] = yStart; + xPoints[k] = innerIncr; + zPoints[k] = outerIncr; + tcS[k] = sSkybox256TexSCoords[j]; + tcT[k] = sSkybox256TexTCoords[i]; + innerIncr += innerIncrVal; } - pad428 += arg7; + outerIncr += outerIncrVal; } break; } - for (phi_a2_4 = 0, sp424 = 0; sp424 < 2; sp424++) { - skyboxCtx->unk_138 = skyboxCtx->dListBuf[arg9 + sp424]; + // For a 256x256 texture with 63x31 tiles there are 32 tiles which requires at least 45 vertices, + // 45 > 32 (the maximum number of vertices that can be loaded at once) so it is split into two passes + for (ult = 0, n = 0; n < 2; n++) { + // Each iteration is 16 tiles of the texture, first iteration is the top 16 tiles - for (i = 0; i < 0x20; i++) { - index = D_8012ACA0[sp424][i]; + // Select gfx buffer + skyboxCtx->gfx = skyboxCtx->dListBuf[dlistBufStartIndex + n]; - roomVtx[arg2 + i].v.ob[0] = sp358[index]; - roomVtx[arg2 + i].v.ob[1] = sp2A4[index]; - roomVtx[arg2 + i].v.ob[2] = sp1F0[index]; - roomVtx[arg2 + i].v.flag = 0; - roomVtx[arg2 + i].v.tc[0] = sp13C[index]; - roomVtx[arg2 + i].v.tc[1] = sp88[index]; - roomVtx[arg2 + i].v.cn[1] = 0; - roomVtx[arg2 + i].v.cn[2] = 0; - roomVtx[arg2 + i].v.cn[0] = 255; + // Generate and load Vertex structures + for (i = 0; i < 32; i++) { + index = sSkybox256VtxBufIndices[n][i]; + + roomVtx[roomVtxStartIndex + i].v.ob[0] = xPoints[index]; + roomVtx[roomVtxStartIndex + i].v.ob[1] = yPoints[index]; + roomVtx[roomVtxStartIndex + i].v.ob[2] = zPoints[index]; + roomVtx[roomVtxStartIndex + i].v.flag = 0; + roomVtx[roomVtxStartIndex + i].v.tc[0] = tcS[index]; + roomVtx[roomVtxStartIndex + i].v.tc[1] = tcT[index]; + roomVtx[roomVtxStartIndex + i].v.cn[1] = 0; + roomVtx[roomVtxStartIndex + i].v.cn[2] = 0; + roomVtx[roomVtxStartIndex + i].v.cn[0] = 255; } - gSPVertex(skyboxCtx->unk_138++, &roomVtx[arg2], 32, 0); - arg2 += i; - gSPCullDisplayList(skyboxCtx->unk_138++, 0, 15); + gSPVertex(skyboxCtx->gfx++, &roomVtx[roomVtxStartIndex], 32, 0); + roomVtxStartIndex += i; // += 32 - for (phi_t2_4 = 0, phi_ra = 0; phi_ra < 4; phi_ra++, phi_a2_4 += 0x1F) { - for (phi_a0_4 = 0, phi_t1 = 0; phi_t1 < 4; phi_t1++, phi_a0_4 += 0x3F, phi_t2_4 += 4) { - gDPLoadTextureTile(skyboxCtx->unk_138++, (u32)skyboxCtx->staticSegments[0] + D_8012AC90[arg8], - G_IM_FMT_CI, G_IM_SIZ_8b, 256, 0, phi_a0_4, phi_a2_4, phi_a0_4 + 0x3F, - phi_a2_4 + 0x1F, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD); - gSP1Quadrangle(skyboxCtx->unk_138++, D_8012AD40[phi_t2_4 + 1], D_8012AD40[phi_t2_4 + 2], - D_8012AD40[phi_t2_4 + 3], D_8012AD40[phi_t2_4 + 0], 3); + // Cull the face if not within the viewing volume + gSPCullDisplayList(skyboxCtx->gfx++, 0, 15); + + // Draw face, load the texture in several tiles to work around TMEM size limitations + for (vtxIdx = 0, l = 0; l < 4; l++, ult += 31) { + for (uls = 0, m = 0; m < 4; m++, uls += 63, vtxIdx += 4) { + gDPLoadTextureTile(skyboxCtx->gfx++, (u32)skyboxCtx->staticSegments[0] + sSkybox256TexOffsets[faceNum], + G_IM_FMT_CI, G_IM_SIZ_8b, 256, 0, uls, ult, uls + 63, ult + 31, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMASK, G_TX_NOLOD); + gSP1Quadrangle(skyboxCtx->gfx++, sSkybox256VtxIndices[vtxIdx + 1], sSkybox256VtxIndices[vtxIdx + 2], + sSkybox256VtxIndices[vtxIdx + 3], sSkybox256VtxIndices[vtxIdx + 0], 3); } } - gSPEndDisplayList(skyboxCtx->unk_138++); + gSPEndDisplayList(skyboxCtx->gfx++); } - return arg2; + return roomVtxStartIndex; } -s32 func_800AE2C0(SkyboxContext* skyboxCtx, Vtx* roomVtx, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6, s32 arg7, - s32 arg8) { +// Texture offsets for each face in the static segment buffer +u32 sSkybox128TexOffsets[6] = { + 128 * 64 * 0, 128 * 64 * 1, 128 * 64 * 2, 128 * 64 * 3, 128 * 64 * 4, 128 * 64 * 4 + 128 * 128, +}; + +// Maps vertex buffer index to coordinate buffer index +u16 sSkybox128VtxBufIndices[32] = { + 0, 2, 10, 12, 2, 4, 12, 14, 10, 12, 20, 22, 12, 14, 22, 24, 1, 3, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 21, 23, +}; + +// S coordinates for all faces +s16 sSkybox128TexSCoords[5] = { + TC(62 * 0), TC(62 * 1), TC(62 * 2), TC(62 * 3), TC(62 * 4), +}; + +// T coordinates for top and bottom faces +s16 sSkybox128TexTCoordsXZ[5] = { + TC(62 * 0), TC(62 * 1), TC(62 * 2), TC(62 * 3), TC(62 * 4), +}; + +// T coordinates for side faces +s16 sSkybox128TexTCoords[5] = { + TC(62 * 0), TC(62 * 1), TC(62 * 2), TC(62 * 1), TC(62 * 0), +}; + +// Maps vertex index to vertex buffer index +s16 sSkybox128VtxIndices[64] = { + 0, 16, 19, 18, 16, 1, 20, 19, 1, 17, 21, 20, 17, 5, 22, 21, 18, 19, 23, 2, 19, 20, + 3, 23, 20, 21, 24, 3, 21, 22, 7, 24, 2, 23, 26, 25, 23, 3, 27, 26, 3, 24, 28, 27, + 24, 7, 29, 28, 25, 26, 30, 10, 26, 27, 11, 30, 27, 28, 31, 11, 28, 29, 15, 31, +}; + +/** + * Build the vertex and display list data for a skybox with 128x128 and 128x64 face textures. + * + * While the textures are nominally 128x128 (128x64) the 4x4 (4x2) tiles that cover it are only 31x31, + * therefore only a 125x125 (125x63) area is ever sampled (see `Skybox_CalculateFace256` for more details) + * + * Each texture dimension is padded to the next power of 2, resulting in a final size of 128x128 (128x64) + */ +s32 Skybox_CalculateFace128(SkyboxContext* skyboxCtx, Vtx* roomVtx, s32 roomVtxStartIndex, s32 xStart, s32 yStart, + s32 zStart, s32 innerIncrVal, s32 outerIncrVal, s32 faceNum) { s32 i; s32 j; s32 k; - s16 phi_a0_4; - s16 phi_t1; - s32 temp1; + s16 uls; + s16 m; + s32 outerIncr; u16 index; - s16 phi_a2_4; - s16 phi_ra; - s16 phi_t2_4; - s32 temp2; - s32 sp2B4[5 * 5]; - s32 sp250[5 * 5]; - s32 sp1EC[5 * 5]; - s32 sp188[5 * 5]; - s32 sp124[5 * 5]; + s16 ult; + s16 l; + s16 vtxIdx; + s32 innerIncr; + s32 xPoints[5 * 5]; + s32 yPoints[5 * 5]; + s32 zPoints[5 * 5]; + s32 tcS[5 * 5]; + s32 tcT[5 * 5]; s32 pad; - switch (arg8) { - case 0: + // Collect all vertex positions for this face + switch (faceNum) { + case 0: // xy plane case 1: - temp1 = arg4; + outerIncr = yStart; for (i = 0, k = 0; k < 25; i++) { - temp2 = arg3; + innerIncr = xStart; + for (j = 0; j < 5; j++, k++) { - sp1EC[k] = arg5; - sp2B4[k] = temp2; - sp250[k] = temp1; - sp188[k] = D_8012AE18[j]; - sp124[k] = D_8012AE30[i]; - temp2 += arg6; + zPoints[k] = zStart; + xPoints[k] = innerIncr; + yPoints[k] = outerIncr; + tcS[k] = sSkybox128TexSCoords[j]; + tcT[k] = sSkybox128TexTCoords[i]; + innerIncr += innerIncrVal; } - temp1 += arg7; + outerIncr += outerIncrVal; } break; - case 2: + case 2: // yz plane case 3: - temp1 = arg4; + outerIncr = yStart; for (i = 0, k = 0; k < 25; i++) { - temp2 = arg5; + innerIncr = zStart; + for (j = 0; j < 5; j++, k++) { - sp2B4[k] = arg3; - sp250[k] = temp1; - sp1EC[k] = temp2; - sp188[k] = D_8012AE18[j]; - sp124[k] = D_8012AE30[i]; - temp2 += arg6; + xPoints[k] = xStart; + yPoints[k] = outerIncr; + zPoints[k] = innerIncr; + tcS[k] = sSkybox128TexSCoords[j]; + tcT[k] = sSkybox128TexTCoords[i]; + innerIncr += innerIncrVal; } - temp1 += arg7; + outerIncr += outerIncrVal; } break; - case 4: + case 4: // xz plane case 5: - temp1 = arg5; + outerIncr = zStart; for (i = 0, k = 0; k < 25; i++) { - temp2 = arg3; + innerIncr = xStart; + for (j = 0; j < 5; j++, k++) { - sp250[k] = arg4; - sp2B4[k] = temp2; - sp1EC[k] = temp1; - sp188[k] = D_8012AE18[j]; - sp124[k] = D_8012AE24[i]; - temp2 += arg6; + yPoints[k] = yStart; + xPoints[k] = innerIncr; + zPoints[k] = outerIncr; + tcS[k] = sSkybox128TexSCoords[j]; + tcT[k] = sSkybox128TexTCoordsXZ[i]; + innerIncr += innerIncrVal; } - temp1 += arg7; + outerIncr += outerIncrVal; } break; } - skyboxCtx->unk_138 = &skyboxCtx->dListBuf[2 * arg8][0]; - for (i = 0; i < 0x20; i++) { - index = D_8012ADD8[i]; + // Select gfx buffer + skyboxCtx->gfx = &skyboxCtx->dListBuf[2 * faceNum][0]; - roomVtx[arg2 + i].v.ob[0] = sp2B4[index]; - roomVtx[arg2 + i].v.ob[1] = sp250[index]; - roomVtx[arg2 + i].v.ob[2] = sp1EC[index]; - roomVtx[arg2 + i].v.flag = 0; - roomVtx[arg2 + i].v.tc[0] = sp188[index]; - roomVtx[arg2 + i].v.tc[1] = sp124[index]; - roomVtx[arg2 + i].v.cn[1] = 0; - roomVtx[arg2 + i].v.cn[2] = 0; - roomVtx[arg2 + i].v.cn[0] = 255; + // Generate and load Vertex structures + for (i = 0; i < 32; i++) { + index = sSkybox128VtxBufIndices[i]; + + roomVtx[roomVtxStartIndex + i].v.ob[0] = xPoints[index]; + roomVtx[roomVtxStartIndex + i].v.ob[1] = yPoints[index]; + roomVtx[roomVtxStartIndex + i].v.ob[2] = zPoints[index]; + roomVtx[roomVtxStartIndex + i].v.flag = 0; + roomVtx[roomVtxStartIndex + i].v.tc[0] = tcS[index]; + roomVtx[roomVtxStartIndex + i].v.tc[1] = tcT[index]; + roomVtx[roomVtxStartIndex + i].v.cn[1] = 0; + roomVtx[roomVtxStartIndex + i].v.cn[2] = 0; + roomVtx[roomVtxStartIndex + i].v.cn[0] = 255; } - gSPVertex(skyboxCtx->unk_138++, &roomVtx[arg2], 32, 0); - arg2 += i; - gSPCullDisplayList(skyboxCtx->unk_138++, 0, 15); + gSPVertex(skyboxCtx->gfx++, &roomVtx[roomVtxStartIndex], 32, 0); + roomVtxStartIndex += i; - if ((arg8 == 4) || (arg8 == 5)) { - phi_a2_4 = 0; - for (phi_t2_4 = 0, phi_ra = 0; phi_ra < 4; phi_ra++, phi_a2_4 += 0x1F) { - for (phi_a0_4 = 0, phi_t1 = 0; phi_t1 < 4; phi_t1++, phi_a0_4 += 0x1F, phi_t2_4 += 4) { - gDPLoadMultiTile(skyboxCtx->unk_138++, (u32)skyboxCtx->staticSegments[0] + D_8012ADC0[arg8], 0, - G_TX_RENDERTILE, G_IM_FMT_CI, G_IM_SIZ_8b, 128, 0, phi_a0_4, phi_a2_4, phi_a0_4 + 0x1F, - phi_a2_4 + 0x1F, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD); - gDPLoadMultiTile(skyboxCtx->unk_138++, (u32)skyboxCtx->staticSegments[1] + D_8012ADC0[arg8], 0x80, 1, - G_IM_FMT_CI, G_IM_SIZ_8b, 128, 0, phi_a0_4, phi_a2_4, phi_a0_4 + 0x1F, phi_a2_4 + 0x1F, - 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, + // Cull the face if not within the viewing volume + gSPCullDisplayList(skyboxCtx->gfx++, 0, 15); + + // Draw face, load the texture in several tiles to work around TMEM size limitations + if (faceNum == 4 || faceNum == 5) { + // top/bottom faces, 128x128 texture + + ult = 0; + for (vtxIdx = 0, l = 0; l < 4; l++, ult += 31) { + for (uls = 0, m = 0; m < 4; m++, uls += 31, vtxIdx += 4) { + gDPLoadMultiTile(skyboxCtx->gfx++, (u32)skyboxCtx->staticSegments[0] + sSkybox128TexOffsets[faceNum], 0, + G_TX_RENDERTILE, G_IM_FMT_CI, G_IM_SIZ_8b, 128, 0, uls, ult, uls + 31, ult + 31, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD); - gSP1Quadrangle(skyboxCtx->unk_138++, D_8012AE3C[phi_t2_4 + 1], D_8012AE3C[phi_t2_4 + 2], - D_8012AE3C[phi_t2_4 + 3], D_8012AE3C[phi_t2_4 + 0], 3); + gDPLoadMultiTile(skyboxCtx->gfx++, (u32)skyboxCtx->staticSegments[1] + sSkybox128TexOffsets[faceNum], + 0x80, 1, G_IM_FMT_CI, G_IM_SIZ_8b, 128, 0, uls, ult, uls + 31, ult + 31, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMASK, G_TX_NOLOD); + gSP1Quadrangle(skyboxCtx->gfx++, sSkybox128VtxIndices[vtxIdx + 1], sSkybox128VtxIndices[vtxIdx + 2], + sSkybox128VtxIndices[vtxIdx + 3], sSkybox128VtxIndices[vtxIdx + 0], 3); } } } else { - phi_a2_4 = 0; - for (phi_t2_4 = 0, phi_ra = 0; phi_ra < 2; phi_ra++, phi_a2_4 += 0x1F) { - for (phi_a0_4 = 0, phi_t1 = 0; phi_t1 < 4; phi_t1++, phi_a0_4 += 0x1F, phi_t2_4 += 4) { - gDPLoadMultiTile(skyboxCtx->unk_138++, (u32)skyboxCtx->staticSegments[0] + D_8012ADC0[arg8], 0, - G_TX_RENDERTILE, G_IM_FMT_CI, G_IM_SIZ_8b, 128, 0, phi_a0_4, phi_a2_4, phi_a0_4 + 0x1F, - phi_a2_4 + 0x1F, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD); - gDPLoadMultiTile(skyboxCtx->unk_138++, (u32)skyboxCtx->staticSegments[1] + D_8012ADC0[arg8], 0x80, 1, - G_IM_FMT_CI, G_IM_SIZ_8b, 128, 0, phi_a0_4, phi_a2_4, phi_a0_4 + 0x1F, phi_a2_4 + 0x1F, - 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, + // other faces, 128x64 texture + + ult = 0; + for (vtxIdx = 0, l = 0; l < 2; l++, ult += 31) { + for (uls = 0, m = 0; m < 4; m++, uls += 31, vtxIdx += 4) { + gDPLoadMultiTile(skyboxCtx->gfx++, (u32)skyboxCtx->staticSegments[0] + sSkybox128TexOffsets[faceNum], 0, + G_TX_RENDERTILE, G_IM_FMT_CI, G_IM_SIZ_8b, 128, 0, uls, ult, uls + 31, ult + 31, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD); - gSP1Quadrangle(skyboxCtx->unk_138++, D_8012AE3C[phi_t2_4 + 1], D_8012AE3C[phi_t2_4 + 2], - D_8012AE3C[phi_t2_4 + 3], D_8012AE3C[phi_t2_4 + 0], 3); + gDPLoadMultiTile(skyboxCtx->gfx++, (u32)skyboxCtx->staticSegments[1] + sSkybox128TexOffsets[faceNum], + 0x80, 1, G_IM_FMT_CI, G_IM_SIZ_8b, 128, 0, uls, ult, uls + 31, ult + 31, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMASK, G_TX_NOLOD); + gSP1Quadrangle(skyboxCtx->gfx++, sSkybox128VtxIndices[vtxIdx + 1], sSkybox128VtxIndices[vtxIdx + 2], + sSkybox128VtxIndices[vtxIdx + 3], sSkybox128VtxIndices[vtxIdx + 0], 3); } } - phi_a2_4 -= 0x1F; - for (phi_ra = 0; phi_ra < 2; phi_ra++, phi_a2_4 -= 0x1F) { - for (phi_a0_4 = 0, phi_t1 = 0; phi_t1 < 4; phi_t1++, phi_a0_4 += 0x1F, phi_t2_4 += 4) { - gDPLoadMultiTile(skyboxCtx->unk_138++, (u32)skyboxCtx->staticSegments[0] + D_8012ADC0[arg8], 0, - G_TX_RENDERTILE, G_IM_FMT_CI, G_IM_SIZ_8b, 128, 0, phi_a0_4, phi_a2_4, phi_a0_4 + 0x1F, - phi_a2_4 + 0x1F, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD); - gDPLoadMultiTile(skyboxCtx->unk_138++, (u32)skyboxCtx->staticSegments[1] + D_8012ADC0[arg8], 0x80, 1, - G_IM_FMT_CI, G_IM_SIZ_8b, 128, 0, phi_a0_4, phi_a2_4, phi_a0_4 + 0x1F, phi_a2_4 + 0x1F, - 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, + ult -= 31; + for (l = 0; l < 2; l++, ult -= 31) { + for (uls = 0, m = 0; m < 4; m++, uls += 31, vtxIdx += 4) { + gDPLoadMultiTile(skyboxCtx->gfx++, (u32)skyboxCtx->staticSegments[0] + sSkybox128TexOffsets[faceNum], 0, + G_TX_RENDERTILE, G_IM_FMT_CI, G_IM_SIZ_8b, 128, 0, uls, ult, uls + 31, ult + 31, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD); - gSP1Quadrangle(skyboxCtx->unk_138++, D_8012AE3C[phi_t2_4 + 1], D_8012AE3C[phi_t2_4 + 2], - D_8012AE3C[phi_t2_4 + 3], D_8012AE3C[phi_t2_4 + 0], 3); + gDPLoadMultiTile(skyboxCtx->gfx++, (u32)skyboxCtx->staticSegments[1] + sSkybox128TexOffsets[faceNum], + 0x80, 1, G_IM_FMT_CI, G_IM_SIZ_8b, 128, 0, uls, ult, uls + 31, ult + 31, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMASK, G_TX_NOLOD); + gSP1Quadrangle(skyboxCtx->gfx++, sSkybox128VtxIndices[vtxIdx + 1], sSkybox128VtxIndices[vtxIdx + 2], + sSkybox128VtxIndices[vtxIdx + 3], sSkybox128VtxIndices[vtxIdx + 0], 3); } } } - gSPEndDisplayList(skyboxCtx->unk_138++); - return arg2; + gSPEndDisplayList(skyboxCtx->gfx++); + return roomVtxStartIndex; } -void func_800AEFC8(SkyboxContext* skyboxCtx, s16 skyboxId) { - s32 i; - s32 j; - s32 phi_s3 = 0; +SkyboxFaceParams sSkybox256FaceParams[4] = { + { -126, 124, -126, 63, -31 }, + { 126, 124, -126, 63, -31 }, + { 126, 124, 126, -63, -31 }, + { -126, 124, 126, -63, -31 }, +}; + +/** + * Computes the display list for a skybox where each face is a 256x256 CI8 texture. + * The number of faces is determined by the skybox id or from the drawType field in SkyboxContext. + */ +void Skybox_Calculate256(SkyboxContext* skyboxCtx, s16 skyboxId) { + s32 faceNum; + s32 dlistBufStartIndex; + s32 roomVtxStartIndex = 0; if (skyboxId == SKYBOX_BAZAAR || (skyboxId > SKYBOX_HOUSE_KAKARIKO && skyboxId <= SKYBOX_BOMBCHU_SHOP)) { - for (j = 0, i = 0; i < 2; i++, j += 2) { - phi_s3 = func_800ADBB0(skyboxCtx, skyboxCtx->roomVtx, phi_s3, D_8012AEBC[i].unk_0, D_8012AEBC[i].unk_4, - D_8012AEBC[i].unk_8, D_8012AEBC[i].unk_C, D_8012AEBC[i].unk_10, i, j); + // 2 faces, one in xy plane and one in yz plane + for (dlistBufStartIndex = 0, faceNum = 0; faceNum < 2; faceNum++, dlistBufStartIndex += 2) { + roomVtxStartIndex = Skybox_CalculateFace256( + skyboxCtx, skyboxCtx->roomVtx, roomVtxStartIndex, sSkybox256FaceParams[faceNum].xStart, + sSkybox256FaceParams[faceNum].yStart, sSkybox256FaceParams[faceNum].zStart, + sSkybox256FaceParams[faceNum].outerIncrVal, sSkybox256FaceParams[faceNum].innerIncrVal, faceNum, + dlistBufStartIndex); } - } else if (skyboxCtx->unk_140 == 2) { - for (j = 0, i = 0; i < 3; i++, j += 2) { - phi_s3 = func_800ADBB0(skyboxCtx, skyboxCtx->roomVtx, phi_s3, D_8012AEBC[i].unk_0, D_8012AEBC[i].unk_4, - D_8012AEBC[i].unk_8, D_8012AEBC[i].unk_C, D_8012AEBC[i].unk_10, i, j); + } else if (skyboxCtx->drawType == SKYBOX_DRAW_256_3FACE) { + // 3 faces, 2 in xy plane and 1 in yz plane + for (dlistBufStartIndex = 0, faceNum = 0; faceNum < 3; faceNum++, dlistBufStartIndex += 2) { + roomVtxStartIndex = Skybox_CalculateFace256( + skyboxCtx, skyboxCtx->roomVtx, roomVtxStartIndex, sSkybox256FaceParams[faceNum].xStart, + sSkybox256FaceParams[faceNum].yStart, sSkybox256FaceParams[faceNum].zStart, + sSkybox256FaceParams[faceNum].outerIncrVal, sSkybox256FaceParams[faceNum].innerIncrVal, faceNum, + dlistBufStartIndex); } } else { - for (j = 0, i = 0; i < 4; i++, j += 2) { - phi_s3 = func_800ADBB0(skyboxCtx, skyboxCtx->roomVtx, phi_s3, D_8012AEBC[i].unk_0, D_8012AEBC[i].unk_4, - D_8012AEBC[i].unk_8, D_8012AEBC[i].unk_C, D_8012AEBC[i].unk_10, i, j); + // 4 faces, 2 in xy plane and 2 in yz plane + for (dlistBufStartIndex = 0, faceNum = 0; faceNum < 4; faceNum++, dlistBufStartIndex += 2) { + roomVtxStartIndex = Skybox_CalculateFace256( + skyboxCtx, skyboxCtx->roomVtx, roomVtxStartIndex, sSkybox256FaceParams[faceNum].xStart, + sSkybox256FaceParams[faceNum].yStart, sSkybox256FaceParams[faceNum].zStart, + sSkybox256FaceParams[faceNum].outerIncrVal, sSkybox256FaceParams[faceNum].innerIncrVal, faceNum, + dlistBufStartIndex); } } } -void func_800AF178(SkyboxContext* skyboxCtx, s32 arg1) { - s32 phi_s2 = 0; - s32 i; +SkyboxFaceParams sSkybox128FaceParams[6] = { + { -64, 64, -64, 32, -32 }, { 64, 64, 64, -32, -32 }, { -64, 64, 64, -32, -32 }, + { 64, 64, -64, 32, -32 }, { -64, 64, 64, 32, -32 }, { -64, -64, -64, 32, 32 }, +}; - for (i = 0; i < arg1; i++) { - phi_s2 = func_800AE2C0(skyboxCtx, skyboxCtx->roomVtx, phi_s2, D_8012AF0C[i].unk_0, D_8012AF0C[i].unk_4, - D_8012AF0C[i].unk_8, D_8012AF0C[i].unk_C, D_8012AF0C[i].unk_10, i); +/** + * Computes the display list for a skybox with up to 6 faces, where the sides are 128x64 CI8 textures and the + * top/bottom faces are 128x128 CI8 textures. + */ +void Skybox_Calculate128(SkyboxContext* skyboxCtx, s32 nFaces) { + s32 roomVtxStartIndex = 0; + s32 faceNum; + + for (faceNum = 0; faceNum < nFaces; faceNum++) { + roomVtxStartIndex = Skybox_CalculateFace128( + skyboxCtx, skyboxCtx->roomVtx, roomVtxStartIndex, sSkybox128FaceParams[faceNum].xStart, + sSkybox128FaceParams[faceNum].yStart, sSkybox128FaceParams[faceNum].zStart, + sSkybox128FaceParams[faceNum].outerIncrVal, sSkybox128FaceParams[faceNum].innerIncrVal, faceNum); } } @@ -447,7 +528,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { break; case SKYBOX_BAZAAR: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_SP1a_staticSegmentRomStart; size = (uintptr_t)_vr_SP1a_staticSegmentRomEnd - start; @@ -489,7 +570,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { DmaMgr_RequestSyncDebug((u8*)skyboxCtx->palettes + size, start, size, "../z_vr_box.c", 1175); break; case SKYBOX_MARKET_ADULT: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_RUVR_staticSegmentRomStart; size = (uintptr_t)_vr_RUVR_staticSegmentRomEnd - start; @@ -535,7 +616,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { size, "../z_vr_box.c", 1216); break; case SKYBOX_HOUSE_LINK: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_LHVR_staticSegmentRomStart; size = (uintptr_t)_vr_LHVR_staticSegmentRomEnd - start; @@ -553,7 +634,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { DmaMgr_RequestSyncDebug(skyboxCtx->palettes, start, size, "../z_vr_box.c", 1233); break; case SKYBOX_MARKET_CHILD_DAY: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_MDVR_staticSegmentRomStart; size = (uintptr_t)_vr_MDVR_staticSegmentRomEnd - start; @@ -571,7 +652,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { DmaMgr_RequestSyncDebug(skyboxCtx->palettes, start, size, "../z_vr_box.c", 1264); break; case SKYBOX_MARKET_CHILD_NIGHT: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_MNVR_staticSegmentRomStart; size = (uintptr_t)_vr_MNVR_staticSegmentRomEnd - start; @@ -591,7 +672,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { DmaMgr_RequestSyncDebug(skyboxCtx->palettes, start, size, "../z_vr_box.c", 1279); break; case SKYBOX_HAPPY_MASK_SHOP: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_FCVR_staticSegmentRomStart; size = (uintptr_t)_vr_FCVR_staticSegmentRomEnd - start; @@ -610,7 +691,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { skyboxCtx->rot.y = 0.8f; break; case SKYBOX_HOUSE_KNOW_IT_ALL_BROTHERS: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_KHVR_staticSegmentRomStart; size = (uintptr_t)_vr_KHVR_staticSegmentRomEnd - start; @@ -628,7 +709,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { DmaMgr_RequestSyncDebug(skyboxCtx->palettes, start, size, "../z_vr_box.c", 1308); break; case SKYBOX_HOUSE_OF_TWINS: - skyboxCtx->unk_140 = 2; + skyboxCtx->drawType = SKYBOX_DRAW_256_3FACE; start = (uintptr_t)_vr_K3VR_staticSegmentRomStart; size = (uintptr_t)_vr_K3VR_staticSegmentRomEnd - start; @@ -646,7 +727,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { DmaMgr_RequestSyncDebug(skyboxCtx->palettes, start, size, "../z_vr_box.c", 1338); break; case SKYBOX_STABLES: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_MLVR_staticSegmentRomStart; size = (uintptr_t)_vr_MLVR_staticSegmentRomEnd - start; @@ -664,7 +745,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { DmaMgr_RequestSyncDebug(skyboxCtx->palettes, start, size, "../z_vr_box.c", 1352); break; case SKYBOX_HOUSE_KAKARIKO: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_KKRVR_staticSegmentRomStart; size = (uintptr_t)_vr_KKRVR_staticSegmentRomEnd - start; @@ -682,7 +763,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { DmaMgr_RequestSyncDebug(skyboxCtx->palettes, start, size, "../z_vr_box.c", 1366); break; case SKYBOX_KOKIRI_SHOP: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_KSVR_staticSegmentRomStart; size = (uintptr_t)_vr_KSVR_staticSegmentRomEnd - start; @@ -701,7 +782,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { skyboxCtx->rot.y = 0.8f; break; case SKYBOX_GORON_SHOP: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_GLVR_staticSegmentRomStart; size = (uintptr_t)_vr_GLVR_staticSegmentRomEnd - start; @@ -720,7 +801,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { skyboxCtx->rot.y = 0.8f; break; case SKYBOX_ZORA_SHOP: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_ZRVR_staticSegmentRomStart; size = (uintptr_t)_vr_ZRVR_staticSegmentRomEnd - start; @@ -739,7 +820,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { skyboxCtx->rot.y = 0.8f; break; case SKYBOX_POTION_SHOP_KAKARIKO: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_DGVR_staticSegmentRomStart; size = (uintptr_t)_vr_DGVR_staticSegmentRomEnd - start; @@ -758,7 +839,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { skyboxCtx->rot.y = 0.8f; break; case SKYBOX_POTION_SHOP_MARKET: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_ALVR_staticSegmentRomStart; size = (uintptr_t)_vr_ALVR_staticSegmentRomEnd - start; @@ -777,7 +858,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { skyboxCtx->rot.y = 0.8f; break; case SKYBOX_BOMBCHU_SHOP: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_NSVR_staticSegmentRomStart; size = (uintptr_t)_vr_NSVR_staticSegmentRomEnd - start; @@ -796,7 +877,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { skyboxCtx->rot.y = 0.8f; break; case SKYBOX_HOUSE_RICHARD: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_IPVR_staticSegmentRomStart; size = (uintptr_t)_vr_IPVR_staticSegmentRomEnd - start; @@ -814,7 +895,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { DmaMgr_RequestSyncDebug(skyboxCtx->palettes, start, size, "../z_vr_box.c", 1519); break; case SKYBOX_HOUSE_IMPA: - skyboxCtx->unk_140 = 1; + skyboxCtx->drawType = SKYBOX_DRAW_256_4FACE; start = (uintptr_t)_vr_LBVR_staticSegmentRomStart; size = (uintptr_t)_vr_LBVR_staticSegmentRomEnd - start; @@ -832,7 +913,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { DmaMgr_RequestSyncDebug(skyboxCtx->palettes, start, size, "../z_vr_box.c", 1533); break; case SKYBOX_TENT: - skyboxCtx->unk_140 = 2; + skyboxCtx->drawType = SKYBOX_DRAW_256_3FACE; start = (uintptr_t)_vr_TTVR_staticSegmentRomStart; size = (uintptr_t)_vr_TTVR_staticSegmentRomEnd - start; @@ -850,7 +931,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { DmaMgr_RequestSyncDebug(skyboxCtx->palettes, start, size, "../z_vr_box.c", 1547); break; case SKYBOX_HOUSE_MIDO: - skyboxCtx->unk_140 = 2; + skyboxCtx->drawType = SKYBOX_DRAW_256_3FACE; start = (uintptr_t)_vr_K4VR_staticSegmentRomStart; size = (uintptr_t)_vr_K4VR_staticSegmentRomEnd - start; @@ -868,7 +949,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { DmaMgr_RequestSyncDebug(skyboxCtx->palettes, start, size, "../z_vr_box.c", 1567); break; case SKYBOX_HOUSE_SARIA: - skyboxCtx->unk_140 = 2; + skyboxCtx->drawType = SKYBOX_DRAW_256_3FACE; start = (uintptr_t)_vr_K5VR_staticSegmentRomStart; size = (uintptr_t)_vr_K5VR_staticSegmentRomEnd - start; @@ -886,7 +967,7 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { DmaMgr_RequestSyncDebug(skyboxCtx->palettes, start, size, "../z_vr_box.c", 1581); break; case SKYBOX_HOUSE_ALLEY: - skyboxCtx->unk_140 = 2; + skyboxCtx->drawType = SKYBOX_DRAW_256_3FACE; start = (uintptr_t)_vr_KR3VR_staticSegmentRomStart; size = (uintptr_t)_vr_KR3VR_staticSegmentRomEnd - start; @@ -911,40 +992,42 @@ void Skybox_Setup(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) { void Skybox_Init(GameState* state, SkyboxContext* skyboxCtx, s16 skyboxId) { PlayState* play = (PlayState*)state; - skyboxCtx->unk_140 = 0; + skyboxCtx->drawType = SKYBOX_DRAW_128; skyboxCtx->rot.x = skyboxCtx->rot.y = skyboxCtx->rot.z = 0.0f; + // DMA required assets based on skybox id Skybox_Setup(play, skyboxCtx, skyboxId); osSyncPrintf("\n\n\n********************\n\n\n" "TYPE=%d" "\n\n\n********************\n\n\n", skyboxId); + // Precompute vertices and display lists for drawing the skybox if (skyboxId != SKYBOX_NONE) { osSyncPrintf(VT_FGCOL(GREEN)); - if (skyboxCtx->unk_140 != 0) { + if (skyboxCtx->drawType != SKYBOX_DRAW_128) { skyboxCtx->dListBuf = GameState_Alloc(state, 8 * 150 * sizeof(Gfx), "../z_vr_box.c", 1636); ASSERT(skyboxCtx->dListBuf != NULL, "vr_box->dpList != NULL", "../z_vr_box.c", 1637); - skyboxCtx->roomVtx = GameState_Alloc(state, 256 * sizeof(Vtx), "../z_vr_box.c", 1639); + skyboxCtx->roomVtx = GameState_Alloc(state, 8 * 32 * sizeof(Vtx), "../z_vr_box.c", 1639); ASSERT(skyboxCtx->roomVtx != NULL, "vr_box->roomVtx != NULL", "../z_vr_box.c", 1640); - func_800AEFC8(skyboxCtx, skyboxId); + Skybox_Calculate256(skyboxCtx, skyboxId); } else { skyboxCtx->dListBuf = GameState_Alloc(state, 12 * 150 * sizeof(Gfx), "../z_vr_box.c", 1643); ASSERT(skyboxCtx->dListBuf != NULL, "vr_box->dpList != NULL", "../z_vr_box.c", 1644); if (skyboxId == SKYBOX_CUTSCENE_MAP) { - skyboxCtx->roomVtx = GameState_Alloc(state, 192 * sizeof(Vtx), "../z_vr_box.c", 1648); + skyboxCtx->roomVtx = GameState_Alloc(state, 6 * 32 * sizeof(Vtx), "../z_vr_box.c", 1648); ASSERT(skyboxCtx->roomVtx != NULL, "vr_box->roomVtx != NULL", "../z_vr_box.c", 1649); - func_800AF178(skyboxCtx, 6); + Skybox_Calculate128(skyboxCtx, 6); // compute all 6 faces } else { - skyboxCtx->roomVtx = GameState_Alloc(state, 160 * sizeof(Vtx), "../z_vr_box.c", 1653); + skyboxCtx->roomVtx = GameState_Alloc(state, 5 * 32 * sizeof(Vtx), "../z_vr_box.c", 1653); ASSERT(skyboxCtx->roomVtx != NULL, "vr_box->roomVtx != NULL", "../z_vr_box.c", 1654); - func_800AF178(skyboxCtx, 5); + Skybox_Calculate128(skyboxCtx, 5); // compute 5 faces, excludes the bottom face } } osSyncPrintf(VT_RST); diff --git a/src/code/z_vr_box_draw.c b/src/code/z_vr_box_draw.c index 60fa408d09..96a785118c 100644 --- a/src/code/z_vr_box_draw.c +++ b/src/code/z_vr_box_draw.c @@ -23,8 +23,8 @@ void Skybox_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyboxId gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x00, 0, 0, 0, blend); gSPTexture(POLY_OPA_DISP++, 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_ON); + // Prepare matrix sSkyboxDrawMatrix = Graph_Alloc(gfxCtx, sizeof(Mtx)); - Matrix_Translate(x, y, z, MTXMODE_NEW); Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_APPLY); Matrix_RotateX(skyboxCtx->rot.x, MTXMODE_APPLY); @@ -33,45 +33,61 @@ void Skybox_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyboxId Matrix_ToMtx(sSkyboxDrawMatrix, "../z_vr_box_draw.c", 76); gSPMatrix(POLY_OPA_DISP++, sSkyboxDrawMatrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + // Enable magic square RGB dithering and bilinear filtering gDPSetColorDither(POLY_OPA_DISP++, G_CD_MAGICSQ); gDPSetTextureFilter(POLY_OPA_DISP++, G_TF_BILERP); + // All skyboxes use CI8 textures with an RGBA16 palette gDPLoadTLUT_pal256(POLY_OPA_DISP++, skyboxCtx->palettes[0]); gDPSetTextureLUT(POLY_OPA_DISP++, G_TT_RGBA16); + + // Enable texture filtering RDP pipeline stages for bilinear filtering gDPSetTextureConvert(POLY_OPA_DISP++, G_TC_FILT); - if (skyboxCtx->unk_140) { - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[0]); - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[1]); + if (skyboxCtx->drawType != SKYBOX_DRAW_128) { + // 256x256 textures, per-face palettes + // 2, 3 or 4 faces + + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[0]); // -z face upper + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[1]); // -z face lower gDPPipeSync(POLY_OPA_DISP++); gDPLoadTLUT_pal256(POLY_OPA_DISP++, skyboxCtx->palettes[1]); - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[2]); - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[3]); + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[2]); // +x face upper + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[3]); // +x face lower if (skyboxId != SKYBOX_BAZAAR) { - if (skyboxId <= SKYBOX_HOUSE_KAKARIKO || skyboxId > SKYBOX_BOMBCHU_SHOP) { - gDPPipeSync(POLY_OPA_DISP++); - gDPLoadTLUT_pal256(POLY_OPA_DISP++, skyboxCtx->palettes[2]); - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[4]); - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[5]); + if (skyboxId < SKYBOX_KOKIRI_SHOP || skyboxId > SKYBOX_BOMBCHU_SHOP) { + // Skip remaining faces for most shop skyboxes gDPPipeSync(POLY_OPA_DISP++); - if (skyboxCtx->unk_140 != 2) { + gDPLoadTLUT_pal256(POLY_OPA_DISP++, skyboxCtx->palettes[2]); + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[4]); // +z face upper + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[5]); // +z face lower + + // Note this pipesync is slightly misplaced and would be better off inside the condition + gDPPipeSync(POLY_OPA_DISP++); + + if (skyboxCtx->drawType != SKYBOX_DRAW_256_3FACE) { gDPLoadTLUT_pal256(POLY_OPA_DISP++, skyboxCtx->palettes[3]); - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[6]); - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[7]); + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[6]); // -x face upper + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[7]); // -x face lower } } } } else { - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[0]); - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[2]); - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[4]); - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[6]); - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[8]); + // 128x128 and 128x64 textures + // 5 or 6 faces + + // Draw each face + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[0]); // -z face + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[2]); // +z face + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[4]); // -x face + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[6]); // +x face + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[8]); // +y face if (skyboxId == SKYBOX_CUTSCENE_MAP) { - gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[10]); + // Skip the bottom face in the cutscene map + gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[10]); // -y face } }