mirror of
https://github.com/perfect-dark-pc-port/perfect_dark.git
synced 2026-10-24 00:02:43 +02:00
258 lines
7.2 KiB
C
258 lines
7.2 KiB
C
#include <ultra64.h>
|
|
#include "constants.h"
|
|
#include "lib/sched.h"
|
|
#include "game/player.h"
|
|
#include "game/zbuf.h"
|
|
#include "game/mplayer/mplayer.h"
|
|
#include "game/options.h"
|
|
#include "bss.h"
|
|
#include "lib/vi.h"
|
|
#include "lib/memp.h"
|
|
#include "data.h"
|
|
#include "types.h"
|
|
|
|
u32 g_ZbufWidth;
|
|
u32 g_ZbufHeight;
|
|
u16 g_ArtifactsCfb0[0x180];
|
|
u16 g_ArtifactsCfb1[0x180];
|
|
u16 g_ArtifactsCfb2[0x180];
|
|
|
|
u16 *g_ZbufPtr1 = NULL;
|
|
u16 *g_ZbufPtr2 = NULL;
|
|
|
|
void *zbufGetAllocation(void)
|
|
{
|
|
return g_ZbufPtr1;
|
|
}
|
|
|
|
void zbufReset(s32 stagenum)
|
|
{
|
|
g_ZbufPtr1 = NULL;
|
|
g_ZbufPtr2 = NULL;
|
|
|
|
if (stagenum != STAGE_TITLE) {
|
|
zbufAllocate();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* In 4MB 2-player, the viewports are displayed with a vertical split and are
|
|
* only half a screen height (the top 25% and bottom 25% of the screen are
|
|
* black), so a half-height z-buffer is allocated.
|
|
*
|
|
* In 8MB, the full hi-res buffer is allocated. This makes sense for solo
|
|
* missions because the player can switch to hi-res mid game. For normal
|
|
* multiplayer this is wasteful but there's plenty of memory. For coop and anti
|
|
* this is also wasteful, and memory is tight. They could have saved 137.5 KB.
|
|
*
|
|
* The allocation sizes need to enforce a minimum because the allocation is also
|
|
* used by lighting initialisation code.
|
|
*/
|
|
void zbufAllocate(void)
|
|
{
|
|
if (IS4MB()) {
|
|
g_ZbufWidth = MAX(320, FBALLOC_WIDTH_LO);
|
|
|
|
if (g_Vars.normmplayerisrunning && PLAYERCOUNT() >= 2) {
|
|
g_ZbufHeight = MAX(220, FBALLOC_HEIGHT_LO) / 2;
|
|
} else {
|
|
g_ZbufHeight = MAX(220, FBALLOC_HEIGHT_LO);
|
|
}
|
|
} else {
|
|
g_ZbufWidth = MAX(640, FBALLOC_WIDTH_HI);
|
|
|
|
if (g_Vars.normmplayerisrunning && PLAYERCOUNT() >= 2) {
|
|
g_ZbufHeight = MAX(220, FBALLOC_HEIGHT_HI);
|
|
} else {
|
|
g_ZbufHeight = MAX(220, FBALLOC_HEIGHT_HI);
|
|
}
|
|
}
|
|
|
|
g_ZbufPtr1 = mempAlloc(g_ZbufWidth * g_ZbufHeight * sizeof(u16) + 0x40, MEMPOOL_STAGE);
|
|
g_ZbufPtr1 = (void *) (((uintptr_t) g_ZbufPtr1 + 0x3f) & ~0x3f);
|
|
g_ZbufPtr2 = g_ZbufPtr1;
|
|
}
|
|
|
|
/**
|
|
* Note: There is only one z-buffer, so there is nothing to swap.
|
|
* Both of these pointers always have the same value.
|
|
*
|
|
* We assume this is a swap function due to the context in which it's called.
|
|
* Perhaps the developers implemented two buffers with swapping before realising
|
|
* they only needed one.
|
|
*/
|
|
void zbufSwap(void)
|
|
{
|
|
g_ZbufPtr2 = g_ZbufPtr1;
|
|
}
|
|
|
|
/**
|
|
* In 8MB multiplayer, players on the bottom half of the screen have their
|
|
* z-buffer shifted backwards by half a screen. This is safe because it's using
|
|
* a scissor on the viewport.
|
|
*
|
|
* This allows the z-buffer allocation to be half a screen instead of a full
|
|
* screen, however zbufAllocate allocates the full hi-res screen for 8MB,
|
|
* so this benefit is not realised. The shifting code is likely from GE.
|
|
*/
|
|
Gfx *zbufConfigureRdp(Gfx *gdl)
|
|
{
|
|
u32 subamount;
|
|
uintptr_t addr;
|
|
|
|
if (g_Vars.normmplayerisrunning
|
|
&& (g_Vars.currentplayernum >= 2 || (PLAYERCOUNT() == 2 && g_Vars.currentplayernum == 1))) {
|
|
subamount = playerGetFbWidth() * playerGetFbHeight();
|
|
|
|
if (IS4MB() || optionsGetScreenSplit() == SCREENSPLIT_VERTICAL) {
|
|
subamount = 0;
|
|
}
|
|
} else {
|
|
subamount = 0;
|
|
}
|
|
|
|
addr = (uintptr_t) g_ZbufPtr2 - subamount;
|
|
addr &= ~0x3f;
|
|
|
|
gDPPipeSync(gdl++);
|
|
gDPSetDepthImage(gdl++, addr);
|
|
|
|
return gdl;
|
|
}
|
|
|
|
/**
|
|
* Clear the current player's portion of the z-buffer.
|
|
*/
|
|
Gfx *zbufClear(Gfx *gdl)
|
|
{
|
|
#ifdef PLATFORM_N64
|
|
s32 left;
|
|
s32 right;
|
|
|
|
gDPPipeSync(gdl++);
|
|
gDPSetRenderMode(gdl++, G_RM_NOOP, G_RM_NOOP2);
|
|
gDPSetColorImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, viGetWidth(), OS_PHYSICAL_TO_K0(g_ZbufPtr2));
|
|
gDPSetCycleType(gdl++, G_CYC_FILL);
|
|
gDPSetFillColor(gdl++, 0xfffcfffc);
|
|
gDPSetScissorFrac(gdl++, G_SC_NON_INTERLACE, 0, 0, playerGetFbWidth() * 4.0f, playerGetFbHeight() * 4.0f);
|
|
|
|
if (PLAYERCOUNT() <= 2) {
|
|
left = 0;
|
|
right = playerGetFbWidth() - 1;
|
|
} else if (g_Vars.currentplayernum == 0 || g_Vars.currentplayernum == 2) {
|
|
left = 0;
|
|
right = playerGetFbWidth() / 2 - 1;
|
|
} else {
|
|
left = playerGetFbWidth() / 2;
|
|
right = playerGetFbWidth() - 1;
|
|
}
|
|
|
|
gDPFillRectangle(gdl++, left, 0, right, playerGetFbHeight() - 1);
|
|
gDPPipeSync(gdl++);
|
|
#else
|
|
gDPClearDepthEXT(gdl++);
|
|
#endif
|
|
|
|
return gdl;
|
|
}
|
|
|
|
u16 *zbufGetArtifactsCfb(s32 index)
|
|
{
|
|
u16 *addr;
|
|
|
|
if (index == 0) {
|
|
addr = g_ArtifactsCfb0;
|
|
}
|
|
|
|
if (index == 1) {
|
|
addr = g_ArtifactsCfb1;
|
|
}
|
|
|
|
if (index == 2) {
|
|
addr = g_ArtifactsCfb2;
|
|
}
|
|
|
|
addr = (u16 *) (((uintptr_t) addr + 0x3f) & ~0x3f);
|
|
|
|
return addr;
|
|
}
|
|
|
|
Gfx *zbufDrawArtifactsOffscreen(Gfx *gdl)
|
|
{
|
|
struct artifact *artifacts = schedGetWriteArtifacts();
|
|
u32 stack;
|
|
u16 *sp4c = g_ZbufPtr1;
|
|
u32 s4 = 0;
|
|
u16 *sp44;
|
|
u16 *s2;
|
|
u16 *image;
|
|
s32 i;
|
|
|
|
viGetBackBuffer();
|
|
sp44 = zbufGetArtifactsCfb(g_SchedWriteArtifactsIndex);
|
|
g_SchedSpecialArtifactIndexes[g_SchedWriteArtifactsIndex] = 1;
|
|
|
|
gDPPipeSync(gdl++);
|
|
gDPSetColorImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, viGetBufWidth(), OS_PHYSICAL_TO_K0(sp44));
|
|
gDPSetScissor(gdl++, G_SC_NON_INTERLACE, 0, 0, SCREEN_320, SCREEN_240);
|
|
gDPSetCycleType(gdl++, G_CYC_COPY);
|
|
gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0x0000, 5, 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);
|
|
gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0x0080, 4, 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);
|
|
gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 160, 0x0000, G_TX_RENDERTILE, 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);
|
|
gDPSetTile(gdl++, G_IM_FMT_I, G_IM_SIZ_8b, 160, 0x0080, 1, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, 15);
|
|
gSPTexture(gdl++, 0xffff, 0xffff, 0, G_TX_RENDERTILE, G_ON);
|
|
gDPSetEnvColor(gdl++, 0xff, 0xff, 0xff, 0xff);
|
|
gDPSetPrimColor(gdl++, 0, 0, 0xff, 0xff, 0xff, 0xff);
|
|
gDPSetRenderMode(gdl++, G_RM_NOOP, G_RM_NOOP2);
|
|
gDPSetCombineMode(gdl++, G_CC_DECALRGBA, G_CC_DECALRGBA);
|
|
gDPSetTextureFilter(gdl++, G_TF_POINT);
|
|
gDPSetTexturePersp(gdl++, G_TP_NONE);
|
|
gDPSetColorDither(gdl++, G_CD_DISABLE);
|
|
gDPSetAlphaDither(gdl++, G_AD_DISABLE);
|
|
gDPSetTextureLOD(gdl++, G_TL_TILE);
|
|
gDPSetTextureDetail(gdl++, G_TD_CLAMP);
|
|
gDPSetTextureLUT(gdl++, G_TT_NONE);
|
|
gDPSetAlphaCompare(gdl++, G_AC_NONE);
|
|
gSPClearGeometryMode(gdl++, G_ZBUFFER);
|
|
gDPTileSync(gdl++);
|
|
|
|
for (i = 0; i < MAX_ARTIFACTS; i++) {
|
|
if (1);
|
|
|
|
if (artifacts[i].type != ARTIFACTTYPE_FREE) {
|
|
s2 = &sp44[s4];
|
|
image = &sp4c[artifacts[i].unk0c.u16_1 * viGetWidth()];
|
|
|
|
gDPPipeSync(gdl++);
|
|
gDPSetTextureImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_320, image);
|
|
gDPLoadSync(gdl++);
|
|
gDPLoadBlock(gdl++, 5, 0, 0, viGetWidth() - 1, 0);
|
|
gDPPipeSync(gdl++);
|
|
|
|
gSPTextureRectangle(gdl++,
|
|
s4 << 2, 0,
|
|
(s4 + 3) << 2, 0,
|
|
G_TX_RENDERTILE, (artifacts[i].unk0c.u16_2 * 32) + 16, 0x0010, 0x1000, 0);
|
|
|
|
artifacts[i].unk0c.u16p = s2;
|
|
s4++;
|
|
|
|
if (s2);
|
|
}
|
|
}
|
|
|
|
gDPPipeSync(gdl++);
|
|
gDPLoadSync(gdl++);
|
|
gDPTileSync(gdl++);
|
|
gDPSetColorImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, viGetBufWidth(), OS_PHYSICAL_TO_K0(viGetBackBuffer()));
|
|
gDPSetScissorFrac(gdl++, G_SC_NON_INTERLACE, 0, 0, viGetWidth() * 4.0f, viGetHeight() * 4.0f);
|
|
gSPSetGeometryMode(gdl++, G_ZBUFFER);
|
|
gDPSetTextureFilter(gdl++, G_TF_BILERP);
|
|
gDPSetTexturePersp(gdl++, G_TP_PERSP);
|
|
gDPSetColorDither(gdl++, G_CD_BAYER);
|
|
|
|
if (sp44);
|
|
|
|
return gdl;
|
|
}
|