Files
perfect_dark/src/lib/vi.c
T
2023-09-03 19:12:29 +02:00

943 lines
23 KiB
C

#include <ultra64.h>
#include "constants.h"
#include "game/tex.h"
#include "game/camera.h"
#include "game/player.h"
#include "game/file.h"
#include "game/zbuf.h"
#include "game/gfxmemory.h"
#include "game/menu.h"
#include "game/options.h"
#include "bss.h"
#include "lib/vi.h"
#include "lib/memp.h"
#include "lib/mtx.h"
#include "data.h"
#include "types.h"
#ifndef PLATFORM_N64
#include "video.h"
#endif
#define TO_U16_A(x) ((u16)(x))
#define TO_U16_B(x) ((x) & 0xffff)
#define TO_U16_C(x) ((u16)((x) & 0xffff))
#define ADD_LOW_AND_HI_16_TRUNCATE(reg, add) ((TO_U16_B(TO_U16_A((reg) >> 16) + (add)) << 16) | TO_U16_B(TO_U16_A(reg) + (add)))
#define ADD_LOW_AND_HI_16_MOD(reg, add) ((((((reg >> 16) & 0xffff) + (add)) % 0xffff) << 16) | (((((reg >> 0) & 0xffff) + (add)) % 0xffff) << 0))
Mtxf var80092830;
Mtx *var80092870;
u16 g_ViPerspScale;
u8 g_ViFrontIndex;
u8 g_ViBackIndex;
struct rend_vidat g_ViDataArray[NUM_GFXTASKS] = {
{
0, 0, 0, 0,
FBALLOC_WIDTH_LO, FBALLOC_HEIGHT_LO, // x and y
60, // fovy
(f32) FBALLOC_WIDTH_LO / (f32) FBALLOC_HEIGHT_LO, // aspect
30, // znear
10000, // zfar
FBALLOC_WIDTH_LO, FBALLOC_HEIGHT_LO, // bufx and bufy
FBALLOC_WIDTH_LO, FBALLOC_HEIGHT_LO, // viewx and viewy
0, 0, // viewleft and viewtop
true, // usezbuf
0,
}, {
0, 0, 0, 0,
FBALLOC_WIDTH_LO, FBALLOC_HEIGHT_LO, // x and y
60, // fovy
(f32) FBALLOC_WIDTH_LO / (f32) FBALLOC_HEIGHT_LO, // aspect
30, // znear
10000, // zfar
FBALLOC_WIDTH_LO, FBALLOC_HEIGHT_LO, // bufx and bufy
FBALLOC_WIDTH_LO, FBALLOC_HEIGHT_LO, // viewx and viewy
0, 0, // viewleft and viewtop
true, // usezbuf
0,
},
};
s32 g_ViTargetHStart = 0;
s32 g_ViTargetVStart = 0;
struct rend_vidat *g_ViFrontData = &g_ViDataArray[0];
struct rend_vidat *g_ViBackData = &g_ViDataArray[0];
bool g_ViIs16Bit = true;
bool g_ViReconfigured = false;
s32 g_ViSlot = 0;
void viConfigureForLogos(void)
{
g_ViFrontIndex = 0;
g_ViBackIndex = 1;
g_ViFrontData = g_ViDataArray + g_ViFrontIndex;
g_ViBackData = g_ViDataArray + g_ViBackIndex;
#if VERSION >= VERSION_PAL_FINAL
if (IS4MB()) {
g_ViDataArray[0].y = FBALLOC_HEIGHT_LO;
g_ViDataArray[0].bufy = FBALLOC_HEIGHT_LO;
g_ViDataArray[0].viewy = FBALLOC_HEIGHT_LO;
g_ViDataArray[1].y = FBALLOC_HEIGHT_LO;
g_ViDataArray[1].bufy = FBALLOC_HEIGHT_LO;
g_ViDataArray[1].viewy = FBALLOC_HEIGHT_LO;
g_ViTargetHStart = 0;
g_ViTargetVStart = 0;
} else {
g_ViTargetHStart = 0;
g_ViTargetVStart = VERSION >= VERSION_JPN_FINAL ? 0 : 12;
}
#else
g_ViTargetHStart = 0;
g_ViTargetVStart = 0;
if (IS4MB()) {
g_ViDataArray[0].y = FBALLOC_HEIGHT_LO;
g_ViDataArray[0].bufy = FBALLOC_HEIGHT_LO;
g_ViDataArray[0].viewy = FBALLOC_HEIGHT_LO;
g_ViDataArray[1].y = FBALLOC_HEIGHT_LO;
g_ViDataArray[1].bufy = FBALLOC_HEIGHT_LO;
g_ViDataArray[1].viewy = FBALLOC_HEIGHT_LO;
}
#endif
}
/**
* Configure the VI to display the copyright or accessingpak texture.
*
* The texture is the first thing displayed after power on.
*
* Both textures are 507 x 48, but the framebuffer width is 576.
*/
void viConfigureForCopyright(u16 *texturedata)
{
s32 i;
for (i = 0; i < NUM_GFXTASKS; i++) {
g_FrameBuffers[i] = texturedata;
g_ViDataArray[i].x = 576;
g_ViDataArray[i].bufx = 576;
g_ViDataArray[i].viewx = (VERSION >= VERSION_NTSC_1_0 ? 576 : 480);
g_ViDataArray[i].y = 48;
g_ViDataArray[i].bufy = 48;
g_ViDataArray[i].viewy = 48;
}
g_ViFrontData->fb = g_FrameBuffers[g_ViFrontIndex];
g_ViBackData->fb = g_FrameBuffers[g_ViBackIndex];
g_ViReconfigured = true;
g_Vars.fourmeg2player = false;
}
/**
* Configure the VI to display the legal screen.
*
* It's also used for the "check controllers" message
* if controller 1 is not connected.
*/
void viConfigureForLegal(void)
{
s32 i;
for (i = 0; i < NUM_GFXTASKS; i++) {
g_ViDataArray[i].x = FBALLOC_WIDTH_LO;
g_ViDataArray[i].bufx = FBALLOC_WIDTH_LO;
g_ViDataArray[i].viewx = FBALLOC_WIDTH_LO;
g_ViDataArray[i].y = FBALLOC_HEIGHT_LO;
g_ViDataArray[i].bufy = FBALLOC_HEIGHT_LO;
g_ViDataArray[i].viewy = FBALLOC_HEIGHT_LO;
}
g_Vars.fourmeg2player = false;
#if PAL
playerResetLoResIf4Mb();
#endif
}
const s16 g_ViModeWidths[] = {FBALLOC_WIDTH_LO, FBALLOC_WIDTH_LO, SCREEN_320 * 2};
const s16 g_ViModeHeights[] = {FBALLOC_HEIGHT_LO, FBALLOC_HEIGHT_LO, (PAL ? 252 : 220) * 2};
/**
* Allocate the colour framebuffers for the given stage.
*
* Regardless of whether hi-res is being used or not, the buffers are allocated
* for hi-res. This is because hi-res can be changed mid-stage, and the engine
* cannot reallocate the frame buffer without clearing the stage's entire memory
* pool.
*
* The same is probably true for wide and cinema modes.
*/
void viReset(s32 stagenum)
{
s32 i;
s32 fbsize;
u8 *ptr;
u8 *fb0;
u8 *fb1;
g_Vars.fourmeg2player = false;
if (stagenum == STAGE_TITLE || stagenum == STAGE_TEST_OLD) {
if (IS4MB()) {
viSetMode(VIMODE_HI);
fbsize = (FBALLOC_WIDTH_LO * 2) * (FBALLOC_HEIGHT_LO * 2) * NUM_FRAMEBUFFERS;
} else {
viSetMode(VIMODE_HI);
fbsize = g_ViModeWidths[2] * g_ViModeHeights[2] * NUM_FRAMEBUFFERS;
}
} else {
viSetMode(VIMODE_LO);
if (1);
fbsize = IS4MB()
? FBALLOC_WIDTH_LO * FBALLOC_HEIGHT_LO * NUM_FRAMEBUFFERS
: FBALLOC_WIDTH_HI * FBALLOC_HEIGHT_HI * NUM_FRAMEBUFFERS;
if (IS4MB() && PLAYERCOUNT() == 2) {
// 4MB 2-player: The viewports are 110px tall
#if VERSION >= VERSION_NTSC_1_0
fbsize = FBALLOC_WIDTH_LO * (FBALLOC_HEIGHT_LO / 2) * NUM_FRAMEBUFFERS;
#else
fbsize = SCREEN_320 * (SCREEN_240 / 2) * NUM_FRAMEBUFFERS;
#endif
g_Vars.fourmeg2player = true;
} else if ((g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0) && PLAYERCOUNT() == 2) {
// PAL is using its correct size
fbsize = SCREEN_WIDTH_LO * SCREEN_HEIGHT_LO * NUM_FRAMEBUFFERS;
}
}
ptr = mempAlloc(fbsize * sizeof(u16) + 0x40, MEMPOOL_STAGE);
ptr = (u8 *)(((uintptr_t) ptr + 0x3f) & 0xffffffc0);
g_FrameBuffers[0] = (u16 *) ptr;
g_FrameBuffers[1] = (u16 *) (fbsize + ptr);
g_ViFrontData->fb = g_FrameBuffers[g_ViFrontIndex];
g_ViBackData->fb = g_FrameBuffers[g_ViBackIndex];
fb0 = (u8 *) g_FrameBuffers[0];
fb1 = (u8 *) g_FrameBuffers[1];
for (i = 0; i < fbsize; i++) {
fb0[i] = 0;
fb1[i] = 0;
}
g_ViReconfigured = true;
}
/**
* If black is true, set the video output to black indefinitely.
* If black is false, unblack once all the framebuffers have been cycled through.
*
* The g_ViUnblackTimer value only ticks down when it's 2 or less,
* so passing true to this function makes it not tick.
*/
void viBlack(bool black)
{
black += NUM_FRAMEBUFFERS;
g_ViUnblackTimer = black;
}
void viHandleRetrace(void)
{
s32 prevmask;
s32 offset;
s32 reg;
if (g_ViShakeTimer != 0) {
g_ViShakeTimer--;
if (g_ViShakeTimer == 0) {
g_ViShakeIntensity = 0;
}
}
offset = g_ViShakeDirection * g_ViShakeIntensity;
g_ViShakeDirection = -g_ViShakeDirection;
#if VERSION >= VERSION_NTSC_1_0
prevmask = osSetIntMask(1);
#endif
reg = g_ViCurVStart0;
var8008dd60[1 - var8005ce74]->fldRegs[0].vStart = ADD_LOW_AND_HI_16_TRUNCATE(reg, offset);
reg = g_ViCurVStart1;
var8008dd60[1 - var8005ce74]->fldRegs[1].vStart = ADD_LOW_AND_HI_16_TRUNCATE(reg, offset);
#if VERSION >= VERSION_NTSC_1_0
osSetIntMask(prevmask);
#endif
#ifndef PLATFORM_N64
videoSetWindowOffset(0, offset);
#endif
osViSetMode(var8008dd60[1 - var8005ce74]);
osViBlack(g_ViUnblackTimer);
osViSetXScale(g_ViXScalesBySlot[1 - var8005ce74]);
osViSetYScale(g_ViYScalesBySlot[1 - var8005ce74]);
osViSetSpecialFeatures(OS_VI_GAMMA_OFF | OS_VI_DITHER_FILTER_ON);
}
void viUpdateMode(void)
{
struct rend_vidat *prevdata;
f32 x;
f32 y;
s32 reg;
s32 v1;
s32 tmp;
s32 slot;
s32 hstart;
s32 vstart;
if (g_ViFrontData->mode != g_ViBackData->mode) {
switch (g_ViBackData->mode) {
case VIMODE_NONE:
osViSetYScale(1.0f);
osViBlack(true);
break;
case VIMODE_LO:
break;
case VIMODE_HI:
break;
}
}
x = (f32) g_ViBackData->x / (f32) g_ViBackData->bufx;
y = (f32) g_ViBackData->y / (f32) g_ViBackData->bufy;
if (g_ViBackData->mode == VIMODE_NONE) {
y = 1.0f; \
} \
slot = g_ViSlot;
if (g_ViBackData->mode == 1);
if (1);
g_ViXScalesBySlot[slot] = x;
g_ViYScalesBySlot[slot] = y;
if (g_ViBackData->mode == VIMODE_LO) {
#if PAL
if (g_ViIs16Bit) {
var8008dcc0[slot] = osViModeTable[OS_VI_PAL_LAN1];
} else {
var8008dcc0[slot] = osViModeTable[OS_VI_PAL_LAN2];
}
#else
if (g_ViIs16Bit) {
if (osTvType == OS_TV_MPAL) {
var8008dcc0[slot] = osViModeTable[OS_VI_MPAL_LAN1];
} else {
var8008dcc0[slot] = osViModeTable[OS_VI_NTSC_LAN1];
}
} else {
if (osTvType == OS_TV_MPAL) {
if (g_ViIs16Bit && g_ViIs16Bit && g_ViIs16Bit);
var8008dcc0[slot] = osViModeTable[OS_VI_MPAL_LAN2];
} else {
var8008dcc0[slot] = osViModeTable[OS_VI_NTSC_LAN2];
}
}
#endif
var8008dcc0[slot].comRegs.width = g_ViBackData->bufx;
var8008dcc0[slot].comRegs.xScale = g_ViBackData->bufx * 1024 / 640;
var8008dcc0[slot].fldRegs[0].origin = g_ViBackData->bufx * 2;
var8008dcc0[slot].fldRegs[1].origin = g_ViBackData->bufx * 2;
#if PAL
var8008dcc0[slot].fldRegs[0].yScale = 1024;
var8008dcc0[slot].fldRegs[1].yScale = 1024;
#else
if (IS4MB()) {
var8008dcc0[slot].fldRegs[0].yScale = 1024;
var8008dcc0[slot].fldRegs[1].yScale = 1024;
} else {
var8008dcc0[slot].fldRegs[0].yScale = g_ViBackData->bufy * 2048 / 440;
var8008dcc0[slot].fldRegs[1].yScale = g_ViBackData->bufy * 2048 / 440;
}
#endif
hstart = var8008dcc0[slot].comRegs.hStart;
var8008de08 = var8008dcc0[slot].comRegs.hStart = ADD_LOW_AND_HI_16_MOD(hstart, g_ViTargetHStart);
v1 = g_ViBackData->bufy;
v1 = v1 * 1024 / var8008dcc0[slot].fldRegs[0].yScale;
if (v1 > 300) {
v1 >>= 1;
}
tmp = ((PAL ? 320 : 277) - v1);
vstart = ((tmp + 2) << 16) | (tmp + ((v1 - 2) << 1) + 2);
g_ViCurVStart0 = var8008dcc0[slot].fldRegs[0].vStart = ADD_LOW_AND_HI_16_MOD(vstart, g_ViTargetVStart);
g_ViCurVStart1 = var8008dcc0[slot].fldRegs[1].vStart = ADD_LOW_AND_HI_16_MOD(vstart, g_ViTargetVStart);
g_SchedViModesPending[slot] = true;
} else if (g_ViBackData->mode == VIMODE_HI) {
#if PAL
var8008dcc0[slot] = osViModeTable[OS_VI_PAL_HAF1];
#else
if (osTvType == OS_TV_MPAL) {
var8008dcc0[slot] = osViModeTable[OS_VI_MPAL_HAF1];
} else {
var8008dcc0[slot] = osViModeTable[OS_VI_NTSC_HAF1];
}
#endif
var8008dcc0[slot].comRegs.width = g_ViBackData->bufx;
var8008dcc0[slot].comRegs.xScale = g_ViBackData->bufx * 1024 / 640;
var8008dcc0[slot].fldRegs[0].yScale = 2048;
var8008dcc0[slot].fldRegs[1].yScale = 2048;
var8008dcc0[slot].fldRegs[0].origin = g_ViBackData->bufx * 2;
var8008dcc0[slot].fldRegs[1].origin = g_ViBackData->bufx * 4;
reg = var8008dcc0[slot].comRegs.hStart;
var8008de08 = var8008dcc0[slot].comRegs.hStart = ADD_LOW_AND_HI_16_MOD(reg, g_ViTargetHStart);
reg = var8008dcc0[slot].fldRegs[0].vStart;
g_ViCurVStart0 = var8008dcc0[slot].fldRegs[0].vStart = ADD_LOW_AND_HI_16_MOD(reg, g_ViTargetVStart);
reg = var8008dcc0[slot].fldRegs[1].vStart;
g_ViCurVStart1 = var8008dcc0[slot].fldRegs[1].vStart = ADD_LOW_AND_HI_16_MOD(reg, g_ViTargetVStart);
if (g_MainIsBooting) {
#if PAL
g_ViCurVStart0 = var8008dcc0[slot].fldRegs[0].vStart = ((g_ViTargetVStart + 506) % 0xffff) << 16 | (g_ViTargetVStart + 134) % 0xffff;
g_ViCurVStart1 = var8008dcc0[slot].fldRegs[1].vStart = ((g_ViTargetVStart + 508) % 0xffff) << 16 | (g_ViTargetVStart + 132) % 0xffff;
#else
g_ViCurVStart0 = var8008dcc0[slot].fldRegs[0].vStart = ((g_ViTargetVStart + 431) % 0xffff) << 16 | (g_ViTargetVStart + 123) % 0xffff;
g_ViCurVStart1 = var8008dcc0[slot].fldRegs[1].vStart = ((g_ViTargetVStart + 433) % 0xffff) << 16 | (g_ViTargetVStart + 121) % 0xffff;
#endif
}
g_SchedViModesPending[slot] = true;
} else {
g_SchedViModesPending[slot] = false;
}
slot = (slot + 1) % NUM_GFXTASKS;
g_ViSlot = slot;
g_RdpCurTask->framebuffer = g_ViIs16Bit ? g_ViBackData->fb : g_FrameBuffers[0];
prevdata = g_ViBackData;
g_ViFrontIndex = (g_ViFrontIndex + 1) % NUM_FRAMEBUFFERS;
g_ViBackIndex = (g_ViBackIndex + 1) % NUM_FRAMEBUFFERS;
g_ViFrontData = g_ViDataArray + g_ViFrontIndex;
g_ViBackData = g_ViDataArray + g_ViBackIndex;
bcopy(prevdata, g_ViBackData, sizeof(struct rend_vidat));
g_ViBackData->fb = g_FrameBuffers[g_ViBackIndex];
if (g_ViReconfigured) {
g_ViReconfigured = false;
viBlack(false);
}
}
void viShake(f32 intensity)
{
if (intensity > 14) {
intensity = 14;
}
if (intensity < 0) {
intensity = 0;
}
#ifdef PLATFORM_N64
g_ViShakeIntensity = intensity;
g_ViShakeTimer = 10;
#else
g_ViShakeIntensity = intensity * g_ViShakeIntensityMult;
g_ViShakeTimer = 20;
#endif
}
void viSetMode(s32 mode)
{
g_ViBackData->mode = mode;
g_ViBackData->x = g_ViBackData->bufx = g_ViModeWidths[mode];
g_ViBackData->y = g_ViBackData->bufy = g_ViModeHeights[mode];
}
void viSet16Bit(void)
{
g_ViIs16Bit = true;
}
void viSet32Bit(void)
{
g_ViIs16Bit = false;
}
u16 *viGetBackBuffer(void)
{
return g_ViBackData->fb;
}
u16 *viGetFrontBuffer(void)
{
return g_ViFrontData->fb;
}
void viSetBackBuffer(u16 *fb)
{
g_ViBackData->fb = fb;
}
Vp *viGetCurrentPlayerViewport(void)
{
return &g_Vars.currentplayer->viewport[g_ViBackIndex];
}
u16 viGetPerspScale(void)
{
return g_ViPerspScale;
}
Gfx *vi0000ab78(Gfx *gdl)
{
Mtxf sp110;
Mtxf spd0;
Mtxf sp90;
Mtxf sp50;
Mtx *sp4c;
Mtx *sp48;
u16 sp46;
guPerspectiveF(sp110.m, &sp46, g_ViBackData->fovy, g_ViBackData->aspect, g_ViBackData->znear, g_ViBackData->zfar + g_ViBackData->zfar, 1);
mtx4Copy(camGetWorldToScreenMtxf(), &sp90);
sp90.m[3][0] = 0;
sp90.m[3][1] = 0;
sp90.m[3][2] = 0;
mtx4MultMtx4(&sp110, &sp90, &spd0);
sp4c = gfxAllocateMatrix();
guMtxF2L(spd0.m, sp4c);
mtx4LoadIdentity(&sp50);
sp48 = gfxAllocateMatrix();
guMtxF2L(sp50.m, sp48);
gSPMatrix(gdl++, OS_K0_TO_PHYSICAL(sp4c), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gdl++, OS_K0_TO_PHYSICAL(sp48), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPPerspNormalize(gdl++, sp46);
return gdl;
}
Gfx *vi0000aca4(Gfx *gdl, f32 znear, f32 zfar)
{
u16 scale;
Mtxf tmp;
Mtx *mtx = gfxAllocateMatrix();
guPerspectiveF(tmp.m, &scale, g_ViBackData->fovy, g_ViBackData->aspect, znear, zfar, 1);
guMtxF2L(tmp.m, mtx);
gSPMatrix(gdl++, OS_K0_TO_PHYSICAL(mtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPPerspNormalize(gdl++, scale);
return gdl;
}
Gfx *vi0000ad5c(Gfx *gdl, Vp *vp)
{
vp[g_ViBackIndex].vp.vscale[0] = g_ViBackData->viewx * 2;
vp[g_ViBackIndex].vp.vtrans[0] = g_ViBackData->viewx * 2 + g_ViBackData->viewleft * 4;
vp[g_ViBackIndex].vp.vscale[1] = g_ViBackData->viewy * 2;
vp[g_ViBackIndex].vp.vtrans[1] = g_ViBackData->viewy * 2 + g_ViBackData->viewtop * 4;
gSPViewport(gdl++, OS_K0_TO_PHYSICAL(&vp[g_ViBackIndex]));
var80092870 = gfxAllocateMatrix();
guPerspectiveF(var80092830.m, &g_ViPerspScale, g_ViBackData->fovy, g_ViBackData->aspect, g_ViBackData->znear, g_ViBackData->zfar, 1);
guMtxF2L(var80092830.m, var80092870);
gSPMatrix(gdl++, OS_K0_TO_PHYSICAL(var80092870), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPPerspNormalize(gdl++, g_ViPerspScale);
camSetPerspectiveMtxL(var80092870);
camSetMtxF1754(&var80092830);
return gdl;
}
Gfx *vi0000af00(Gfx *gdl, Vp *vp)
{
vp[g_ViBackIndex].vp.vscale[0] = g_ViBackData->viewx * 2;
vp[g_ViBackIndex].vp.vtrans[0] = g_ViBackData->viewx * 2 + g_ViBackData->viewleft * 4;
vp[g_ViBackIndex].vp.vscale[1] = g_ViBackData->viewy * 2;
vp[g_ViBackIndex].vp.vtrans[1] = g_ViBackData->viewy * 2 + g_ViBackData->viewtop * 4;
vp[g_ViBackIndex].vp.vscale[2] = 511;
vp[g_ViBackIndex].vp.vtrans[2] = 511;
vp[g_ViBackIndex].vp.vscale[3] = 0;
vp[g_ViBackIndex].vp.vtrans[3] = 0;
gSPViewport(gdl++, OS_K0_TO_PHYSICAL(&vp[g_ViBackIndex]));
var80092870 = gfxAllocateMatrix();
guPerspectiveF(var80092830.m, &g_ViPerspScale, g_ViBackData->fovy, g_ViBackData->aspect, g_ViBackData->znear, g_ViBackData->zfar, 1);
guMtxF2L(var80092830.m, var80092870);
gSPMatrix(gdl++, OS_K0_TO_PHYSICAL(var80092870), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPPerspNormalize(gdl++, g_ViPerspScale);
camSetPerspectiveMtxL(var80092870);
camSetMtxF1754(&var80092830);
return gdl;
}
Gfx *vi0000b0e8(Gfx *gdl, f32 fovy, f32 aspect)
{
Mtxf tmp;
Mtx *mtx = gfxAllocateMatrix();
guPerspectiveF(tmp.m, &g_ViPerspScale, fovy, aspect, g_ViBackData->znear, g_ViBackData->zfar, 1);
guMtxF2L(tmp.m, mtx);
gSPMatrix(gdl++, OS_K0_TO_PHYSICAL(mtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPPerspNormalize(gdl++, g_ViPerspScale);
return gdl;
}
Gfx *vi0000b1a8(Gfx *gdl)
{
return vi0000ad5c(gdl, &g_Vars.currentplayer->viewport[0]);
}
Gfx *vi0000b1d0(Gfx *gdl)
{
gdl = vi0000b1a8(gdl);
if (g_ViIs16Bit) {
gDPSetColorImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, g_ViBackData->bufx, OS_K0_TO_PHYSICAL(g_ViBackData->fb));
} else {
gDPSetColorImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_32b, g_ViBackData->bufx, OS_K0_TO_PHYSICAL(g_FrameBuffers[0]));
}
return gdl;
}
Gfx *viPrepareZbuf(Gfx *gdl)
{
if (g_ViBackData->usezbuf) {
gdl = zbufConfigureRdp(gdl);
gdl = zbufClear(gdl);
}
return gdl;
}
Gfx *viFillBuffer(Gfx *gdl)
{
gDPSetCycleType(gdl++, G_CYC_FILL);
gDPFillRectangle(gdl++, 0, 0, g_ViBackData->bufx - 1, g_ViBackData->bufy - 1);
gDPPipeSync(gdl++);
return gdl;
}
Gfx *viRenderViewportEdges(Gfx *gdl)
{
gDPSetCycleType(gdl++, G_CYC_FILL);
gDPSetScissor(gdl++, G_SC_NON_INTERLACE, 0, 0, viGetWidth(), viGetHeight());
gDPSetFillColor(gdl++, GPACK_RGBA5551(0, 0, 0, 1) << 16 | GPACK_RGBA5551(0, 0, 0, 1));
#if VERSION >= VERSION_NTSC_1_0
if (PLAYERCOUNT() == 1
|| ((g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0)
&& playerHasSharedViewport() && g_Vars.currentplayernum == 0))
#else
if (PLAYERCOUNT() == 1
|| ((g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0)
&& (
(g_InCutscene && !g_MainIsEndscreen) || menuGetRoot() == MENUROOT_COOPCONTINUE
) && g_Vars.currentplayernum == 0))
#endif
{
// Single viewport
if (viGetViewTop() > 0) {
// Fill above
gDPFillRectangle(gdl++, 0, 0, viGetWidth() - 1, viGetViewTop() - 1);
gDPPipeSync(gdl++);
}
if (viGetViewTop() + viGetViewHeight() < viGetHeight()) {
// Fill below
gDPFillRectangle(gdl++,
0, viGetViewTop() + viGetViewHeight(),
viGetWidth() - 1, viGetHeight() - 1);
gDPPipeSync(gdl++);
}
} else {
if (g_Vars.currentplayerindex == 0) {
s32 topplayernum = 0;
s32 bottomplayernum = 0;
s32 tmpplayernum = 0;
if (PLAYERCOUNT() == 2) {
bottomplayernum = 1;
tmpplayernum = 1;
} else if (PLAYERCOUNT() >= 3) {
bottomplayernum = 2;
tmpplayernum = 2;
}
if (g_Vars.players[topplayernum]->viewtop > 0) {
// Fill above all viewports - full width
gDPFillRectangle(gdl++, 0, 0, viGetWidth() - 1, g_Vars.players[topplayernum]->viewtop - 1);
gDPPipeSync(gdl++);
}
if (g_Vars.players[bottomplayernum]->viewtop + g_Vars.players[bottomplayernum]->viewheight < viGetHeight()) {
// Fill below all viewports - full width
gDPFillRectangle(gdl++,
0, g_Vars.players[bottomplayernum]->viewtop + g_Vars.players[bottomplayernum]->viewheight,
viGetWidth() - 1, viGetHeight() - 1);
gDPPipeSync(gdl++);
}
// Horizontal middle line
gDPFillRectangle(gdl++,
0, g_Vars.players[tmpplayernum]->viewtop - 1,
viGetWidth() - 1, g_Vars.players[tmpplayernum]->viewtop - 1);
gDPPipeSync(gdl++);
if (PLAYERCOUNT() >= 3 ||
(PLAYERCOUNT() == 2 && (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL || g_Vars.fourmeg2player))) {
if (PLAYERCOUNT() == 2) {
tmpplayernum = 0;
}
// Vertical middle line
gDPFillRectangle(gdl++,
g_Vars.players[tmpplayernum]->viewleft + g_Vars.players[tmpplayernum]->viewwidth, 0,
g_Vars.players[tmpplayernum]->viewleft + g_Vars.players[tmpplayernum]->viewwidth, viGetHeight() - 1);
gDPPipeSync(gdl++);
}
if (PLAYERCOUNT() == 3) {
// Blank square in P4 spot
gDPFillRectangle(gdl++,
g_Vars.players[tmpplayernum]->viewleft + g_Vars.players[tmpplayernum]->viewwidth + 1, g_Vars.players[tmpplayernum]->viewtop,
viGetWidth() - 1, viGetHeight() - 1);
gDPPipeSync(gdl++);
}
}
}
return gdl;
}
#if VERSION < VERSION_NTSC_1_0
void viSetVStart(s32 vstart)
{
g_ViTargetVStart = vstart;
}
s32 viGetVStart(void)
{
return g_ViTargetVStart;
}
void viSetHStart(s32 hstart)
{
g_ViTargetHStart = hstart;
}
s32 viGetHStart(void)
{
return g_ViTargetHStart;
}
#endif
void viSetBufSize(s16 width, s16 height)
{
g_ViBackData->bufx = width;
g_ViBackData->bufy = height;
}
s16 viGetBufWidth(void)
{
return g_ViBackData->bufx;
}
s16 viGetBufHeight(void)
{
return g_ViBackData->bufy;
}
void viSetSize(s16 width, s16 height)
{
g_ViBackData->x = width;
g_ViBackData->y = height;
}
s16 viGetWidth(void)
{
return g_ViBackData->x;
}
s16 viGetHeight(void)
{
return g_ViBackData->y;
}
void viSetViewSize(s16 width, s16 height)
{
g_ViBackData->viewx = width;
g_ViBackData->viewy = height;
camSetScreenSize(g_ViBackData->viewx, g_ViBackData->viewy);
camSetScale();
}
s16 viGetViewWidth(void)
{
return g_ViBackData->viewx;
}
s16 viGetViewHeight(void)
{
return g_ViBackData->viewy;
}
void viSetViewPosition(s16 left, s16 top)
{
g_ViBackData->viewleft = left;
g_ViBackData->viewtop = top;
camSetScreenPosition(g_ViBackData->viewleft, g_ViBackData->viewtop);
}
s16 viGetViewLeft(void)
{
return g_ViBackData->viewleft;
}
s16 viGetViewTop(void)
{
return g_ViBackData->viewtop;
}
void viSetUseZBuf(bool use)
{
g_ViBackData->usezbuf = use;
}
void viSetFovY(f32 fovy)
{
g_ViBackData->fovy = fovy;
camSetPerspective(g_ViBackData->znear, g_ViBackData->fovy, g_ViBackData->aspect);
camSetScale();
}
void viSetAspect(f32 aspect)
{
g_ViBackData->aspect = aspect;
camSetPerspective(g_ViBackData->znear, g_ViBackData->fovy, g_ViBackData->aspect);
camSetScale();
}
f32 viGetAspect(void)
{
return g_ViBackData->aspect;
}
void viSetFovAspectAndSize(f32 fovy, f32 aspect, s16 width, s16 height)
{
g_ViBackData->fovy = fovy;
g_ViBackData->aspect = aspect;
g_ViBackData->viewx = width;
g_ViBackData->viewy = height;
camSetScreenSize(g_ViBackData->viewx, g_ViBackData->viewy);
camSetPerspective(g_ViBackData->znear, g_ViBackData->fovy, g_ViBackData->aspect);
camSetScale();
}
f32 viGetFovY(void)
{
return g_ViBackData->fovy;
}
void viSetZRange(f32 near, f32 far)
{
g_ViBackData->znear = near;
g_ViBackData->zfar = far;
camSetPerspective(g_ViBackData->znear, g_ViBackData->fovy, g_ViBackData->aspect);
camSetScale();
}
void viGetZRange(struct zrange *zrange)
{
zrange->near = g_ViBackData->znear;
zrange->far = g_ViBackData->zfar;
}
Gfx *viSetFillColour(Gfx *gdl, s32 r, s32 g, s32 b)
{
if (g_ViIs16Bit) {
gDPSetFillColor(gdl++, (GPACK_RGBA5551(r, g, b, 1) << 16) | GPACK_RGBA5551(r, g, b, 1));
} else {
gDPSetFillColor(gdl++, r << 24 | g << 16 | b << 8 | 0xff);
}
return gdl;
}
void viGrabJpg16(void)
{
// empty
}
void viGrabJpg32(void)
{
// empty
}
void viGrabRgb16(void)
{
// empty
}
void viGrabRgb32(void)
{
// empty
}