mirror of
https://github.com/zeldaret/oot.git
synced 2025-01-15 12:47:04 +00:00
5441559b30
* clean up gSPMatrix usage * add weird hybrid macro gSPMATRIX_SET_NEW * Matrix_NewMtx, MATRIX_NEW -> Matrix_Finalize, MATRIX_FINALIZE * gSPMATRIX_SET_NEW -> MATRIX_FINALIZE_AND_LOAD * format
723 lines
28 KiB
C
723 lines
28 KiB
C
#include "global.h"
|
|
#include "fault.h"
|
|
#include "terminal.h"
|
|
#if PLATFORM_N64
|
|
#include "n64dd.h"
|
|
#endif
|
|
|
|
Vec3f D_801270A0 = { 0.0f, 0.0f, 0.0f };
|
|
|
|
// unused
|
|
Gfx D_801270B0[] = {
|
|
gsDPPipeSync(),
|
|
gsSPClearGeometryMode(G_ZBUFFER | G_CULL_BOTH | G_FOG | G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_LOD),
|
|
gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF),
|
|
gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
|
|
gsDPSetOtherMode(G_AD_DISABLE | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_NONE | G_TL_TILE |
|
|
G_TD_CLAMP | G_TP_PERSP | G_CYC_FILL | G_PM_NPRIMITIVE,
|
|
G_AC_NONE | G_ZS_PIXEL | G_RM_NOOP | G_RM_NOOP2),
|
|
gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_CULL_BACK | G_LIGHTING | G_SHADING_SMOOTH),
|
|
gsDPSetScissor(G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT),
|
|
gsSPClipRatio(FRUSTRATIO_1),
|
|
gsSPEndDisplayList(),
|
|
};
|
|
|
|
void Room_DrawNormal(PlayState* play, Room* room, u32 flags);
|
|
void Room_DrawImage(PlayState* play, Room* room, u32 flags);
|
|
void Room_DrawCullable(PlayState* play, Room* room, u32 flags);
|
|
|
|
void (*sRoomDrawHandlers[ROOM_SHAPE_TYPE_MAX])(PlayState* play, Room* room, u32 flags) = {
|
|
Room_DrawNormal, // ROOM_SHAPE_TYPE_NORMAL
|
|
Room_DrawImage, // ROOM_SHAPE_TYPE_IMAGE
|
|
Room_DrawCullable, // ROOM_SHAPE_TYPE_CULLABLE
|
|
};
|
|
|
|
void func_80095AA0(PlayState* play, Room* room, Input* input, s32 arg3) {
|
|
}
|
|
|
|
void Room_DrawNormal(PlayState* play, Room* room, u32 flags) {
|
|
s32 i;
|
|
RoomShapeNormal* roomShape;
|
|
RoomShapeDListsEntry* entry;
|
|
|
|
OPEN_DISPS(play->state.gfxCtx, "../z_room.c", 193);
|
|
|
|
if (flags & ROOM_DRAW_OPA) {
|
|
func_800342EC(&D_801270A0, play);
|
|
gSPSegment(POLY_OPA_DISP++, 0x03, room->segment);
|
|
func_80093C80(play);
|
|
gSPMatrix(POLY_OPA_DISP++, &gMtxClear, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
}
|
|
|
|
if (flags & ROOM_DRAW_XLU) {
|
|
func_8003435C(&D_801270A0, play);
|
|
gSPSegment(POLY_XLU_DISP++, 0x03, room->segment);
|
|
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
|
|
gSPMatrix(POLY_XLU_DISP++, &gMtxClear, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
}
|
|
|
|
roomShape = &room->roomShape->normal;
|
|
entry = SEGMENTED_TO_VIRTUAL(roomShape->entries);
|
|
for (i = 0; i < roomShape->numEntries; i++) {
|
|
if ((flags & ROOM_DRAW_OPA) && (entry->opa != NULL)) {
|
|
gSPDisplayList(POLY_OPA_DISP++, entry->opa);
|
|
}
|
|
|
|
if ((flags & ROOM_DRAW_XLU) && (entry->xlu != NULL)) {
|
|
gSPDisplayList(POLY_XLU_DISP++, entry->xlu);
|
|
}
|
|
|
|
entry++;
|
|
}
|
|
|
|
CLOSE_DISPS(play->state.gfxCtx, "../z_room.c", 239);
|
|
}
|
|
|
|
typedef enum RoomCullableDebugMode {
|
|
/* 0 */ ROOM_CULL_DEBUG_MODE_OFF,
|
|
/* 1 */ ROOM_CULL_DEBUG_MODE_UP_TO_TARGET,
|
|
/* 2 */ ROOM_CULL_DEBUG_MODE_ONLY_TARGET
|
|
} RoomCullableDebugMode;
|
|
|
|
typedef struct RoomShapeCullableEntryLinked {
|
|
/* 0x00 */ RoomShapeCullableEntry* entry;
|
|
/* 0x04 */ f32 boundsNearZ;
|
|
/* 0x08 */ struct RoomShapeCullableEntryLinked* prev;
|
|
/* 0x0C */ struct RoomShapeCullableEntryLinked* next;
|
|
} RoomShapeCullableEntryLinked; // size = 0x10
|
|
|
|
/**
|
|
* Handle room drawing for the "cullable" type of room shape.
|
|
*
|
|
* Each entry referenced by the room shape struct is attached to display lists, and a position and radius indicating the
|
|
* bounding sphere for the geometry drawn.
|
|
* The first step Z-sorts the entries, and excludes the entries with a bounding sphere that is entirely before or
|
|
* beyond the rendered depth range.
|
|
* The second step draws the entries that remain, from nearest to furthest.
|
|
*/
|
|
void Room_DrawCullable(PlayState* play, Room* room, u32 flags) {
|
|
RoomShapeCullable* roomShape;
|
|
RoomShapeCullableEntry* roomShapeCullableEntry;
|
|
RoomShapeCullableEntryLinked linkedEntriesBuffer[ROOM_SHAPE_CULLABLE_MAX_ENTRIES];
|
|
RoomShapeCullableEntryLinked* head = NULL;
|
|
RoomShapeCullableEntryLinked* tail = NULL;
|
|
RoomShapeCullableEntryLinked* iter;
|
|
s32 pad;
|
|
RoomShapeCullableEntryLinked* insert;
|
|
s32 j;
|
|
s32 i;
|
|
Vec3f pos;
|
|
Vec3f projectedPos;
|
|
f32 projectedW;
|
|
s32 pad2;
|
|
RoomShapeCullableEntry* roomShapeCullableEntries;
|
|
RoomShapeCullableEntry* roomShapeCullableEntryIter;
|
|
f32 entryBoundsNearZ;
|
|
|
|
OPEN_DISPS(play->state.gfxCtx, "../z_room.c", 287);
|
|
|
|
if (flags & ROOM_DRAW_OPA) {
|
|
func_800342EC(&D_801270A0, play);
|
|
gSPSegment(POLY_OPA_DISP++, 0x03, room->segment);
|
|
func_80093C80(play);
|
|
gSPMatrix(POLY_OPA_DISP++, &gMtxClear, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
}
|
|
|
|
if (1) {}
|
|
|
|
if (flags & ROOM_DRAW_XLU) {
|
|
func_8003435C(&D_801270A0, play);
|
|
gSPSegment(POLY_XLU_DISP++, 0x03, room->segment);
|
|
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
|
|
gSPMatrix(POLY_XLU_DISP++, &gMtxClear, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
}
|
|
|
|
roomShape = &room->roomShape->cullable;
|
|
roomShapeCullableEntry = SEGMENTED_TO_VIRTUAL(roomShape->entries);
|
|
insert = linkedEntriesBuffer;
|
|
|
|
ASSERT(roomShape->numEntries <= ROOM_SHAPE_CULLABLE_MAX_ENTRIES, "polygon2->num <= SHAPE_SORT_MAX", "../z_room.c",
|
|
317);
|
|
|
|
roomShapeCullableEntries = roomShapeCullableEntry;
|
|
|
|
// Pick and sort entries by depth
|
|
for (i = 0; i < roomShape->numEntries; i++, roomShapeCullableEntry++) {
|
|
|
|
// Project the entry position, to get the depth it is at.
|
|
pos.x = roomShapeCullableEntry->boundsSphereCenter.x;
|
|
pos.y = roomShapeCullableEntry->boundsSphereCenter.y;
|
|
pos.z = roomShapeCullableEntry->boundsSphereCenter.z;
|
|
SkinMatrix_Vec3fMtxFMultXYZW(&play->viewProjectionMtxF, &pos, &projectedPos, &projectedW);
|
|
|
|
// If the entry bounding sphere isn't fully before the rendered depth range
|
|
if (-(f32)roomShapeCullableEntry->boundsSphereRadius < projectedPos.z) {
|
|
|
|
// Compute the depth of the nearest point in the entry's bounding sphere
|
|
entryBoundsNearZ = projectedPos.z - roomShapeCullableEntry->boundsSphereRadius;
|
|
|
|
// If the entry bounding sphere isn't fully beyond the rendered depth range
|
|
if (entryBoundsNearZ < play->lightCtx.zFar) {
|
|
|
|
// This entry will be rendered
|
|
insert->entry = roomShapeCullableEntry;
|
|
insert->boundsNearZ = entryBoundsNearZ;
|
|
|
|
// Insert into the linked list, ordered by ascending depth of the nearest point in the bounding sphere
|
|
iter = head;
|
|
if (iter == NULL) {
|
|
head = tail = insert;
|
|
insert->prev = insert->next = NULL;
|
|
} else {
|
|
do {
|
|
if (insert->boundsNearZ < iter->boundsNearZ) {
|
|
break;
|
|
}
|
|
iter = iter->next;
|
|
} while (iter != NULL);
|
|
|
|
if (iter == NULL) {
|
|
insert->prev = tail;
|
|
insert->next = NULL;
|
|
tail->next = insert;
|
|
tail = insert;
|
|
} else {
|
|
insert->prev = iter->prev;
|
|
if (insert->prev == NULL) {
|
|
head = insert;
|
|
} else {
|
|
insert->prev->next = insert;
|
|
}
|
|
iter->prev = insert;
|
|
insert->next = iter;
|
|
}
|
|
}
|
|
|
|
insert++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if this is real then I might not be
|
|
R_ROOM_CULL_NUM_ENTRIES = roomShape->numEntries & 0xFFFF & 0xFFFF & 0xFFFF;
|
|
|
|
// Draw entries, from nearest to furthest
|
|
for (i = 1; head != NULL; head = head->next, i++) {
|
|
Gfx* displayList;
|
|
|
|
roomShapeCullableEntry = head->entry;
|
|
|
|
if (R_ROOM_CULL_DEBUG_MODE != ROOM_CULL_DEBUG_MODE_OFF) {
|
|
// Debug mode drawing
|
|
|
|
// This loop does nothing
|
|
roomShapeCullableEntryIter = roomShapeCullableEntries;
|
|
for (j = 0; j < roomShape->numEntries; j++, roomShapeCullableEntryIter++) {
|
|
if (roomShapeCullableEntry == roomShapeCullableEntryIter) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (((R_ROOM_CULL_DEBUG_MODE == ROOM_CULL_DEBUG_MODE_UP_TO_TARGET) && (i <= R_ROOM_CULL_DEBUG_TARGET)) ||
|
|
((R_ROOM_CULL_DEBUG_MODE == ROOM_CULL_DEBUG_MODE_ONLY_TARGET) && (i == R_ROOM_CULL_DEBUG_TARGET))) {
|
|
if (flags & ROOM_DRAW_OPA) {
|
|
displayList = roomShapeCullableEntry->opa;
|
|
if (displayList != NULL) {
|
|
gSPDisplayList(POLY_OPA_DISP++, displayList);
|
|
}
|
|
}
|
|
|
|
if (flags & ROOM_DRAW_XLU) {
|
|
displayList = roomShapeCullableEntry->xlu;
|
|
if (displayList != NULL) {
|
|
gSPDisplayList(POLY_XLU_DISP++, displayList);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (flags & ROOM_DRAW_OPA) {
|
|
displayList = roomShapeCullableEntry->opa;
|
|
if (displayList != NULL) {
|
|
gSPDisplayList(POLY_OPA_DISP++, displayList);
|
|
}
|
|
}
|
|
|
|
if (flags & ROOM_DRAW_XLU) {
|
|
displayList = roomShapeCullableEntry->xlu;
|
|
if (displayList != NULL) {
|
|
gSPDisplayList(POLY_XLU_DISP++, displayList);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
R_ROOM_CULL_USED_ENTRIES = i - 1;
|
|
|
|
CLOSE_DISPS(play->state.gfxCtx, "../z_room.c", 430);
|
|
}
|
|
|
|
#define JPEG_MARKER 0xFFD8FFE0
|
|
|
|
/**
|
|
* If the data is JPEG, decode it and overwrite the initial data with the result.
|
|
* Uses the depth frame buffer as temporary storage.
|
|
*/
|
|
s32 Room_DecodeJpeg(void* data) {
|
|
OSTime time;
|
|
|
|
if (*(u32*)data == JPEG_MARKER) {
|
|
PRINTF(T("JPEGデータを展開します\n", "Expanding jpeg data\n"));
|
|
PRINTF(T("JPEGデータアドレス %08x\n", "Jpeg data address %08x\n"), data);
|
|
PRINTF(T("ワークバッファアドレス(Zバッファ)%08x\n", "Work buffer address (Z buffer) %08x\n"), gZBuffer);
|
|
|
|
time = osGetTime();
|
|
if (!Jpeg_Decode(data, gZBuffer, gGfxSPTaskOutputBuffer, sizeof(gGfxSPTaskOutputBuffer))) {
|
|
time = osGetTime() - time;
|
|
|
|
PRINTF(T("成功…だと思う。 time = %6.3f ms \n", "Success... I think. time = %6.3f ms\n"),
|
|
OS_CYCLES_TO_USEC(time) / 1000.0f);
|
|
PRINTF(T("ワークバッファから元のアドレスに書き戻します。\n",
|
|
"Writing back to original address from work buffer.\n"));
|
|
PRINTF(T("元のバッファのサイズが150キロバイト無いと暴走するでしょう。\n",
|
|
"If the original buffer size isn't at least 150kB, it will be out of control.\n"));
|
|
|
|
bcopy(gZBuffer, data, sizeof(u16[SCREEN_HEIGHT][SCREEN_WIDTH]));
|
|
} else {
|
|
PRINTF(T("失敗!なんで〜\n", "Failure! Why is it ~\n"));
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void Room_DrawBackground2D(Gfx** gfxP, void* tex, void* tlut, u16 width, u16 height, u8 fmt, u8 siz, u16 tlutMode,
|
|
u16 tlutCount, f32 offsetX, f32 offsetY) {
|
|
Gfx* gfx = *gfxP;
|
|
uObjBg* bg;
|
|
|
|
Room_DecodeJpeg(SEGMENTED_TO_VIRTUAL(tex));
|
|
|
|
bg = (uObjBg*)(gfx + 1);
|
|
gSPBranchList(gfx, (Gfx*)(bg + 1));
|
|
gfx = (Gfx*)(bg + 1);
|
|
|
|
bg->b.imageX = 0;
|
|
bg->b.imageW = width * (1 << 2);
|
|
bg->b.frameX = offsetX * (1 << 2);
|
|
bg->b.imageY = 0;
|
|
bg->b.imageH = height * (1 << 2);
|
|
bg->b.frameY = offsetY * (1 << 2);
|
|
bg->b.imagePtr = tex;
|
|
bg->b.imageLoad = G_BGLT_LOADTILE;
|
|
bg->b.imageFmt = fmt;
|
|
bg->b.imageSiz = siz;
|
|
bg->b.imagePal = 0;
|
|
bg->b.imageFlip = 0;
|
|
|
|
if (fmt == G_IM_FMT_CI) {
|
|
gDPLoadTLUT(gfx++, tlutCount, 256, tlut);
|
|
} else {
|
|
gDPPipeSync(gfx++);
|
|
}
|
|
|
|
if ((fmt == G_IM_FMT_RGBA) && !R_ROOM_BG2D_FORCE_SCALEBG) {
|
|
bg->b.frameW = width * (1 << 2);
|
|
bg->b.frameH = height * (1 << 2);
|
|
guS2DInitBg(bg);
|
|
gDPSetOtherMode(gfx++, tlutMode | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_COPY | G_PM_NPRIMITIVE,
|
|
G_AC_THRESHOLD | G_ZS_PIXEL | G_RM_NOOP | G_RM_NOOP2);
|
|
gSPBgRectCopy(gfx++, bg);
|
|
|
|
} else {
|
|
bg->s.frameW = width * (1 << 2);
|
|
bg->s.frameH = height * (1 << 2);
|
|
bg->s.scaleW = 1 << 10;
|
|
bg->s.scaleH = 1 << 10;
|
|
bg->s.imageYorig = bg->b.imageY;
|
|
gDPSetOtherMode(gfx++,
|
|
tlutMode | G_AD_DISABLE | G_CD_DISABLE | G_CK_NONE | G_TC_FILT | G_TF_POINT | G_TL_TILE |
|
|
G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE,
|
|
G_AC_THRESHOLD | G_ZS_PIXEL | AA_EN | CVG_DST_CLAMP | ZMODE_OPA | CVG_X_ALPHA | ALPHA_CVG_SEL |
|
|
GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_BL, G_BL_1MA) |
|
|
GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_BL, G_BL_1MA));
|
|
gDPSetCombineLERP(gfx++, 0, 0, 0, TEXEL0, 0, 0, 0, 1, 0, 0, 0, TEXEL0, 0, 0, 0, 1);
|
|
gSPObjRenderMode(gfx++, G_OBJRM_ANTIALIAS | G_OBJRM_BILERP);
|
|
gSPBgRect1Cyc(gfx++, bg);
|
|
}
|
|
|
|
gDPPipeSync(gfx++);
|
|
|
|
*gfxP = gfx;
|
|
}
|
|
|
|
#define ROOM_IMAGE_NODRAW_BACKGROUND (1 << 0)
|
|
#define ROOM_IMAGE_NODRAW_OPA (1 << 1)
|
|
#define ROOM_IMAGE_NODRAW_XLU (1 << 2)
|
|
|
|
void Room_DrawImageSingle(PlayState* play, Room* room, u32 flags) {
|
|
Camera* activeCam;
|
|
Gfx* gfx;
|
|
RoomShapeImageSingle* roomShape;
|
|
RoomShapeDListsEntry* entry;
|
|
u32 isFixedCamera;
|
|
u32 drawBackground;
|
|
u32 drawOpa;
|
|
u32 drawXlu;
|
|
|
|
OPEN_DISPS(play->state.gfxCtx, "../z_room.c", 628);
|
|
|
|
activeCam = GET_ACTIVE_CAM(play);
|
|
isFixedCamera = (activeCam->setting == CAM_SET_PREREND_FIXED);
|
|
roomShape = &room->roomShape->image.single;
|
|
entry = SEGMENTED_TO_VIRTUAL(roomShape->base.entry);
|
|
drawBackground = (flags & ROOM_DRAW_OPA) && isFixedCamera && (roomShape->source != NULL) &&
|
|
!(R_ROOM_IMAGE_NODRAW_FLAGS & ROOM_IMAGE_NODRAW_BACKGROUND);
|
|
drawOpa = (flags & ROOM_DRAW_OPA) && (entry->opa != NULL) && !(R_ROOM_IMAGE_NODRAW_FLAGS & ROOM_IMAGE_NODRAW_OPA);
|
|
drawXlu = (flags & ROOM_DRAW_XLU) && (entry->xlu != NULL) && !(R_ROOM_IMAGE_NODRAW_FLAGS & ROOM_IMAGE_NODRAW_XLU);
|
|
|
|
if (drawOpa || drawBackground) {
|
|
gSPSegment(POLY_OPA_DISP++, 0x03, room->segment);
|
|
|
|
if (drawOpa) {
|
|
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
|
gSPMatrix(POLY_OPA_DISP++, &gMtxClear, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_OPA_DISP++, entry->opa);
|
|
}
|
|
|
|
if (drawBackground) {
|
|
gSPLoadUcodeL(POLY_OPA_DISP++, gspS2DEX2d_fifo);
|
|
|
|
gfx = POLY_OPA_DISP;
|
|
|
|
{
|
|
Vec3f quakeOffset;
|
|
|
|
quakeOffset = Camera_GetQuakeOffset(activeCam);
|
|
Room_DrawBackground2D(&gfx, roomShape->source, roomShape->tlut, roomShape->width, roomShape->height,
|
|
roomShape->fmt, roomShape->siz, roomShape->tlutMode, roomShape->tlutCount,
|
|
(quakeOffset.x + quakeOffset.z) * 1.2f + quakeOffset.y * 0.6f,
|
|
quakeOffset.y * 2.4f + (quakeOffset.x + quakeOffset.z) * 0.3f);
|
|
}
|
|
|
|
POLY_OPA_DISP = gfx;
|
|
|
|
gSPLoadUcode(POLY_OPA_DISP++, SysUcode_GetUCode(), SysUcode_GetUCodeData());
|
|
}
|
|
}
|
|
|
|
if (drawXlu) {
|
|
gSPSegment(POLY_XLU_DISP++, 0x03, room->segment);
|
|
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
|
|
gSPMatrix(POLY_XLU_DISP++, &gMtxClear, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, entry->xlu);
|
|
}
|
|
|
|
CLOSE_DISPS(play->state.gfxCtx, "../z_room.c", 691);
|
|
}
|
|
|
|
RoomShapeImageMultiBgEntry* Room_GetImageMultiBgEntry(RoomShapeImageMulti* roomShapeImageMulti, PlayState* play) {
|
|
Camera* activeCam = GET_ACTIVE_CAM(play);
|
|
s32 bgCamIndex = activeCam->bgCamIndex;
|
|
s16 overrideBgCamIndex;
|
|
Player* player;
|
|
RoomShapeImageMultiBgEntry* bgEntry;
|
|
s32 i;
|
|
|
|
// In mq debug vanilla scenes, overrideBgCamIndex is always -1 or the same as bgCamIndex
|
|
overrideBgCamIndex = ((BgCamFuncData*)BgCheck_GetBgCamFuncDataImpl(&play->colCtx, bgCamIndex, BGCHECK_SCENE))
|
|
->roomImageOverrideBgCamIndex;
|
|
if (overrideBgCamIndex >= 0) {
|
|
bgCamIndex = overrideBgCamIndex;
|
|
}
|
|
|
|
player = GET_PLAYER(play);
|
|
player->actor.params = PARAMS_GET_NOSHIFT(player->actor.params, 8, 8) | bgCamIndex;
|
|
|
|
bgEntry = SEGMENTED_TO_VIRTUAL(roomShapeImageMulti->backgrounds);
|
|
for (i = 0; i < roomShapeImageMulti->numBackgrounds; i++) {
|
|
if (bgEntry->bgCamIndex == bgCamIndex) {
|
|
return bgEntry;
|
|
}
|
|
bgEntry++;
|
|
}
|
|
|
|
PRINTF(VT_COL(RED, WHITE) T("z_room.c:カメラIDに一致するデータが存在しません camid=%d\n",
|
|
"z_room.c: Data consistent with camera id does not exist camid=%d\n") VT_RST,
|
|
bgCamIndex);
|
|
#if PLATFORM_N64
|
|
Fault_AddHungupAndCrash("../z_room.c", 721);
|
|
#else
|
|
LogUtils_HungupThread("../z_room.c", 726);
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void Room_DrawImageMulti(PlayState* play, Room* room, u32 flags) {
|
|
Camera* activeCam;
|
|
Gfx* gfx;
|
|
RoomShapeImageMulti* roomShape;
|
|
RoomShapeImageMultiBgEntry* bgEntry;
|
|
RoomShapeDListsEntry* dListsEntry;
|
|
u32 isFixedCamera;
|
|
u32 drawBackground;
|
|
u32 drawOpa;
|
|
u32 drawXlu;
|
|
|
|
OPEN_DISPS(play->state.gfxCtx, "../z_room.c", 752);
|
|
|
|
activeCam = GET_ACTIVE_CAM(play);
|
|
isFixedCamera = (activeCam->setting == CAM_SET_PREREND_FIXED);
|
|
roomShape = &room->roomShape->image.multi;
|
|
dListsEntry = SEGMENTED_TO_VIRTUAL(roomShape->base.entry);
|
|
|
|
bgEntry = Room_GetImageMultiBgEntry(roomShape, play);
|
|
|
|
drawBackground = (flags & ROOM_DRAW_OPA) && isFixedCamera && (bgEntry->source != NULL) &&
|
|
!(R_ROOM_IMAGE_NODRAW_FLAGS & ROOM_IMAGE_NODRAW_BACKGROUND);
|
|
drawOpa =
|
|
(flags & ROOM_DRAW_OPA) && (dListsEntry->opa != NULL) && !(R_ROOM_IMAGE_NODRAW_FLAGS & ROOM_IMAGE_NODRAW_OPA);
|
|
drawXlu =
|
|
(flags & ROOM_DRAW_XLU) && (dListsEntry->xlu != NULL) && !(R_ROOM_IMAGE_NODRAW_FLAGS & ROOM_IMAGE_NODRAW_XLU);
|
|
|
|
if (drawOpa || drawBackground) {
|
|
gSPSegment(POLY_OPA_DISP++, 0x03, room->segment);
|
|
|
|
if (drawOpa) {
|
|
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
|
gSPMatrix(POLY_OPA_DISP++, &gMtxClear, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_OPA_DISP++, dListsEntry->opa);
|
|
}
|
|
|
|
if (drawBackground) {
|
|
gSPLoadUcodeL(POLY_OPA_DISP++, gspS2DEX2d_fifo);
|
|
|
|
gfx = POLY_OPA_DISP;
|
|
|
|
{
|
|
Vec3f quakeOffset;
|
|
|
|
quakeOffset = Camera_GetQuakeOffset(activeCam);
|
|
Room_DrawBackground2D(&gfx, bgEntry->source, bgEntry->tlut, bgEntry->width, bgEntry->height,
|
|
bgEntry->fmt, bgEntry->siz, bgEntry->tlutMode, bgEntry->tlutCount,
|
|
(quakeOffset.x + quakeOffset.z) * 1.2f + quakeOffset.y * 0.6f,
|
|
quakeOffset.y * 2.4f + (quakeOffset.x + quakeOffset.z) * 0.3f);
|
|
}
|
|
|
|
POLY_OPA_DISP = gfx;
|
|
|
|
gSPLoadUcode(POLY_OPA_DISP++, SysUcode_GetUCode(), SysUcode_GetUCodeData());
|
|
}
|
|
}
|
|
|
|
if (drawXlu) {
|
|
gSPSegment(POLY_XLU_DISP++, 0x03, room->segment);
|
|
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
|
|
gSPMatrix(POLY_XLU_DISP++, &gMtxClear, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, dListsEntry->xlu);
|
|
}
|
|
|
|
CLOSE_DISPS(play->state.gfxCtx, "../z_room.c", 819);
|
|
}
|
|
|
|
void Room_DrawImage(PlayState* play, Room* room, u32 flags) {
|
|
RoomShapeImageBase* roomShape = &room->roomShape->image.base;
|
|
|
|
if (roomShape->amountType == ROOM_SHAPE_IMAGE_AMOUNT_SINGLE) {
|
|
Room_DrawImageSingle(play, room, flags);
|
|
} else if (roomShape->amountType == ROOM_SHAPE_IMAGE_AMOUNT_MULTI) {
|
|
Room_DrawImageMulti(play, room, flags);
|
|
} else {
|
|
#if PLATFORM_N64
|
|
Fault_AddHungupAndCrash("../z_room.c", 836);
|
|
#else
|
|
LogUtils_HungupThread("../z_room.c", 841);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void Room_Init(PlayState* play, Room* room) {
|
|
room->num = -1;
|
|
room->segment = NULL;
|
|
}
|
|
|
|
/**
|
|
* Allocates memory for rooms and fetches the first room that the player will spawn into.
|
|
*
|
|
* @return u32 size of the buffer reserved for room data
|
|
*/
|
|
u32 Room_SetupFirstRoom(PlayState* play, RoomContext* roomCtx) {
|
|
u32 roomBufferSize = 0;
|
|
u32 roomSize;
|
|
s32 i;
|
|
s32 j;
|
|
s32 frontRoom;
|
|
s32 backRoom;
|
|
u32 frontRoomSize;
|
|
u32 backRoomSize;
|
|
u32 cumulRoomSize;
|
|
s32 pad;
|
|
|
|
// Set roomBufferSize to the largest room
|
|
{
|
|
RomFile* roomList = play->roomList.romFiles;
|
|
|
|
for (i = 0; i < play->roomList.count; i++) {
|
|
roomSize = roomList[i].vromEnd - roomList[i].vromStart;
|
|
PRINTF("ROOM%d size=%d\n", i, roomSize);
|
|
if (roomBufferSize < roomSize) {
|
|
roomBufferSize = roomSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If there any rooms are connected, find their combined size and update roomBufferSize if larger
|
|
if ((u32)play->transitionActors.count != 0) {
|
|
RomFile* roomList = play->roomList.romFiles;
|
|
TransitionActorEntry* transitionActor = &play->transitionActors.list[0];
|
|
|
|
LOG_NUM("game_play->room_rom_address.num", play->roomList.count, "../z_room.c", 912);
|
|
|
|
for (j = 0; j < play->transitionActors.count; j++) {
|
|
frontRoom = transitionActor->sides[0].room;
|
|
backRoom = transitionActor->sides[1].room;
|
|
frontRoomSize = (frontRoom < 0) ? 0 : roomList[frontRoom].vromEnd - roomList[frontRoom].vromStart;
|
|
backRoomSize = (backRoom < 0) ? 0 : roomList[backRoom].vromEnd - roomList[backRoom].vromStart;
|
|
cumulRoomSize = (frontRoom != backRoom) ? frontRoomSize + backRoomSize : frontRoomSize;
|
|
|
|
PRINTF("DOOR%d=<%d> ROOM1=<%d, %d> ROOM2=<%d, %d>\n", j, cumulRoomSize, frontRoom, frontRoomSize, backRoom,
|
|
backRoomSize);
|
|
if (roomBufferSize < cumulRoomSize) {
|
|
roomBufferSize = cumulRoomSize;
|
|
}
|
|
transitionActor++;
|
|
}
|
|
}
|
|
|
|
PRINTF(VT_FGCOL(YELLOW));
|
|
PRINTF(T("部屋バッファサイズ=%08x(%5.1fK)\n", "Room buffer size=%08x(%5.1fK)\n"), roomBufferSize,
|
|
roomBufferSize / 1024.0f);
|
|
roomCtx->bufPtrs[0] = GAME_STATE_ALLOC(&play->state, roomBufferSize, "../z_room.c", 946);
|
|
PRINTF(T("部屋バッファ開始ポインタ=%08x\n", "Room buffer initial pointer=%08x\n"), roomCtx->bufPtrs[0]);
|
|
roomCtx->bufPtrs[1] = (void*)((uintptr_t)roomCtx->bufPtrs[0] + roomBufferSize);
|
|
PRINTF(T("部屋バッファ終了ポインタ=%08x\n", "Room buffer end pointer=%08x\n"), roomCtx->bufPtrs[1]);
|
|
PRINTF(VT_RST);
|
|
roomCtx->activeBufPage = 0;
|
|
roomCtx->status = 0;
|
|
|
|
frontRoom = gSaveContext.respawnFlag > 0 ? ((void)0, gSaveContext.respawn[gSaveContext.respawnFlag - 1].roomIndex)
|
|
: play->spawnList[play->spawn].room;
|
|
|
|
// Load into a room for the first time.
|
|
// Since curRoom was initialized to `room = -1` and `segment = NULL` in Play_InitScene, the previous room
|
|
// will also be initialized to the nulled state when this function completes.
|
|
Room_RequestNewRoom(play, roomCtx, frontRoom);
|
|
|
|
return roomBufferSize;
|
|
}
|
|
|
|
/**
|
|
* Tries to create an asynchronous request to transfer room data into memory.
|
|
* If successful, the requested room will be loaded into memory and becomes the new current room; the room that was
|
|
* current before becomes the previous room.
|
|
*
|
|
* Room_RequestNewRoom will be blocked from loading new rooms until Room_ProcessRoomRequest completes room
|
|
* initialization.
|
|
*
|
|
* Calling Room_RequestNewRoom outside of Room_SetupFirstRoom will allow for two rooms being initialized simultaneously.
|
|
* This allows an actor like ACTOR_EN_HOLL to seamlessly swap the two rooms as the player moves between them. Calling
|
|
* Room_FinishRoomChange afterward will finalize the room swap.
|
|
*
|
|
* @param roomNum is the id of the room to load. roomNum must NOT be the same id as curRoom.num, since this will create
|
|
* duplicate actor instances that cannot be cleaned up by calling Room_FinishRoomChange
|
|
* @returns bool false if the request could not be created.
|
|
*/
|
|
s32 Room_RequestNewRoom(PlayState* play, RoomContext* roomCtx, s32 roomNum) {
|
|
if (roomCtx->status == 0) {
|
|
u32 size;
|
|
|
|
roomCtx->prevRoom = roomCtx->curRoom;
|
|
roomCtx->curRoom.num = roomNum;
|
|
roomCtx->curRoom.segment = NULL;
|
|
roomCtx->status = 1;
|
|
|
|
ASSERT(roomNum < play->roomList.count, "read_room_ID < game_play->room_rom_address.num", "../z_room.c", 1009);
|
|
|
|
size = play->roomList.romFiles[roomNum].vromEnd - play->roomList.romFiles[roomNum].vromStart;
|
|
roomCtx->roomRequestAddr = (void*)ALIGN16((uintptr_t)roomCtx->bufPtrs[roomCtx->activeBufPage] -
|
|
((size + 8) * roomCtx->activeBufPage + 7));
|
|
|
|
osCreateMesgQueue(&roomCtx->loadQueue, &roomCtx->loadMsg, 1);
|
|
|
|
#if PLATFORM_N64
|
|
if ((B_80121220 != NULL) && (B_80121220->unk_08 != NULL)) {
|
|
B_80121220->unk_08(play, roomCtx, roomNum);
|
|
} else {
|
|
DMA_REQUEST_ASYNC(&roomCtx->dmaRequest, roomCtx->roomRequestAddr,
|
|
play->roomList.romFiles[roomNum].vromStart, size, 0, &roomCtx->loadQueue, NULL,
|
|
"../z_room.c", 1036);
|
|
}
|
|
#else
|
|
DMA_REQUEST_ASYNC(&roomCtx->dmaRequest, roomCtx->roomRequestAddr, play->roomList.romFiles[roomNum].vromStart,
|
|
size, 0, &roomCtx->loadQueue, NULL, "../z_room.c", 1036);
|
|
#endif
|
|
|
|
roomCtx->activeBufPage ^= 1;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Completes room initialization for the room requested by a call to Room_RequestNewRoom.
|
|
* This function does not block the thread if the room data is still being transferred.
|
|
*
|
|
* @returns bool false if a dma transfer is in progress.
|
|
*/
|
|
s32 Room_ProcessRoomRequest(PlayState* play, RoomContext* roomCtx) {
|
|
if (roomCtx->status == 1) {
|
|
if (osRecvMesg(&roomCtx->loadQueue, NULL, OS_MESG_NOBLOCK) == 0) {
|
|
roomCtx->status = 0;
|
|
roomCtx->curRoom.segment = roomCtx->roomRequestAddr;
|
|
gSegments[3] = VIRTUAL_TO_PHYSICAL(roomCtx->curRoom.segment);
|
|
|
|
Scene_ExecuteCommands(play, roomCtx->curRoom.segment);
|
|
Player_SetBootData(play, GET_PLAYER(play));
|
|
Actor_SpawnTransitionActors(play, &play->actorCtx);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Room_Draw(PlayState* play, Room* room, u32 flags) {
|
|
if (room->segment != NULL) {
|
|
gSegments[3] = VIRTUAL_TO_PHYSICAL(room->segment);
|
|
ASSERT(room->roomShape->base.type < ARRAY_COUNTU(sRoomDrawHandlers),
|
|
"this->ground_shape->polygon.type < number(Room_Draw_Proc)", "../z_room.c", 1125);
|
|
sRoomDrawHandlers[room->roomShape->base.type](play, room, flags);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Finalizes a swap between two rooms.
|
|
*
|
|
* When a new room is created with Room_RequestNewRoom, the previous room and its actors remain in memory. This allows
|
|
* an actor like ACTOR_EN_HOLL to seamlessly swap the two rooms as the player moves between them.
|
|
*/
|
|
void Room_FinishRoomChange(PlayState* play, RoomContext* roomCtx) {
|
|
// Delete the previous room
|
|
roomCtx->prevRoom.num = -1;
|
|
roomCtx->prevRoom.segment = NULL;
|
|
|
|
func_80031B14(play, &play->actorCtx);
|
|
Actor_SpawnTransitionActors(play, &play->actorCtx);
|
|
Map_InitRoomData(play, roomCtx->curRoom.num);
|
|
if (!((play->sceneId >= SCENE_HYRULE_FIELD) && (play->sceneId <= SCENE_LON_LON_RANCH))) {
|
|
Map_SavePlayerInitialInfo(play);
|
|
}
|
|
Audio_SetEnvReverb(play->roomCtx.curRoom.echo);
|
|
}
|