mirror of
https://gitlab.com/ryandwyer/perfect-dark
synced 2026-07-03 03:42:52 -04:00
1127 lines
25 KiB
C
1127 lines
25 KiB
C
#include <ultra64.h>
|
|
#include "constants.h"
|
|
#include "game/dlights.h"
|
|
#include "game/game_006900.h"
|
|
#include "game/atan2f.h"
|
|
#include "game/savebuffer.h"
|
|
#include "game/sky.h"
|
|
#include "game/bondview.h"
|
|
#include "game/game_1531a0.h"
|
|
#include "game/gfxmemory.h"
|
|
#include "game/lang.h"
|
|
#include "game/options.h"
|
|
#include "bss.h"
|
|
#include "lib/vi.h"
|
|
#include "lib/joy.h"
|
|
#include "lib/main.h"
|
|
#include "lib/rng.h"
|
|
#include "lib/str.h"
|
|
#include "lib/mtx.h"
|
|
#include "data.h"
|
|
#include "types.h"
|
|
#include "gbiex.h"
|
|
|
|
#ifdef AVOID_UB
|
|
char var800a41c0[26];
|
|
#else
|
|
char var800a41c0[24];
|
|
#endif
|
|
|
|
u8 g_IrScanlines[2][480];
|
|
|
|
#if VERSION < VERSION_NTSC_1_0
|
|
u8 var800a8b58nb[0x1c0];
|
|
#endif
|
|
|
|
s32 var8007f840 = 0;
|
|
u8 var8007f844 = 0;
|
|
u8 var8007f848 = 0;
|
|
s32 g_IrBinocularRadius = PAL ? 102 : 90;
|
|
s32 var8007f850 = 3;
|
|
u32 var8007f854 = 0x00000000;
|
|
u32 var8007f858 = 0xb8000000;
|
|
u32 var8007f85c = 0x00000000;
|
|
|
|
#if VERSION < VERSION_NTSC_1_0
|
|
void func0f13c2d0nb(void)
|
|
{
|
|
mainOverrideVariable("fsrad", (u32 *)&g_IrBinocularRadius);
|
|
mainOverrideVariable("fscs", (u32 *)&var8007f850);
|
|
}
|
|
#endif
|
|
|
|
Gfx *bviewDrawIrRect(Gfx *gdl, s32 x1, s32 y1, s32 x2, s32 y2)
|
|
{
|
|
gDPFillRectangle(gdl++, x1, y1, x2, y2);
|
|
|
|
return gdl;
|
|
}
|
|
|
|
Gfx *bview0f141864(Gfx *gdl, s32 arg1, s32 arg2, s32 arg3, s32 arg4, s32 arg5)
|
|
{
|
|
s32 value = viGetWidth() * arg2 + arg4;
|
|
|
|
gDPPipeSync(gdl++);
|
|
gDPSetTextureImage(gdl++, G_IM_FMT_I, G_IM_SIZ_8b, 320, value * 2 + arg1);
|
|
gDPLoadSync(gdl++);
|
|
gDPLoadBlock(gdl++, arg3, 0, 0, arg5 - 1, 0);
|
|
|
|
return gdl;
|
|
}
|
|
|
|
Gfx *bview0f141940(Gfx *gdl, s32 arg1, s32 arg2, s32 tile, s32 arg4, s32 width)
|
|
{
|
|
s32 value = viGetWidth() * arg2 + arg4;
|
|
|
|
gDPPipeSync(gdl++);
|
|
gDPSetTextureImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, width, value * 2 + arg1);
|
|
gDPLoadSync(gdl++);
|
|
gDPLoadBlock(gdl++, tile, 0, 0, width - 1, 0);
|
|
|
|
return gdl;
|
|
}
|
|
|
|
Gfx *bview0f141a20(Gfx *gdl, s32 top, s32 height, s32 left, s32 width)
|
|
{
|
|
gDPPipeSync(gdl++);
|
|
|
|
gSPTextureRectangle(gdl++,
|
|
left << 2,
|
|
top << 2,
|
|
(left + width) << 2,
|
|
(top + 1) << 2,
|
|
G_TX_RENDERTILE, 0, 0, height * 1024, 1024);
|
|
|
|
return gdl;
|
|
}
|
|
|
|
Gfx *bviewCopyPixels(Gfx *gdl, u16 *fb, s32 top, u32 tile, s32 arg4, f32 arg5, s32 left, s32 width)
|
|
{
|
|
u32 image;
|
|
s32 width2;
|
|
s32 numparts;
|
|
s32 lrs[1];
|
|
|
|
if (width > 320) {
|
|
numparts = 2;
|
|
lrs[0] = width / numparts;
|
|
|
|
image = (u32) &fb[viGetWidth() * top + left] & 0x00ffffff;
|
|
|
|
gDPSetTextureImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 320, image);
|
|
gDPLoadBlock(gdl++, tile, 0, 0, width / numparts - 1, 0);
|
|
gSPTextureRectangle(gdl++,
|
|
left << 2,
|
|
arg4 << 2,
|
|
((s32) left + width / numparts) << 2,
|
|
(arg4 + 1) << 2,
|
|
G_TX_RENDERTILE,
|
|
(s32) ((width - width / arg5) * 16.0f),
|
|
0,
|
|
(s32) (1024.0f / arg5),
|
|
1024);
|
|
|
|
left += lrs[0];
|
|
|
|
image = (u32) &fb[viGetWidth() * top + left] & 0x00ffffff;
|
|
|
|
gDPSetTextureImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 320, image);
|
|
gDPLoadBlock(gdl++, tile, 0, 0, lrs[0] - 1, 0);
|
|
|
|
gSPTextureRectangle(gdl++,
|
|
left << 2,
|
|
arg4 << 2,
|
|
(left + lrs[0]) << (0, 2),
|
|
(arg4 + 1) << 2,
|
|
G_TX_RENDERTILE,
|
|
0,
|
|
0,
|
|
(s32) (1024.0f / arg5),
|
|
1024);
|
|
} else {
|
|
width2 = width;
|
|
|
|
image = (u32) &fb[viGetWidth() * top + left] & 0x00ffffff;
|
|
|
|
gDPSetTextureImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 320, image);
|
|
gDPLoadBlock(gdl++, tile, 0, 0, width2 - 1, 0);
|
|
|
|
numparts = (s32) (1024.0f / arg5);
|
|
|
|
gSPTextureRectangle(gdl++,
|
|
left << 2,
|
|
arg4 << 2,
|
|
(left + width2) << 2,
|
|
(arg4 + 1) << 2,
|
|
G_TX_RENDERTILE,
|
|
(s32) ((width - width / arg5) * 16.0f),
|
|
0,
|
|
numparts,
|
|
1024);
|
|
}
|
|
|
|
return gdl;
|
|
}
|
|
|
|
Gfx *bviewDrawFisheyeRect(Gfx *gdl, s32 arg1, f32 arg2, s32 arg3, s32 arg4)
|
|
{
|
|
if (arg2 < 1) {
|
|
f32 tmp = arg4 * 0.5f;
|
|
f32 fVar4 = arg3 + tmp;
|
|
f32 fVar7 = (s32)(arg2 * tmp);
|
|
|
|
gDPFillRectangle(gdl++, arg3, arg1, fVar4 - fVar7, arg1 + 1);
|
|
gDPFillRectangle(gdl++, fVar4 + fVar7, arg1, arg3 + arg4, arg1 + 1);
|
|
}
|
|
|
|
return gdl;
|
|
}
|
|
|
|
Gfx *bviewPrepareStaticRgba16(Gfx *gdl, u32 colour, u32 alpha)
|
|
{
|
|
static u32 envcol = 0xffffffff;
|
|
static u32 primcol = 0x7f7f7fff;
|
|
|
|
mainOverrideVariable("envcol", &envcol);
|
|
mainOverrideVariable("primcol", &primcol);
|
|
|
|
gDPPipeSync(gdl++);
|
|
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);
|
|
gDPSetCycleType(gdl++, G_CYC_1CYCLE);
|
|
gSPTexture(gdl++, 0xffff, 0xffff, 0, G_TX_RENDERTILE, G_ON);
|
|
gDPSetTextureLOD(gdl++, G_TL_TILE);
|
|
gDPSetTextureDetail(gdl++, G_TD_CLAMP);
|
|
gDPSetTextureLUT(gdl++, G_TT_NONE);
|
|
gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 160, 0, 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);
|
|
gDPSetTileSize(gdl++, G_TX_RENDERTILE, 0, 0, 0x0800, 0x0020);
|
|
gDPSetTextureFilter(gdl++, G_TF_POINT);
|
|
gDPSetColor(gdl++, G_SETENVCOLOR, (colour & 0xffffff00) | (alpha & 0xff));
|
|
gDPSetCombineLERP(gdl++,
|
|
TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, ENVIRONMENT,
|
|
TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, ENVIRONMENT);
|
|
gDPSetTexturePersp(gdl++, G_TP_NONE);
|
|
gDPSetColorDither(gdl++, G_CD_DISABLE);
|
|
gDPSetAlphaDither(gdl++, G_AD_NOISE);
|
|
gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_NOOP2);
|
|
|
|
return gdl;
|
|
}
|
|
|
|
Gfx *bviewPrepareStaticI8(Gfx *gdl, u32 colour, u32 alpha)
|
|
{
|
|
static u32 envcol = 0xffffffff;
|
|
static u32 primcol = 0x7f7f7fff;
|
|
|
|
mainOverrideVariable("envcol", &envcol);
|
|
mainOverrideVariable("primcol", &primcol);
|
|
|
|
gDPPipeSync(gdl++);
|
|
gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_8b, 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);
|
|
gDPSetCycleType(gdl++, G_CYC_1CYCLE);
|
|
gSPTexture(gdl++, 0xffff, 0xffff, 0, G_TX_RENDERTILE, G_ON);
|
|
gDPSetTextureLOD(gdl++, G_TL_TILE);
|
|
gDPSetTextureDetail(gdl++, G_TD_CLAMP);
|
|
gDPSetTextureLUT(gdl++, G_TT_NONE);
|
|
gDPSetTile(gdl++, G_IM_FMT_I, G_IM_SIZ_8b, 160, 0, 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);
|
|
gDPSetTileSize(gdl++, G_TX_RENDERTILE, 0, 0, 0x0800, 0x0020);
|
|
gDPSetTextureFilter(gdl++, G_TF_POINT);
|
|
gDPSetColor(gdl++, G_SETENVCOLOR, (colour & 0xffffff00) | (alpha & 0xff));
|
|
gDPSetCombineLERP(gdl++,
|
|
TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, ENVIRONMENT,
|
|
TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, ENVIRONMENT);
|
|
gDPSetTexturePersp(gdl++, G_TP_NONE);
|
|
gDPSetColorDither(gdl++, G_CD_DISABLE);
|
|
gDPSetAlphaDither(gdl++, G_AD_NOISE);
|
|
gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_NOOP2);
|
|
|
|
return gdl;
|
|
}
|
|
|
|
Gfx *bviewDrawMotionBlur(Gfx *gdl, u32 colour, u32 alpha)
|
|
{
|
|
u16 *fb = viGetFrontBuffer();
|
|
s32 viewtop = viGetViewTop();
|
|
s32 viewheight = viGetViewHeight();
|
|
f32 fxxx;
|
|
f32 fyyy;
|
|
s32 viewwidth = viGetViewWidth();
|
|
s32 viewleft = viGetViewLeft();
|
|
f32 somefloat;
|
|
s32 newalpha;
|
|
s32 i;
|
|
|
|
static u32 sfyyy = 1000;
|
|
static u32 sfxxx = 1000;
|
|
|
|
if (var8007f848) {
|
|
return gdl;
|
|
}
|
|
|
|
var8007f848 = true;
|
|
|
|
newalpha = alpha;
|
|
newalpha += var8007f844;
|
|
|
|
if (newalpha > 230) {
|
|
newalpha = 230;
|
|
}
|
|
|
|
var8007f844 = 0;
|
|
|
|
mainOverrideVariable("sfxxx", &sfxxx);
|
|
fxxx = sfxxx / 1000.0f;
|
|
mainOverrideVariable("sfyyy", &sfyyy);
|
|
fyyy = sfyyy / 1000.0f;
|
|
|
|
gDPPipeSync(gdl++);
|
|
|
|
somefloat = (viewheight - viewheight / fyyy) * 0.5f;
|
|
gdl = bviewPrepareStaticRgba16(gdl, colour, newalpha);
|
|
|
|
for (i = viewtop; i < viewtop + viewheight; i++) {
|
|
gdl = bviewCopyPixels(gdl, fb, viewtop + (s32)somefloat, 5, i, fxxx, viewleft, viewwidth);
|
|
somefloat += 1.0f / fyyy;
|
|
}
|
|
|
|
return gdl;
|
|
}
|
|
|
|
/**
|
|
* Draw static for the Infiltration intro cutscene and Slayer rockets.
|
|
*/
|
|
Gfx *bviewDrawStatic(Gfx *gdl, u32 arg1, s32 arg2)
|
|
{
|
|
u16 *fb = viGetFrontBuffer();
|
|
s32 viewtop = viGetViewTop();
|
|
s32 viewheight = viGetViewHeight();
|
|
s32 viewwidth = viGetViewWidth();
|
|
s32 viewleft = viGetViewLeft();
|
|
u16 *fb2 = (u16 *) PHYS_TO_K0(random() & 0xfff00);
|
|
s32 y;
|
|
|
|
gDPPipeSync(gdl++);
|
|
|
|
gdl = bviewPrepareStaticI8(gdl, arg1, arg2);
|
|
|
|
for (y = viewtop; y < viewtop + viewheight; y++) {
|
|
gdl = bviewCopyPixels(gdl, fb2, random() % 240, 5, y, 1.0f, viewleft, viewwidth);
|
|
}
|
|
|
|
if (fb2) {
|
|
// empty
|
|
}
|
|
|
|
return gdl;
|
|
}
|
|
|
|
/**
|
|
* Draw the yellow interlace effect for Slayer rockets.
|
|
*/
|
|
Gfx *bviewDrawSlayerRocketInterlace(Gfx *gdl, u32 colour, u32 alpha)
|
|
{
|
|
u16 *fb = viGetBackBuffer();
|
|
s32 viewtop = viGetViewTop();
|
|
s32 viewheight = viGetViewHeight();
|
|
s32 viewwidth = viGetViewWidth();
|
|
s32 y;
|
|
s32 viewleft = viGetViewLeft();
|
|
f32 angle = 0.52359879016876f;
|
|
s32 offset = (s32)(g_20SecIntervalFrac * 600.0f) % 12;
|
|
f32 increment;
|
|
|
|
var8007f840++;
|
|
|
|
if (var8007f840 >= 2) {
|
|
return gdl;
|
|
}
|
|
|
|
strcpy(var800a41c0, "interlaceGfx");
|
|
|
|
gDPPipeSync(gdl++);
|
|
|
|
increment = (2.6179938316345f - angle) / viewheight;
|
|
|
|
gdl = bviewPrepareStaticRgba16(gdl, colour, alpha);
|
|
|
|
for (y = viewtop; y < viewtop + viewheight; y++) {
|
|
s32 offsety = y - offset;
|
|
|
|
if ((offsety % 8) == 0 || y == viewtop) {
|
|
if ((offsety % 16) < 8) {
|
|
gDPSetEnvColor(gdl++, 0xff, 0xff, 0x00, 0xff);
|
|
} else {
|
|
gDPSetEnvColor(gdl++, 0xff, 0xff, 0xbf, 0xff);
|
|
}
|
|
}
|
|
|
|
gdl = bviewCopyPixels(gdl, fb, y, 5, y, 2.0f - sinf(angle), viewleft, viewwidth);
|
|
|
|
angle += increment;
|
|
}
|
|
|
|
return gdl;
|
|
}
|
|
|
|
/**
|
|
* Draw the blue film interlace effect for the Infiltration intro cutscene.
|
|
*/
|
|
Gfx *bviewDrawFilmInterlace(Gfx *gdl, u32 colour, u32 alpha)
|
|
{
|
|
u16 *fb = viGetBackBuffer();
|
|
s32 viewtop = viGetViewTop();
|
|
s32 viewheight = viGetViewHeight();
|
|
s32 y;
|
|
s32 viewwidth = viGetViewWidth();
|
|
s32 viewleft = viGetViewLeft();
|
|
s32 offset = (s32)(g_20SecIntervalFrac * 600.0f) % 12;
|
|
u32 stack;
|
|
|
|
var8007f840++;
|
|
|
|
if (var8007f840 >= 2) {
|
|
return gdl;
|
|
}
|
|
|
|
strcpy(var800a41c0, "BlueInterlaceGfx");
|
|
|
|
gDPPipeSync(gdl++);
|
|
|
|
gdl = bviewPrepareStaticRgba16(gdl, colour, alpha);
|
|
|
|
for (y = viewtop; y < viewtop + viewheight; y++) {
|
|
s32 offsety = y - offset;
|
|
s32 tmpy = y;
|
|
|
|
if (offsety % 6 == 0 || y == viewtop) {
|
|
if (offsety % 12 < 6) {
|
|
gDPSetEnvColor(gdl++, 0x7f, 0xff, 0xff, 0xff);
|
|
} else {
|
|
gDPSetEnvColor(gdl++, 0x00, 0xaf, 0xff, 0xff);
|
|
}
|
|
}
|
|
|
|
if (random() % 20 == 1) {
|
|
tmpy = random() % 200;
|
|
}
|
|
|
|
gdl = bviewCopyPixels(gdl, fb, tmpy, 5, y, 1, viewleft, viewwidth);
|
|
}
|
|
|
|
return gdl;
|
|
}
|
|
|
|
/**
|
|
* Draw a zoom in/out motion blur effect.
|
|
*
|
|
* Used when entering/exiting combat boosts and when entering/exiting xray mode.
|
|
*/
|
|
Gfx *bviewDrawZoomBlur(Gfx *gdl, u32 colour, s32 alpha, f32 arg3, f32 arg4)
|
|
{
|
|
u16 *fb = viGetFrontBuffer();
|
|
s32 viewtop = viGetViewTop();
|
|
s32 viewheight = viGetViewHeight();
|
|
s32 viewwidth = viGetViewWidth();
|
|
s32 viewleft = viGetViewLeft();
|
|
f32 somefloat;
|
|
s32 i;
|
|
|
|
var8007f840++;
|
|
|
|
if (var8007f840 >= 2) {
|
|
return gdl;
|
|
}
|
|
|
|
strcpy(var800a41c0, "stretchBlurGfx");
|
|
|
|
gDPPipeSync(gdl++);
|
|
|
|
somefloat = (viewheight - viewheight / arg4) * 0.5f;
|
|
|
|
gdl = bviewPrepareStaticRgba16(gdl, colour, alpha);
|
|
|
|
for (i = viewtop; i < viewtop + viewheight; i++) {
|
|
gdl = bviewCopyPixels(gdl, fb, (s32)somefloat + viewtop, 5, i, arg3, viewleft, viewwidth);
|
|
somefloat += 1.0f / arg4;
|
|
}
|
|
|
|
return gdl;
|
|
}
|
|
|
|
f32 bview0f142d74(s32 arg0, f32 arg1, f32 arg2, f32 arg3)
|
|
{
|
|
f32 result;
|
|
f32 value = arg2;
|
|
|
|
if (arg0 < 0 || arg0 >= 0x80) {
|
|
return 0.01f;
|
|
}
|
|
|
|
value += arg0 * arg1;
|
|
|
|
if (arg3 > value * value) {
|
|
result = sqrtf(arg3 - value * value) * 0.00625f;
|
|
} else {
|
|
result = 0.01f;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void bview0f1572f8(void)
|
|
{
|
|
// empty
|
|
}
|
|
|
|
u8 var8007f878 = 0;
|
|
|
|
Gfx *bviewDrawNvLens(Gfx *gdl)
|
|
{
|
|
u16 *fb = viGetBackBuffer();
|
|
s32 viewheight = viGetViewHeight();
|
|
s32 viewwidth = viGetViewWidth();
|
|
s32 viewtop = viGetViewTop();
|
|
s32 viewleft = viGetViewLeft();
|
|
s32 viewbottom = viewtop + viewheight;
|
|
s32 roomvalue;
|
|
s32 y;
|
|
|
|
var8007f840++;
|
|
|
|
if (var8007f840 >= 2) {
|
|
return gdl;
|
|
}
|
|
|
|
strcpy(var800a41c0, "Fullscreen_DrawFaultScope");
|
|
|
|
var8009caec = 0xbc;
|
|
var8009caef = 0xbe;
|
|
var8009caf0 = 0xde;
|
|
var8009caed = 0x50;
|
|
var8009caee = 0xc0;
|
|
|
|
roomvalue = func0f0009c0(g_Vars.currentplayer->prop->rooms[0]);
|
|
|
|
if (roomvalue > 128) {
|
|
sky0f127334(roomvalue, roomvalue, roomvalue);
|
|
}
|
|
|
|
if (g_Menus[g_Vars.currentplayerstats->mpindex].curdialog == NULL) {
|
|
gdl = bviewDrawMotionBlur(gdl, 0x00ff0000, 0x60);
|
|
}
|
|
|
|
gDPPipeSync(gdl++);
|
|
|
|
gdl = bviewPrepareStaticRgba16(gdl, 0xffffffff, 0xff);
|
|
|
|
var8007f878++;
|
|
|
|
for (y = viewtop; y < viewbottom; y++) {
|
|
u8 green;
|
|
|
|
if (((var8007f878 & 1) != (y & 1)) != 0) {
|
|
u8 tmp = random() % 12;
|
|
green = 0xff - tmp;
|
|
} else {
|
|
green = 0x94;
|
|
}
|
|
|
|
gDPSetColor(gdl++, G_SETENVCOLOR, (green << 16) + 0xff);
|
|
|
|
gdl = bviewCopyPixels(gdl, fb, y, 5, y, 1, viewleft, viewwidth);
|
|
}
|
|
|
|
return gdl;
|
|
}
|
|
|
|
/**
|
|
* Night vision doesn't have binoculars.
|
|
*/
|
|
Gfx *bviewDrawNvBinoculars(Gfx *gdl)
|
|
{
|
|
return gdl;
|
|
}
|
|
|
|
Gfx *bviewDrawIrLens(Gfx *gdl)
|
|
{
|
|
s32 i;
|
|
s32 fadeincrement;
|
|
u16 *fb = viGetBackBuffer();
|
|
s32 viewheight = viGetViewHeight();
|
|
s32 viewwidth = viGetViewWidth();
|
|
s32 viewtop = viGetViewTop();
|
|
s32 viewleft = viGetViewLeft();
|
|
s32 viewright;
|
|
s32 viewbottom;
|
|
s32 viewcentrex;
|
|
s32 sqinnerradius;
|
|
s32 stack[3];
|
|
s32 scanincrement;
|
|
s32 scantop;
|
|
s32 scanbottom;
|
|
s32 scanrate = 4;
|
|
s32 faderate = 2;
|
|
u32 red;
|
|
s32 outerradius;
|
|
s32 innerradius;
|
|
s32 viewcentrey;
|
|
f32 viewheightf;
|
|
s32 a0;
|
|
|
|
#if VERSION < VERSION_NTSC_1_0
|
|
static s32 fsscanline = 0;
|
|
static s32 fslastradius = -1;
|
|
#endif
|
|
|
|
viewright = viewleft + viewwidth;
|
|
viewcentrex = (viewleft + viewright) / 2;
|
|
|
|
outerradius = g_IrBinocularRadius;
|
|
innerradius = g_IrBinocularRadius / var8007f850;
|
|
|
|
var8007f840++;
|
|
|
|
if (var8007f840 >= 2) {
|
|
return gdl;
|
|
}
|
|
|
|
strcpy(var800a41c0, "Fullscreen_DrawFaultScope");
|
|
|
|
#if VERSION < VERSION_NTSC_1_0
|
|
osSyncPrintf("Fault Scope is active\n");
|
|
func0f13c2d0nb();
|
|
#endif
|
|
|
|
viewbottom = viewtop + viewheight;
|
|
viewcentrey = (viewtop + viewbottom) / 2;
|
|
scantop = viewcentrey - outerradius;
|
|
scanbottom = viewcentrey + outerradius;
|
|
i = viewheight;
|
|
|
|
if (scantop > viewbottom) {
|
|
scantop = viewbottom;
|
|
}
|
|
|
|
#if VERSION >= VERSION_NTSC_1_0
|
|
if (scanbottom > viewbottom) {
|
|
scanbottom = viewbottom;
|
|
}
|
|
#else
|
|
if (scantop > viewbottom) {
|
|
scantop = viewbottom;
|
|
}
|
|
#endif
|
|
|
|
if (scantop < viewtop) {
|
|
scantop = viewtop;
|
|
}
|
|
|
|
if (scanbottom < viewtop) {
|
|
scanbottom = viewtop;
|
|
}
|
|
|
|
scanincrement = (f32) scanrate * i / 240.0f;
|
|
fadeincrement = (f32) faderate * i / 240.0f;
|
|
|
|
// This code runs on the first frame of IR use (90 != 0),
|
|
// and in debug versions developers could change the radius at runtime.
|
|
#if VERSION >= VERSION_NTSC_1_0
|
|
if (g_Vars.currentplayer->fslastradius != outerradius) {
|
|
for (i = 0; i < 480; i++) {
|
|
g_IrScanlines[g_Vars.currentplayernum][i] = 0xff;
|
|
}
|
|
|
|
g_Vars.currentplayer->fsscanline = 0;
|
|
g_Vars.currentplayer->fslastradius = outerradius;
|
|
}
|
|
#else
|
|
if (fslastradius != outerradius) {
|
|
for (i = 0; i < 480; i++) {
|
|
g_IrScanlines[0][i] = 0xff;
|
|
}
|
|
|
|
fsscanline = 0;
|
|
fslastradius = outerradius;
|
|
}
|
|
#endif
|
|
|
|
// Increment the scanline
|
|
#if VERSION >= VERSION_NTSC_1_0
|
|
for (i = 0; i < scanincrement; i++) {
|
|
if (g_Vars.currentplayer->fsscanline >= scanbottom) {
|
|
g_Vars.currentplayer->fsscanline = scantop;
|
|
}
|
|
|
|
g_IrScanlines[g_Vars.currentplayernum][g_Vars.currentplayer->fsscanline] = 0xff - i;
|
|
|
|
g_Vars.currentplayer->fsscanline++;
|
|
}
|
|
#else
|
|
for (i = 0; i < scanincrement; i++, fsscanline++) {
|
|
if (fsscanline == scanbottom) {
|
|
fsscanline = scantop;
|
|
}
|
|
|
|
g_IrScanlines[0][fsscanline] = 0xff - i;
|
|
}
|
|
#endif
|
|
|
|
var8009caec = 0xff;
|
|
var8009caef = 0xde;
|
|
var8009caf0 = 0xde;
|
|
|
|
gDPPipeSync(gdl++);
|
|
|
|
gdl = bviewPrepareStaticRgba16(gdl, 0xffffffff, 255);
|
|
|
|
sqinnerradius = innerradius * innerradius;
|
|
|
|
for (i = scantop; i < scanbottom; i++) {
|
|
#if VERSION >= VERSION_NTSC_1_0
|
|
if (i & 1) {
|
|
red = g_IrScanlines[g_Vars.currentplayernum][i];
|
|
} else {
|
|
red = g_IrScanlines[g_Vars.currentplayernum][i] * 2 / 3;
|
|
}
|
|
#else
|
|
if (i & 1) {
|
|
red = g_IrScanlines[0][i];
|
|
} else {
|
|
red = g_IrScanlines[0][i] * 2 / 3;
|
|
}
|
|
#endif
|
|
|
|
red += random() % 8;
|
|
|
|
if (red > 255) {
|
|
red = 255;
|
|
}
|
|
|
|
gDPSetEnvColorViaWord(gdl++, (red << 24) + 0xff);
|
|
|
|
a0 = viewcentrey - i;
|
|
|
|
if (a0 * a0 < sqinnerradius) {
|
|
// Rendering a line that overlaps the semicircle
|
|
// in the middle of the screen
|
|
f32 f0 = a0;
|
|
s32 semicirclewidth = sqrtf(sqinnerradius - (s32) (f0 * f0)) * (viewwidth / 320.0f);
|
|
s32 semicircleright = viewcentrex + semicirclewidth;
|
|
s32 rightsidewidth = viewwidth - semicircleright;
|
|
|
|
// Left and right of semicircle
|
|
gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, viewleft, viewcentrex);
|
|
gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, semicircleright, rightsidewidth);
|
|
|
|
// The semicircle itself has a static colour
|
|
gDPSetEnvColorViaWord(gdl++, 0xee0000ff);
|
|
gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, viewcentrex, semicirclewidth);
|
|
} else {
|
|
gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, viewleft, viewwidth);
|
|
}
|
|
|
|
#if VERSION >= VERSION_NTSC_1_0
|
|
if (g_IrScanlines[g_Vars.currentplayernum][i] > fadeincrement) {
|
|
g_IrScanlines[g_Vars.currentplayernum][i] -= fadeincrement;
|
|
}
|
|
#else
|
|
if (g_IrScanlines[0][i] > fadeincrement) {
|
|
g_IrScanlines[0][i] -= fadeincrement;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (g_Menus[g_Vars.currentplayerstats->mpindex].curdialog == NULL) {
|
|
gdl = bviewDrawMotionBlur(gdl, 0xff000000, 0x40);
|
|
}
|
|
|
|
return gdl;
|
|
}
|
|
|
|
/**
|
|
* Draw a horizontal blur/sretch effect. Unused.
|
|
*
|
|
* The term "Intro" used in the string suggests that was made for an older
|
|
* version of the title screen, similar to bviewDrawIntroText.
|
|
*/
|
|
Gfx *bviewDrawIntroFaderBlur(Gfx *gdl, s32 arg1)
|
|
{
|
|
u16 *fb = viGetBackBuffer();
|
|
s32 viewtop = viGetViewTop();
|
|
s32 viewheight = viGetViewHeight();
|
|
s32 viewwidth = viGetViewWidth();
|
|
s32 viewleft = viGetViewLeft();
|
|
f32 halfheight;
|
|
f32 extra;
|
|
s32 y;
|
|
|
|
var8007f840++;
|
|
|
|
if (var8007f840 >= 2) {
|
|
return gdl;
|
|
}
|
|
|
|
strcpy(var800a41c0, "IntroFaderBlurGfx");
|
|
|
|
gDPPipeSync(gdl++);
|
|
|
|
gdl = bviewPrepareStaticRgba16(gdl, 0xffffffff, 255);
|
|
|
|
halfheight = viewheight * 0.5f;
|
|
|
|
extra = 0.5f;
|
|
extra += 0.5f;
|
|
|
|
for (y = viewtop; y < viewtop + viewheight; y++) {
|
|
f32 frac = (y - viewtop - halfheight) / halfheight;
|
|
|
|
if (frac < 0.0f) {
|
|
frac = -frac;
|
|
}
|
|
|
|
frac += extra;
|
|
|
|
if (frac > 1.0f) {
|
|
frac = 1.0f;
|
|
}
|
|
|
|
gdl = bviewCopyPixels(gdl, fb, y, 5, y, RANDOMFRAC() * frac + 1.0f, viewleft, viewwidth);
|
|
}
|
|
|
|
return gdl;
|
|
}
|
|
|
|
/**
|
|
* Called from the title screen's "Rare Presents" mode, which is unused.
|
|
*/
|
|
Gfx *bviewDrawIntroText(Gfx *gdl)
|
|
{
|
|
u16 *fb = viGetBackBuffer();
|
|
s32 viewtop = viGetViewTop();
|
|
s32 viewheight = viGetViewHeight();
|
|
s32 viewwidth = viGetViewWidth();
|
|
s32 viewleft = viGetViewLeft();
|
|
s32 y;
|
|
|
|
var8007f840++;
|
|
|
|
if (var8007f840 >= 2) {
|
|
return gdl;
|
|
}
|
|
|
|
strcpy(var800a41c0, "IntroTextInterfereGfx");
|
|
|
|
gDPPipeSync(gdl++);
|
|
|
|
gdl = bviewPrepareStaticRgba16(gdl, 0x8f8f8f8f, 255);
|
|
|
|
for (y = viewtop; y < viewtop + viewheight; y += 2) {
|
|
gdl = bviewCopyPixels(gdl, fb, y, 5, y, 1.0f, viewleft, viewwidth);
|
|
}
|
|
|
|
return gdl;
|
|
}
|
|
|
|
Gfx *bviewDrawHorizonScanner(Gfx *gdl)
|
|
{
|
|
u16 *fb = viGetBackBuffer();
|
|
s32 viewtop = viGetViewTop();
|
|
s32 viewheight = viGetViewHeight();
|
|
s32 viewwidth = viGetViewWidth();
|
|
s32 viewleft = viGetViewLeft();
|
|
char directiontext[32];
|
|
char hertztext[24];
|
|
char zoomtext[24];
|
|
#if VERSION >= VERSION_NTSC_1_0
|
|
char nametext[52];
|
|
#endif
|
|
f32 lookx = g_Vars.currentplayer->cam_look.x;
|
|
f32 lookz = g_Vars.currentplayer->cam_look.z;
|
|
s32 x;
|
|
s32 y;
|
|
|
|
char directions[][3] = {
|
|
{'n', '\0', '\0'},
|
|
{'n', 'e', '\0'},
|
|
{'e', '\0', '\0'},
|
|
{'s', 'e', '\0'},
|
|
{'s', '\0', '\0'},
|
|
{'s', 'w', '\0'},
|
|
{'w', '\0', '\0'},
|
|
{'n', 'w', '\0'},
|
|
{'n', '\0', '\0'},
|
|
};
|
|
|
|
s32 turnangle = atan2f(-lookx, lookz) * 180.0f / M_PI;
|
|
f32 fovy;
|
|
char arrows[12];
|
|
s32 tmplensheight = 130;
|
|
s32 lenstop;
|
|
s32 lensheight;
|
|
s32 liney;
|
|
s32 scale = 1;
|
|
s32 vsplit = false;
|
|
u32 colour;
|
|
f32 range;
|
|
|
|
var8007f840++;
|
|
|
|
if (var8007f840 >= 2) {
|
|
return gdl;
|
|
}
|
|
|
|
strcpy(var800a41c0, "BinocularViewGfx");
|
|
|
|
if (!PAL && g_ViRes == VIRES_HI) {
|
|
scale = 2;
|
|
}
|
|
|
|
if (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL && PLAYERCOUNT() >= 2) {
|
|
vsplit = true;
|
|
}
|
|
|
|
if (tmplensheight > viewheight - 30) {
|
|
tmplensheight = viewheight - 30;
|
|
}
|
|
|
|
if (((s32)(g_20SecIntervalFrac * 30.0f) & 1) == 1) {
|
|
sprintf(arrows, ">> ");
|
|
} else {
|
|
sprintf(arrows, " >>");
|
|
}
|
|
|
|
lensheight = tmplensheight;
|
|
lenstop = viewtop + (viewheight / 2) - (lensheight / 2);
|
|
|
|
// Black out areas above and below lens
|
|
gdl = textSetPrimColour(gdl, 0x000000ff);
|
|
|
|
gDPFillRectangle(gdl++, viewleft, viewtop, viewleft + viewwidth, lenstop);
|
|
gDPFillRectangle(gdl++, viewleft, lenstop + lensheight, viewleft + viewwidth, viewtop + viewheight);
|
|
|
|
gdl = text0f153838(gdl);
|
|
|
|
// Prepare text buffers
|
|
sprintf(directiontext, "%s %s:%03d", arrows, &directions[(turnangle + 22) / 45], turnangle);
|
|
sprintf(hertztext, "%s %s%s%4.2fh", arrows, "", "", menuGetCosOscFrac(4) * 4.6f + 917.4f);
|
|
|
|
fovy = viGetFovY();
|
|
|
|
if (fovy == 0 || fovy == 60.0f) {
|
|
fovy = 1;
|
|
} else {
|
|
fovy = 60.0f / fovy + 1;
|
|
}
|
|
|
|
sprintf(zoomtext, "%s %s%s%4.2fX", arrows, "", "", fovy);
|
|
|
|
gdl = text0f153628(gdl);
|
|
|
|
// Arrows left of product name
|
|
if (vsplit) {
|
|
x = viewleft + 15 * scale;
|
|
} else {
|
|
x = viewleft + 25 * scale;
|
|
}
|
|
|
|
y = lenstop - 7;
|
|
gdl = textRenderProjected(gdl, &x, &y, arrows,
|
|
g_CharsHandelGothicXs, g_FontHandelGothicXs, 0xffffff7f, viGetWidth(), viGetHeight(), 0, 0);
|
|
|
|
// Product name
|
|
#if VERSION >= VERSION_NTSC_1_0
|
|
strcpy(nametext, " JMBC");
|
|
|
|
if (!vsplit) {
|
|
strcat(nametext, " WIDE BAND");
|
|
}
|
|
|
|
strcat(nametext, " SCANNER\n");
|
|
|
|
gdl = textRenderProjected(gdl, &x, &y, nametext,
|
|
g_CharsHandelGothicXs, g_FontHandelGothicXs, 0xffffff7f, viGetWidth(), viGetHeight(), 0, 0);
|
|
#else
|
|
gdl = textRenderProjected(gdl, &x, &y, " JMBC WIDE BAND SCANNER\n",
|
|
g_CharsHandelGothicXs, g_FontHandelGothicXs, 0xffffff7f, viGetWidth(), viGetHeight(), 0, 0);
|
|
#endif
|
|
|
|
// Hertz
|
|
x = viewleft + 75 * scale;
|
|
y = lenstop + lensheight + 1;
|
|
gdl = textRenderProjected(gdl, &x, &y, hertztext,
|
|
g_CharsHandelGothicXs, g_FontHandelGothicXs, 0xffffff7f, viGetWidth(), viGetHeight(), 0, 0);
|
|
|
|
// Zoom level
|
|
if (vsplit) {
|
|
x = viewleft + 75 * scale;
|
|
y = lenstop + lensheight + 8;
|
|
} else {
|
|
x = viewleft + 150 * scale;
|
|
y = lenstop + lensheight + 1;
|
|
}
|
|
|
|
gdl = textRenderProjected(gdl, &x, &y, zoomtext,
|
|
g_CharsHandelGothicXs, g_FontHandelGothicXs, 0xffffff7f, viGetWidth(), viGetHeight(), 0, 0);
|
|
|
|
// Direction
|
|
if (vsplit) {
|
|
x = viewleft + 75 * scale;
|
|
y = lenstop + lensheight + 15;
|
|
} else {
|
|
x = viewleft + 225 * scale;
|
|
y = lenstop + lensheight + 1;
|
|
}
|
|
|
|
gdl = textRenderProjected(gdl, &x, &y, directiontext,
|
|
g_CharsHandelGothicXs, g_FontHandelGothicXs, 0xffffff7f, viGetWidth(), viGetHeight(), 0, 0);
|
|
gdl = text0f153780(gdl);
|
|
|
|
gDPPipeSync(gdl++);
|
|
|
|
gdl = bviewPrepareStaticRgba16(gdl, 0xffffffff, 255);
|
|
|
|
if (vsplit) {
|
|
vsplit = 14;
|
|
}
|
|
|
|
// Iterate horizontal lines down the lens with a bit extra on top and bottom
|
|
for (liney = lenstop - 9; liney < lenstop + lensheight + vsplit + 9; liney++) {
|
|
if (liney < lenstop + lensheight && liney >= lenstop) {
|
|
// Inside the lens
|
|
if ((liney % 2) == 0) {
|
|
colour = 0x00ffffff;
|
|
} else {
|
|
colour = 0x7fffffff;
|
|
}
|
|
|
|
range = (liney - lenstop - lensheight * 0.5f) / (lensheight * 0.5f);
|
|
|
|
if (range < 0) {
|
|
range = -range;
|
|
}
|
|
|
|
if (range > 1) {
|
|
range = 0;
|
|
}
|
|
|
|
range = (range - 0.75f) * 4.0f;
|
|
|
|
if (range < 0) {
|
|
range = 0;
|
|
}
|
|
|
|
if (range > 0) {
|
|
colour = colourBlend(0x000000ff, colour, range * 255.0f);
|
|
}
|
|
} else {
|
|
// Outside of the lens
|
|
if ((liney % 2) == 0) {
|
|
colour = 0x007f7fff;
|
|
} else {
|
|
colour = 0x7fffffff;
|
|
}
|
|
|
|
range = 0;
|
|
}
|
|
|
|
// Different coloured lines at 1/4 and 3/4 marks in the lens
|
|
if (liney == lenstop + lensheight / 4 || liney == lenstop + lensheight - lensheight / 4) {
|
|
colour = 0xffffffff;
|
|
}
|
|
|
|
gDPSetColor(gdl++, G_SETENVCOLOR, colour);
|
|
|
|
gdl = bviewCopyPixels(gdl, fb, liney, 5, liney, RANDOMFRAC() * range + 1, viewleft, viewwidth);
|
|
}
|
|
|
|
return gdl;
|
|
}
|
|
|
|
/**
|
|
* Draws the black part of the IR scanner, which obscures the edges of the
|
|
* screen and creates the binocular effect.
|
|
*
|
|
* The two circles are "placed" at the 1/3 and 2/3 marks horizontally. The
|
|
* screen is then iterated top to bottom, one line at a time, and draws
|
|
* black rectangles on each line to fill in the area outside the circles.
|
|
*/
|
|
Gfx *bviewDrawIrBinoculars(Gfx *gdl)
|
|
{
|
|
s32 viewheight = viGetViewHeight();
|
|
s32 viewwidth = viGetViewWidth();
|
|
s32 viewtop = viGetViewTop();
|
|
s32 viewleft = viGetViewLeft();
|
|
s32 viewright = viewleft + viewwidth;
|
|
s32 viewbottom = viewtop + viewheight;
|
|
s32 leftx = viewleft + viewwidth / 3;
|
|
s32 rightx = viewleft + (viewwidth * 2) / 3;
|
|
s32 centrey = (viewtop + viewbottom) / 2;
|
|
s32 radius = g_IrBinocularRadius;
|
|
s32 sqradius = radius * radius;
|
|
s32 y;
|
|
u32 stack[2];
|
|
|
|
gDPPipeSync(gdl++);
|
|
gDPSetCycleType(gdl++, G_CYC_1CYCLE);
|
|
gDPSetRenderMode(gdl++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
|
|
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
|
|
gDPSetPrimColor(gdl++, 0, 0, 0x00, 0x00, 0x00, 0xff);
|
|
|
|
for (y = viewtop; y < viewbottom; y++) {
|
|
s32 ytocentre = centrey - y;
|
|
s32 sqytocentre = ytocentre * ytocentre;
|
|
|
|
if (sqytocentre < sqradius) {
|
|
s32 xoffset = (viewwidth / 320.0f) * sqrtf(sqradius - sqytocentre);
|
|
|
|
// Left side
|
|
if (leftx - xoffset > viewleft) {
|
|
gdl = bviewDrawIrRect(gdl, viewleft, y, leftx - xoffset, y + 1);
|
|
}
|
|
|
|
// Middle (top and bottom)
|
|
if (leftx + xoffset < rightx - xoffset) {
|
|
gdl = bviewDrawIrRect(gdl, leftx + xoffset, y, rightx - xoffset, y + 1);
|
|
}
|
|
|
|
// Right side
|
|
if (rightx + xoffset < viewright) {
|
|
gdl = bviewDrawIrRect(gdl, rightx + xoffset, y, viewright, y + 1);
|
|
}
|
|
} else {
|
|
// Very top or bottom - whole line is black
|
|
#if VERSION >= VERSION_NTSC_1_0
|
|
gdl = bviewDrawIrRect(gdl, viewleft, y, viewright, y + 1);
|
|
#else
|
|
gdl = bviewDrawIrRect(gdl, viewleft, y, viewright - 1, y + 1);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return gdl;
|
|
}
|
|
|
|
Gfx *bview0f148b38(Gfx *gdl)
|
|
{
|
|
return gdl;
|
|
}
|
|
|
|
void bviewSetMotionBlur(u32 bluramount)
|
|
{
|
|
var8007f840 = 0;
|
|
var8007f848 = 0;
|
|
var8007f844 = (bluramount << 1) / 3;
|
|
}
|
|
|
|
void bviewClearMotionBlur(void)
|
|
{
|
|
var8007f844 = 0;
|
|
}
|