Files
perfect-dark/src/game/bondview.c
T
2022-11-04 20:39:39 +10:00

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;
}