diff --git a/include/config/config_graphics.h b/include/config/config_graphics.h index 591254ad1..6b55b0ed7 100644 --- a/include/config/config_graphics.h +++ b/include/config/config_graphics.h @@ -29,12 +29,10 @@ // Similar to the above, but 30 FPS (Textures by InTheBeef, cleaned up by Arceveti) #define IA8_30FPS_COINS -#ifdef F3DEX_GBI_2 // !Safeguard -// Use .rej microcode for certain objects (experimental - only should be used when F3DEX_GBI_2 is defined). +// Use .rej microcode for certain objects (experimental - only should be used when F3DZEX_GBI_2 is defined). // So far - recent tests have show that this has reduced performance overall due to CPU load, // though in some cases it may perform better. // #define OBJECTS_REJ -#endif /** * Mario's silhouette when behind solid objects/surfaces @@ -65,10 +63,27 @@ // Uses the correct "up" vector for the guLookAtReflect call in geo_process_master_list_sub. // It is sideways in vanilla, and since vanilla's environment map textures are sideways too, they will appear as sideways in-game if this is enabled. // Make sure your custom environment map textures are the correct orientation. -#define FIX_REFLECT_MTX +// #define FIX_REFLECT_MTX // This improves performance a bit, and does not seem to break anything. #define DISABLE_GRAPH_NODE_TYPE_FUNCTIONAL // Disables object shadows. You'll probably only want this either as a last resort for performance or if you're making a super stylized hack. -//#define DISABLE_SHADOWS +// #define DISABLE_SHADOWS + + +// -- Compatibility safeguards. Don't mess with these unless you know what you're doing.-- + +#ifndef F3DZEX_GBI_2 +#undef OBJECTS_REJ // OBJECTS_REJ requires f3dzex. +#endif // !F3DZEX_GBI_2 + +#ifndef F3DEX_GBI_SHARED +#undef OBJECTS_REJ // Non F3DEX-based ucodes do NOT support ucode switching. +#endif // !F3DEX_GBI_SHARED + +#ifdef OBJECTS_REJ +// Enable required ucodes. +#define F3DEX2_REJ_GBI +#define F3DLX2_REJ_GBI +#endif // OBJECTS_REJ diff --git a/rspdata.inc.ld b/rspdata.inc.ld index 8bf38b02a..2e8f077f3 100644 --- a/rspdata.inc.ld +++ b/rspdata.inc.ld @@ -68,6 +68,11 @@ lib/PR/f3dex2/fifo/gspF3DEX2.Rej.fifo.o(.data); #endif +/* Fast3DLX2 Rej Data */ +#ifdef F3DLX2_REJ_GBI + lib/PR/f3dex2/fifo/gspF3DLX2.Rej.fifo.o(.data); +#endif + /* Line3DEX2 Data */ #ifdef L3DEX2_GBI lib/PR/f3dex2/fifo/gspL3DEX2.fifo.o(.data); @@ -81,4 +86,4 @@ /* S2DEX2 Data */ #ifdef S2DEX_GBI_2 lib/PR/s2dex2/fifo/gspS2DEX2.fifo.o(.data); -#endif \ No newline at end of file +#endif diff --git a/rsptext.inc.ld b/rsptext.inc.ld index f9a423168..5d5b9d69d 100644 --- a/rsptext.inc.ld +++ b/rsptext.inc.ld @@ -68,6 +68,11 @@ lib/PR/f3dex2/fifo/gspF3DEX2.Rej.fifo.o(.text); #endif +/* Fast3DLX2 Rej Text */ +#ifdef F3DLX2_REJ_GBI + lib/PR/f3dex2/fifo/gspF3DLX2.Rej.fifo.o(.text); +#endif + /* Line3DEX2 Text */ #ifdef L3DEX2_GBI lib/PR/f3dex2/fifo/gspL3DEX2.fifo.o(.text); @@ -81,4 +86,4 @@ /* S2DEX2 Text */ #ifdef S2DEX_GBI_2 lib/PR/s2dex2/fifo/gspS2DEX2.fifo.o(.text); -#endif \ No newline at end of file +#endif diff --git a/src/game/game_init.c b/src/game/game_init.c index e27d9d02e..3626d0449 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -278,31 +278,47 @@ void create_gfx_task_structure(void) { gGfxSPTask->task.t.type = M_GFXTASK; gGfxSPTask->task.t.ucode_boot = rspbootTextStart; gGfxSPTask->task.t.ucode_boot_size = ((u8 *) rspbootTextEnd - (u8 *) rspbootTextStart); - gGfxSPTask->task.t.flags = OS_TASK_LOADABLE | OS_TASK_DP_WAIT; +#if defined(F3DEX_GBI_SHARED) && defined(OBJECTS_REJ) + gGfxSPTask->task.t.flags = (OS_TASK_LOADABLE | OS_TASK_DP_WAIT); +#else + gGfxSPTask->task.t.flags = 0x0; +#endif #ifdef L3DEX2_ALONE gGfxSPTask->task.t.ucode = gspL3DEX2_fifoTextStart; gGfxSPTask->task.t.ucode_data = gspL3DEX2_fifoDataStart; + gGfxSPTask->task.t.ucode_size = ((u8 *) gspL3DEX2_fifoTextEnd - (u8 *) gspL3DEX2_fifoTextStart); + gGfxSPTask->task.t.ucode_data_size = ((u8 *) gspL3DEX2_fifoDataEnd - (u8 *) gspL3DEX2_fifoDataStart); #elif F3DZEX_GBI_2 gGfxSPTask->task.t.ucode = gspF3DZEX2_PosLight_fifoTextStart; gGfxSPTask->task.t.ucode_data = gspF3DZEX2_PosLight_fifoDataStart; + gGfxSPTask->task.t.ucode_size = ((u8 *) gspF3DZEX2_PosLight_fifoTextEnd - (u8 *) gspF3DZEX2_PosLight_fifoTextStart); + gGfxSPTask->task.t.ucode_data_size = ((u8 *) gspF3DZEX2_PosLight_fifoDataEnd - (u8 *) gspF3DZEX2_PosLight_fifoDataStart); #elif F3DEX2PL_GBI gGfxSPTask->task.t.ucode = gspF3DEX2_PosLight_fifoTextStart; gGfxSPTask->task.t.ucode_data = gspF3DEX2_PosLight_fifoDataStart; + gGfxSPTask->task.t.ucode_size = ((u8 *) gspF3DEX2_PosLight_fifoTextEnd - (u8 *) gspF3DEX2_PosLight_fifoTextStart); + gGfxSPTask->task.t.ucode_data_size = ((u8 *) gspF3DEX2_PosLight_fifoDataEnd - (u8 *) gspF3DEX2_PosLight_fifoDataStart); #elif F3DEX_GBI_2 gGfxSPTask->task.t.ucode = gspF3DEX2_fifoTextStart; gGfxSPTask->task.t.ucode_data = gspF3DEX2_fifoDataStart; + gGfxSPTask->task.t.ucode_size = ((u8 *) gspF3DEX2_fifoTextEnd - (u8 *) gspF3DEX2_fifoTextStart); + gGfxSPTask->task.t.ucode_data_size = ((u8 *) gspF3DEX2_fifoDataEnd - (u8 *) gspF3DEX2_fifoDataStart); #elif F3DEX_GBI gGfxSPTask->task.t.ucode = gspF3DEX_fifoTextStart; gGfxSPTask->task.t.ucode_data = gspF3DEX_fifoDataStart; + gGfxSPTask->task.t.ucode_size = ((u8 *) gspF3DEX_fifoTextEnd - (u8 *) gspF3DEX_fifoTextStart); + gGfxSPTask->task.t.ucode_data_size = ((u8 *) gspF3DEX_fifoDataEnd - (u8 *) gspF3DEX_fifoDataStart); #elif SUPER3D_GBI - gGfxSPTask->task.t.ucode = gspSuper3D_fifoTextStart; - gGfxSPTask->task.t.ucode_data = gspSuper3D_fifoDataStart; + gGfxSPTask->task.t.ucode = gspSuper3DTextStart; + gGfxSPTask->task.t.ucode_data = gspSuper3DDataStart; + gGfxSPTask->task.t.ucode_size = ((u8 *) gspSuper3DTextEnd - (u8 *) gspSuper3DTextStart); + gGfxSPTask->task.t.ucode_data_size = ((u8 *) gspSuper3DDataEnd - (u8 *) gspSuper3DDataStart); #else gGfxSPTask->task.t.ucode = gspFast3D_fifoTextStart; gGfxSPTask->task.t.ucode_data = gspFast3D_fifoDataStart; + gGfxSPTask->task.t.ucode_size = ((u8 *) gspFast3D_fifoTextEnd - (u8 *) gspFast3D_fifoTextStart); + gGfxSPTask->task.t.ucode_data_size = ((u8 *) gspFast3D_fifoDataEnd - (u8 *) gspFast3D_fifoDataStart); #endif - gGfxSPTask->task.t.ucode_size = SP_UCODE_SIZE; // (this size is ignored) - gGfxSPTask->task.t.ucode_data_size = SP_UCODE_DATA_SIZE; gGfxSPTask->task.t.dram_stack = (u64 *) gGfxSPTaskStack; gGfxSPTask->task.t.dram_stack_size = SP_DRAM_STACK_SIZE8; gGfxSPTask->task.t.output_buff = gGfxSPTaskOutputBuffer; diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 8ab229a8e..050760215 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -164,153 +164,221 @@ ALIGNED16 struct GraphNodeObject *gCurGraphNodeObject = NULL; ALIGNED16 struct GraphNodeHeldObject *gCurGraphNodeHeldObject = NULL; u16 gAreaUpdateCounter = 0; -#if defined(OBJECTS_REJ) && defined(F3DZEX_GBI_2) -// u8 ucodeTestSwitch = 1; -void reset_clipping(void) { +#ifdef F3DEX_GBI_2 +LookAt lookAt; +#endif + +#if SILHOUETTE +// AA_EN Enable anti aliasing (not actually used for AA in this case). +// IM_RD Enable reading coverage value. +// CLR_ON_CVG Don't change the color unless coverage overflows. This helps prevent triangle overlap. +// CVG_DST_WRAP Wrap the coverage value on overflow. +// CVG_X_ALPHA Coverage and alpha will be multiplied and both will be the same. This makes texture alpha work (eg. Wing Cap wings). +// FORCE_BL Force Blending. +#define SIL_CVG_THRESHOLD 0x3F // 32..255, 63 seems to give best results +#define SCHWA (AA_EN | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | CVG_X_ALPHA | FORCE_BL) +static const Gfx dl_silhouette_begin[] = { + gsDPPipeSync(), + // Set the render mode for the silhouette so that it gets its color and alpha from the fog register. + gsDPSetRenderMode((SCHWA | GBL_c1(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1MA)), + (SCHWA | GBL_c2(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1MA))), + // Set the silhouette's color & alpha. + gsDPSetFogColor(0, 0, 0, SILHOUETTE), + // Hacky way to prevent triangle overlap. 32..255. 63 seems to give best results. + gsDPSetEnvColor(0, 0, 0, 0x3F), + gsSPEndDisplayList(), +}; + +static const Gfx dl_silhouette_end[] = { + gsDPPipeSync(), + gsDPSetFogColor( 0, 0, 0, 255), // Reset fog color & alpha + gsDPSetEnvColor(255, 255, 255, 255), // Reset env color & alpha + gsSPEndDisplayList(), +}; +#undef SCHWA +#endif + +struct RenderPhase { + u8 startLayer; + u8 endLayer; +#ifdef OBJECTS_REJ + u8 headsIndex : 1; +#endif +}; + +// startLayer endLayer headsIndex +static struct RenderPhase sRenderPhases[] = { +#ifdef OBJECTS_REJ + #if SILHOUETTE + // Silhouette, .rej + /* RENDER_PHASE_ZEX_BEFORE_SILHOUETTE */ { LAYER_FIRST, LAYER_LAST_BEFORE_SILHOUETTE, LIST_HEADS_ZEX }, + /* RENDER_PHASE_REJ_ZB */ { LAYER_ZB_FIRST, LAYER_LAST_BEFORE_SILHOUETTE, LIST_HEADS_REJ }, + /* RENDER_PHASE_REJ_SILHOUETTE */ { LAYER_SILHOUETTE_FIRST, LAYER_SILHOUETTE_LAST, LIST_HEADS_REJ }, + /* RENDER_PHASE_REJ_NON_SILHOUETTE */ { LAYER_SILHOUETTE_FIRST, LAYER_SILHOUETTE_LAST, LIST_HEADS_REJ }, + /* RENDER_PHASE_REJ_OCCLUDE_SILHOUETTE */ { LAYER_OCCLUDE_SILHOUETTE_FIRST, LAYER_OCCLUDE_SILHOUETTE_LAST, LIST_HEADS_REJ }, + /* RENDER_PHASE_ZEX_AFTER_SILHOUETTE */ { LAYER_OCCLUDE_SILHOUETTE_FIRST, LAYER_LAST, LIST_HEADS_ZEX }, + /* RENDER_PHASE_REJ_NON_ZB */ { LAYER_NON_ZB_FIRST, LAYER_LAST, LIST_HEADS_REJ }, + #else + // No silhouette, .rej + /* RENDER_PHASE_ZEX_BG */ { LAYER_FIRST, LAYER_FIRST, LIST_HEADS_ZEX }, + /* RENDER_PHASE_REJ_ZB */ { LAYER_ZB_FIRST, LAYER_ZB_LAST, LIST_HEADS_REJ }, + /* RENDER_PHASE_ZEX_ALL */ { LAYER_ZB_FIRST, LAYER_LAST, LIST_HEADS_ZEX }, + /* RENDER_PHASE_REJ_NON_ZB */ { LAYER_NON_ZB_FIRST, LAYER_LAST, LIST_HEADS_REJ }, + #endif +#else + #if SILHOUETTE + // Silhouette, no .rej + /* RENDER_PHASE_ZEX_BEFORE_SILHOUETTE */ { LAYER_FIRST, LAYER_LAST_BEFORE_SILHOUETTE }, + /* RENDER_PHASE_ZEX_SILHOUETTE */ { LAYER_SILHOUETTE_FIRST, LAYER_SILHOUETTE_LAST }, + /* RENDER_PHASE_ZEX_NON_SILHOUETTE */ { LAYER_SILHOUETTE_FIRST, LAYER_SILHOUETTE_LAST }, + /* RENDER_PHASE_ZEX_OCCLUDE_SILHOUETTE */ { LAYER_OCCLUDE_SILHOUETTE_FIRST, LAYER_OCCLUDE_SILHOUETTE_LAST }, + /* RENDER_PHASE_ZEX_AFTER_SILHOUETTE */ { LAYER_OCCLUDE_SILHOUETTE_FIRST, LAYER_LAST }, + #else + // No silhouette, no .rej + /* RENDER_PHASE_ZEX_ALL */ { LAYER_FIRST, LAYER_LAST }, + #endif +#endif +}; + +#ifdef OBJECTS_REJ +static void reset_clipping(void) { if (gMarioState->action == ACT_CREDITS_CUTSCENE) { make_viewport_clip_rect(&sEndCutsceneVp); } else { gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, gBorderHeight, SCREEN_WIDTH, (SCREEN_HEIGHT - gBorderHeight)); } } -#endif -#ifdef F3DEX_GBI_2 -LookAt lookAt; +static void switch_ucode(s32 headsIndex) { + if (headsIndex == LIST_HEADS_REJ) { + if (gIsConsole) { + gSPLoadUcodeL(gDisplayListHead++, gspF3DLX2_Rej_fifo); + } else { + gSPLoadUcodeL(gDisplayListHead++, gspF3DEX2_Rej_fifo); + } + init_rcp(KEEP_ZBUFFER); + gSPClipRatio(gDisplayListHead++, FRUSTRATIO_2); + } else { // LIST_HEADS_ZEX + gSPLoadUcodeL(gDisplayListHead++, gspF3DZEX2_PosLight_fifo); + init_rcp(KEEP_ZBUFFER); + gSPClipRatio(gDisplayListHead++, FRUSTRATIO_1); + } +} #endif -#if SILHOUETTE -#define SIL_CVG_THRESHOLD 0x3F // 32..255, 63 seems to give best results -#define SCHWA (AA_EN | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | CVG_X_ALPHA | FORCE_BL) -const Gfx dl_silhouette_begin[] = { - gsDPPipeSync(), - gsDPSetRenderMode((SCHWA | GBL_c1(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1MA)), - (SCHWA | GBL_c2(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1MA))), - gsDPSetFogColor(0, 0, 0, SILHOUETTE ), /* Silhouette color & alpha */ - gsDPSetEnvColor(0, 0, 0, SIL_CVG_THRESHOLD), /* Silhouette env transparency */ - gsSPEndDisplayList(), -}; -const Gfx dl_silhouette_end[] = { - gsDPPipeSync(), - gsDPSetFogColor( 0, 0, 0, 255), /* Reset fog color & alpha */ - gsDPSetEnvColor(255, 255, 255, 255), /* Reset env color & alpha */ - gsSPEndDisplayList(), -}; -#endif - -#ifdef OBJECTS_REJ -/** - * These replacement functions are used when OBJECTS_REJ is enabled. - */ - /** * Process a master list node. This has been modified, so now it runs twice, for each microcode. - It iterates through the first 5 layers of if the first index using F3DLX2.Rej, then it switches - to F3DZEX and iterates through all layers, then switches back to F3DLX2.Rej and finishes the last - 3. It does this, because layers 5-7 are non zbuffered, and just doing 0-7 of ZEX, then 0-7 of REJ - would make the ZEX 0-4 render on top of Rej's 5-7. + * It iterates through the first 5 layers of if the first index using F3DLX2.Rej, then it switches + * to F3DZEX and iterates through all layers, then switches back to F3DLX2.Rej and finishes the last + * 3. It does this, because layers 5-7 are non zbuffered, and just doing 0-7 of ZEX, then 0-7 of REJ + * would make the ZEX 0-4 render on top of Rej's 5-7. */ void geo_process_master_list_sub(struct GraphNodeMasterList *node) { + struct RenderPhase *renderPhase; struct DisplayListNode *currList; s32 currLayer = LAYER_FIRST; s32 startLayer = LAYER_FIRST; s32 endLayer = LAYER_LAST; +#ifdef OBJECTS_REJ s32 headsIndex = LIST_HEADS_ZEX; - s32 renderPhase = RENDER_PHASE_FIRST; +#endif + s32 currPhase = RENDER_PHASE_FIRST; s32 enableZBuffer = (node->node.flags & GRAPH_RENDER_Z_BUFFER) != 0; struct RenderModeContainer *mode1List = &renderModeTable_1Cycle[enableZBuffer]; struct RenderModeContainer *mode2List = &renderModeTable_2Cycle[enableZBuffer]; +#ifdef F3DEX_GBI_2 Mtx lMtx; -#ifdef FIX_REFLECT_MTX + #ifdef FIX_REFLECT_MTX guLookAtReflect(&lMtx, &lookAt, 0.0f, 0.0f, 0.0f, /* eye */ 0.0f, 0.0f, 1.0f, /* at */ 0.0f, -1.0f, 0.0f /* up */); -#else + #else + // @bug This is where the LookAt values should be calculated but aren't. + // As a result, environment mapping is broken on Fast3DEX2 without the + // changes below. guLookAtReflect(&lMtx, &lookAt, 0.0f, 0.0f, 0.0f, /* eye */ 0.0f, 0.0f, 1.0f, /* at */ 1.0f, 0.0f, 0.0f /* up */); -#endif + #endif +#endif // F3DEX_GBI_2 - for (renderPhase = 0; renderPhase < RENDER_PHASE_END; renderPhase++) { - switch (renderPhase) { -#if SILHOUETTE - case RENDER_PHASE_ZEX_BG: headsIndex = LIST_HEADS_ZEX; startLayer = LAYER_FIRST; endLayer = LAYER_FIRST; break; - case RENDER_PHASE_REJ_ZB: headsIndex = LIST_HEADS_REJ; startLayer = LAYER_FIRST; endLayer = LAYER_LAST_BEFORE_SILHOUETTE; break; - case RENDER_PHASE_ZEX_BEFORE_SILHOUETTE: headsIndex = LIST_HEADS_ZEX; startLayer = LAYER_ZB_FIRST; endLayer = LAYER_LAST_BEFORE_SILHOUETTE; break; - case RENDER_PHASE_REJ_SILHOUETTE: headsIndex = LIST_HEADS_REJ; startLayer = LAYER_SILHOUETTE_FIRST; endLayer = LAYER_SILHOUETTE_LAST; break; - case RENDER_PHASE_REJ_NON_SILHOUETTE: headsIndex = LIST_HEADS_REJ; startLayer = LAYER_SILHOUETTE_FIRST; endLayer = LAYER_SILHOUETTE_LAST; break; - case RENDER_PHASE_REJ_OCCLUDE_SILHOUETTE: headsIndex = LIST_HEADS_REJ; startLayer = LAYER_OCCLUDE_SILHOUETTE_FIRST; endLayer = LAYER_OCCLUDE_SILHOUETTE_LAST; break; - case RENDER_PHASE_ZEX_AFTER_SILHOUETTE: headsIndex = LIST_HEADS_ZEX; startLayer = LAYER_OCCLUDE_SILHOUETTE_FIRST; endLayer = LAYER_LAST; break; - case RENDER_PHASE_REJ_NON_ZB: headsIndex = LIST_HEADS_REJ; startLayer = LAYER_NON_ZB_FIRST; endLayer = LAYER_LAST; break; -#else - case RENDER_PHASE_ZEX_BG: headsIndex = LIST_HEADS_ZEX; startLayer = LAYER_FIRST; endLayer = LAYER_FIRST; break; - case RENDER_PHASE_REJ_ZB: headsIndex = LIST_HEADS_REJ; startLayer = LAYER_FIRST; endLayer = LAYER_ZB_LAST; break; - case RENDER_PHASE_ZEX_ALL: headsIndex = LIST_HEADS_ZEX; startLayer = LAYER_ZB_FIRST; endLayer = LAYER_LAST; break; - case RENDER_PHASE_REJ_NON_ZB: headsIndex = LIST_HEADS_REJ; startLayer = LAYER_NON_ZB_FIRST; endLayer = LAYER_LAST; break; -#endif - } - - // Load rejection on pass 2. ZEX is loaded afterwards. - if (headsIndex == LIST_HEADS_REJ) { - if (gIsConsole) { - gSPLoadUcodeL(gDisplayListHead++, gspF3DLX2_Rej_fifo); - } else { - gSPLoadUcodeL(gDisplayListHead++, gspF3DEX2_Rej_fifo); - } - init_rcp(KEEP_ZBUFFER); - gSPClipRatio(gDisplayListHead++, FRUSTRATIO_2); - } else { - gSPLoadUcodeL(gDisplayListHead++, gspF3DZEX2_PosLight_fifo); - init_rcp(KEEP_ZBUFFER); - gSPClipRatio(gDisplayListHead++, FRUSTRATIO_1); - } + for (currPhase = RENDER_PHASE_FIRST; currPhase < RENDER_PHASE_END; currPhase++) { + renderPhase = &sRenderPhases[currPhase]; + startLayer = renderPhase->startLayer; + endLayer = renderPhase->endLayer; +#ifdef OBJECTS_REJ + headsIndex = renderPhase->headsIndex; + switch_ucode(headsIndex); gSPLookAt(gDisplayListHead++, &lookAt); reset_clipping(); - +#endif if (enableZBuffer) { + // Enable z buffer. gDPPipeSync(gDisplayListHead++); gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER); } + // Iterate through the layers on the current render phase. for (currLayer = startLayer; currLayer <= endLayer; currLayer++) { + // Set 'currList' to the first DisplayListNode on the current layer. +#ifdef OBJECTS_REJ currList = node->listHeads[headsIndex][currLayer]; - -#if defined(DISABLE_AA) || !defined(SILHOUETTE) - gDPSetRenderMode(gDisplayListHead++, mode1List->modes[currLayer], mode2List->modes[currLayer]); +#else + currList = node->listHeads[currLayer]; #endif +#if defined(DISABLE_AA) || !SILHOUETTE + // Set the render mode for the current layer. + gDPSetRenderMode(gDisplayListHead++, mode1List->modes[currLayer], + mode2List->modes[currLayer]); +#else + if (currPhase == RENDER_PHASE_NON_SILHOUETTE) { + // To properly cover the silhouette, disable AA. + // The silhouette model does not have AA due to the hack used to prevent triangle overlap. + gDPSetRenderMode(gDisplayListHead++, (mode1List->modes[currLayer] & ~IM_RD), + (mode2List->modes[currLayer] & ~IM_RD)); + } else { + // Set the render mode for the current dl. + gDPSetRenderMode(gDisplayListHead++, mode1List->modes[currLayer], + mode2List->modes[currLayer]); + } +#endif + // Iterate through all the displaylists on the current layer. while (currList != NULL) { -#if SILHOUETTE - if (renderPhase == RENDER_PHASE_REJ_SILHOUETTE) { - gSPDisplayList(gDisplayListHead++, dl_silhouette_begin); - } else if (renderPhase == RENDER_PHASE_REJ_NON_SILHOUETTE) { - gSPDisplayList(gDisplayListHead++, dl_silhouette_end); -#ifndef DISABLE_AA - // Use normal mode list, no AA - gDPSetRenderMode(gDisplayListHead++, (mode1List->modes[currLayer] & ~IM_RD), - (mode2List->modes[currLayer] & ~IM_RD)); - } else { - gDPSetRenderMode(gDisplayListHead++, mode1List->modes[currLayer], mode2List->modes[currLayer]); -#endif - } -#endif + // Add the display list's transformation to the master list. gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transform), - G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); + (G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH)); +#if SILHOUETTE + if (currPhase == RENDER_PHASE_SILHOUETTE) { + // Add the current display list to the master list, with silhouette F3D. + gSPDisplayList(gDisplayListHead++, dl_silhouette_begin); + gSPDisplayList(gDisplayListHead++, currList->displayList); + gSPDisplayList(gDisplayListHead++, dl_silhouette_end); + } else { + // Add the current display list to the master list. + gSPDisplayList(gDisplayListHead++, currList->displayList); + } +#else + // Add the current display list to the master list. gSPDisplayList(gDisplayListHead++, currList->displayList); +#endif + // Move to the next DisplayListNode. currList = currList->next; } } } if (enableZBuffer) { + // Disable z buffer. gDPPipeSync(gDisplayListHead++); gSPClearGeometryMode(gDisplayListHead++, G_ZBUFFER); } - -#ifdef VISUAL_DEBUG +#ifdef F3DZEX_GBI_2 + #ifdef VISUAL_DEBUG if (hitboxView) render_debug_boxes(DEBUG_UCODE_REJ); -#endif - + #endif + #ifdef OBJECTS_REJ gSPLoadUcodeL(gDisplayListHead++, gspF3DZEX2_PosLight_fifo); init_rcp(KEEP_ZBUFFER); gSPClipRatio(gDisplayListHead++, FRUSTRATIO_1); reset_clipping(); - + #endif +#endif #ifdef VISUAL_DEBUG if ( hitboxView) render_debug_boxes(DEBUG_UCODE_DEFAULT | DEBUG_BOX_CLEAR); if (surfaceView) visual_surface_loop(); @@ -323,18 +391,24 @@ void geo_process_master_list_sub(struct GraphNodeMasterList *node) { * render modes of layers. */ void geo_append_display_list(void *displayList, s32 layer) { +#ifdef OBJECTS_REJ s32 index = LIST_HEADS_ZEX; - +#endif +#ifdef F3DEX_GBI_2 gSPLookAt(gDisplayListHead++, &lookAt); - +#endif +#if defined(OBJECTS_REJ) || SILHOUETTE if (gCurGraphNodeObject != NULL) { + #ifdef OBJECTS_REJ if (gCurGraphNodeObject->ucode == GRAPH_NODE_UCODE_REJ) { index = LIST_HEADS_REJ; } - -#if SILHOUETTE + #endif + #if SILHOUETTE if (gCurGraphNodeObject->node.flags & GRAPH_RENDER_SILHOUETTE) { + #ifdef OBJECTS_REJ index = LIST_HEADS_REJ; + #endif switch (layer) { case LAYER_OPAQUE: layer = LAYER_SILHOUETTE_OPAQUE; break; case LAYER_ALPHA: layer = LAYER_SILHOUETTE_ALPHA; break; @@ -346,160 +420,34 @@ void geo_append_display_list(void *displayList, s32 layer) { case LAYER_ALPHA: layer = LAYER_OCCLUDE_SILHOUETTE_ALPHA; break; } } -#endif + #endif // SILHOUETTE } - +#endif // F3DZEX_GBI_2 || SILHOUETTE if (gCurGraphNodeMasterList != 0) { - struct DisplayListNode *listNode = alloc_only_pool_alloc(gDisplayListHeap, sizeof(struct DisplayListNode)); + struct DisplayListNode *listNode = + alloc_only_pool_alloc(gDisplayListHeap, sizeof(struct DisplayListNode)); listNode->transform = gMatStackFixed[gMatStackIndex]; listNode->displayList = displayList; listNode->next = 0; +#ifdef OBJECTS_REJ if (gCurGraphNodeMasterList->listHeads[index][layer] == 0) { gCurGraphNodeMasterList->listHeads[index][layer] = listNode; } else { gCurGraphNodeMasterList->listTails[index][layer]->next = listNode; } gCurGraphNodeMasterList->listTails[index][layer] = listNode; - } -} - -#else // not OBJECTS_REJ - -/** - * Process a master list node. - */ -void geo_process_master_list_sub(struct GraphNodeMasterList *node) { - struct DisplayListNode *currList; - s32 currLayer = LAYER_FIRST; - s32 startLayer = LAYER_FIRST; - s32 endLayer = LAYER_LAST; - s32 renderPhase = RENDER_PHASE_FIRST; - s32 enableZBuffer = (node->node.flags & GRAPH_RENDER_Z_BUFFER) != 0; - struct RenderModeContainer *mode1List = &renderModeTable_1Cycle[enableZBuffer]; - struct RenderModeContainer *mode2List = &renderModeTable_2Cycle[enableZBuffer]; - - // @bug This is where the LookAt values should be calculated but aren't. - // As a result, environment mapping is broken on Fast3DEX2 without the - // changes below. -#ifdef F3DEX_GBI_2 - Mtx lMtx; -#ifdef FIX_REFLECT_MTX - guLookAtReflect(&lMtx, &lookAt, 0.0f, 0.0f, 0.0f, /* eye */ 0.0f, 0.0f, 1.0f, /* at */ 0.0f, -1.0f, 0.0f /* up */); #else - guLookAtReflect(&lMtx, &lookAt, 0.0f, 0.0f, 0.0f, /* eye */ 0.0f, 0.0f, 1.0f, /* at */ 1.0f, 0.0f, 0.0f /* up */); -#endif -#endif - -#if SILHOUETTE - for (renderPhase = 0; renderPhase < RENDER_PHASE_END; renderPhase++) { - switch (renderPhase) { - case RENDER_PHASE_ZEX_BEFORE_SILHOUETTE: startLayer = LAYER_FIRST; endLayer = LAYER_LAST_BEFORE_SILHOUETTE; break; - case RENDER_PHASE_ZEX_SILHOUETTE: startLayer = LAYER_SILHOUETTE_FIRST; endLayer = LAYER_SILHOUETTE_LAST; break; - case RENDER_PHASE_ZEX_NON_SILHOUETTE: startLayer = LAYER_SILHOUETTE_FIRST; endLayer = LAYER_SILHOUETTE_LAST; break; - case RENDER_PHASE_ZEX_OCCLUDE_SILHOUETTE: startLayer = LAYER_OCCLUDE_SILHOUETTE_FIRST; endLayer = LAYER_OCCLUDE_SILHOUETTE_LAST; break; - case RENDER_PHASE_ZEX_AFTER_SILHOUETTE: startLayer = LAYER_OCCLUDE_SILHOUETTE_FIRST; endLayer = LAYER_LAST; break; - } -#endif - - if (enableZBuffer) { - gDPPipeSync(gDisplayListHead++); - gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER); - } - - for (currLayer = startLayer; currLayer <= endLayer; currLayer++) { - currList = node->listHeads[currLayer]; -#if defined(DISABLE_AA) || !defined(SILHOUETTE) - gDPSetRenderMode(gDisplayListHead++, mode1List->modes[currLayer], mode2List->modes[currLayer]); -#endif - - while (currList != NULL) { -#if SILHOUETTE - if (renderPhase == RENDER_PHASE_ZEX_SILHOUETTE) { - gSPDisplayList(gDisplayListHead++, dl_silhouette_begin); - } else if (renderPhase == RENDER_PHASE_ZEX_NON_SILHOUETTE) { - gSPDisplayList(gDisplayListHead++, dl_silhouette_end); -#ifndef DISABLE_AA - // Use normal mode list, no AA - gDPSetRenderMode(gDisplayListHead++, (mode1List->modes[currLayer] & ~IM_RD), - (mode2List->modes[currLayer] & ~IM_RD)); - } else { - gDPSetRenderMode(gDisplayListHead++, mode1List->modes[currLayer], mode2List->modes[currLayer]); -#endif - } -#endif - gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transform), - G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); - gSPDisplayList(gDisplayListHead++, currList->displayList); - currList = currList->next; - } - } -#if SILHOUETTE // End renderPhase for-loop - } -#endif - - if (enableZBuffer) { - gDPPipeSync(gDisplayListHead++); - gSPClearGeometryMode(gDisplayListHead++, G_ZBUFFER); - } - -#ifdef VISUAL_DEBUG - if ( hitboxView) render_debug_boxes(DEBUG_UCODE_DEFAULT | DEBUG_BOX_CLEAR); - if (surfaceView) visual_surface_loop(); -#endif -} - -/** - * Appends the display list to one of the master lists based on the layer - * parameter. Look at the RenderModeContainer struct to see the corresponding - * render modes of layers. - */ -void geo_append_display_list(void *displayList, s32 layer) { -#ifdef F3DEX_GBI_2 - gSPLookAt(gDisplayListHead++, &lookAt); -#endif - -#if (SILHOUETTE > 0) - if (gCurGraphNodeObject != NULL) { - if (gCurGraphNodeObject->node.flags & GRAPH_RENDER_SILHOUETTE) { - switch (layer) { - case LAYER_OPAQUE: layer = LAYER_SILHOUETTE_OPAQUE; break; - case LAYER_ALPHA: layer = LAYER_SILHOUETTE_ALPHA; break; - } - } - if (gCurGraphNodeObject->node.flags & GRAPH_RENDER_OCCLUDE_SILHOUETTE) { - switch (layer) { - case LAYER_OPAQUE: layer = LAYER_OCCLUDE_SILHOUETTE_OPAQUE; break; - case LAYER_ALPHA: layer = LAYER_OCCLUDE_SILHOUETTE_ALPHA; break; - } - } - } -#endif - - if (gCurGraphNodeMasterList != 0) { - struct DisplayListNode *listNode = alloc_only_pool_alloc(gDisplayListHeap, sizeof(struct DisplayListNode)); - - listNode->transform = gMatStackFixed[gMatStackIndex]; - listNode->displayList = displayList; - listNode->next = 0; if (gCurGraphNodeMasterList->listHeads[layer] == 0) { gCurGraphNodeMasterList->listHeads[layer] = listNode; } else { gCurGraphNodeMasterList->listTails[layer]->next = listNode; } gCurGraphNodeMasterList->listTails[layer] = listNode; +#endif } } -#endif - -#if SILHOUETTE -#undef SIL_CVG_THRESHOLD -#undef SCHWA -#undef SET_SILHOUETTE_F3D -#undef CLEAR_SILHOUETTE_F3D -#endif - static void inc_mat_stack() { Mtx *mtx = alloc_display_list(sizeof(*mtx)); gMatStackIndex++; diff --git a/src/game/rendering_graph_node.h b/src/game/rendering_graph_node.h index f12b9e848..21e0516ec 100644 --- a/src/game/rendering_graph_node.h +++ b/src/game/rendering_graph_node.h @@ -28,56 +28,65 @@ enum AnimType { ANIM_TYPE_ROTATION }; +#define IS_LAYER_ZB( layer) (((layer) >= LAYER_ZB_FIRST ) || ((layer) <= LAYER_ZB_LAST)) +#define IS_LAYER_NON_ZB(layer) (((layer) >= LAYER_NON_ZB_FIRST) || ((layer) <= LAYER_LAST )) + #ifdef OBJECTS_REJ enum HeadsList { LIST_HEADS_ZEX, LIST_HEADS_REJ, }; -#endif -#define IS_LAYER_ZB( layer) (((layer) >= LAYER_ZB_FIRST ) || ((layer) <= LAYER_ZB_LAST)) -#define IS_LAYER_NON_ZB(layer) (((layer) >= LAYER_NON_ZB_FIRST) || ((layer) <= LAYER_LAST )) + #if SILHOUETTE + // Silhouette, .rej + enum RenderPhases { + RENDER_PHASE_ZEX_BEFORE_SILHOUETTE, + RENDER_PHASE_REJ_ZB, + RENDER_PHASE_REJ_SILHOUETTE, + RENDER_PHASE_REJ_NON_SILHOUETTE, + RENDER_PHASE_REJ_OCCLUDE_SILHOUETTE, + RENDER_PHASE_ZEX_AFTER_SILHOUETTE, + RENDER_PHASE_REJ_NON_ZB, + RENDER_PHASE_END, + }; + #define RENDER_PHASE_SILHOUETTE RENDER_PHASE_REJ_SILHOUETTE + #define RENDER_PHASE_NON_SILHOUETTE RENDER_PHASE_REJ_NON_SILHOUETTE + #else + // No silhouette, .rej + enum RenderPhases { + RENDER_PHASE_ZEX_BG, + RENDER_PHASE_REJ_ZB, + RENDER_PHASE_ZEX_ALL, + RENDER_PHASE_REJ_NON_ZB, + RENDER_PHASE_END, + }; + #endif +#else + #if SILHOUETTE + // Silhouette, no .rej + enum RenderPhases { + RENDER_PHASE_ZEX_BEFORE_SILHOUETTE, + RENDER_PHASE_ZEX_SILHOUETTE, + RENDER_PHASE_ZEX_NON_SILHOUETTE, + RENDER_PHASE_ZEX_OCCLUDE_SILHOUETTE, + RENDER_PHASE_ZEX_AFTER_SILHOUETTE, + RENDER_PHASE_END, + }; + #define RENDER_PHASE_SILHOUETTE RENDER_PHASE_ZEX_SILHOUETTE + #define RENDER_PHASE_NON_SILHOUETTE RENDER_PHASE_ZEX_NON_SILHOUETTE + #else + // No silhouette, no .rej + enum RenderPhases { + RENDER_PHASE_ZEX_ALL, + RENDER_PHASE_END, + }; + #endif +#endif #if SILHOUETTE #define IS_LAYER_SILHOUETTE(layer) (((layer) >= LAYER_SILHOUETTE_FIRST) || ((layer) <= LAYER_SILHOUETTE_LAST)) -#ifdef OBJECTS_REJ -enum RenderPhase { // Silhouette, .rej - RENDER_PHASE_ZEX_BG, - RENDER_PHASE_REJ_ZB, - RENDER_PHASE_ZEX_BEFORE_SILHOUETTE, - RENDER_PHASE_REJ_SILHOUETTE, - RENDER_PHASE_REJ_NON_SILHOUETTE, - RENDER_PHASE_REJ_OCCLUDE_SILHOUETTE, - RENDER_PHASE_ZEX_AFTER_SILHOUETTE, - RENDER_PHASE_REJ_NON_ZB, - RENDER_PHASE_END, -}; -#else -enum RenderPhase { // Silhouette, no .rej - RENDER_PHASE_ZEX_BEFORE_SILHOUETTE, - RENDER_PHASE_ZEX_SILHOUETTE, - RENDER_PHASE_ZEX_NON_SILHOUETTE, - RENDER_PHASE_ZEX_OCCLUDE_SILHOUETTE, - RENDER_PHASE_ZEX_AFTER_SILHOUETTE, - RENDER_PHASE_END, -}; -#endif -#else -#ifdef OBJECTS_REJ -enum RenderPhase { // No silhouette, .rej - RENDER_PHASE_ZEX_BG, - RENDER_PHASE_REJ_ZB, - RENDER_PHASE_ZEX_ALL, - RENDER_PHASE_REJ_NON_ZB, - RENDER_PHASE_END, -}; -#else -enum RenderPhase { // No silhouette, no .rej - RENDER_PHASE_ZEX_ALL, - RENDER_PHASE_END, -}; -#endif #endif + #define RENDER_PHASE_FIRST 0 void geo_process_node_and_siblings(struct GraphNode *firstNode);