Zelda64Recomp/patches/ui_patches.c

1524 lines
70 KiB
C

#include "patches.h"
#include "buffers.h"
#include "sys_cfb.h"
#include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h"
// This moves elements towards the screen edges when increased
s32 margin_reduction = 8;
// Modified to enable RT64 extended GBI mode
void Graph_SetNextGfxPool(GraphicsContext* gfxCtx) {
GfxPool* pool = &gGfxPools[gfxCtx->gfxPoolIdx % 2];
gGfxMasterDL = &pool->master;
gSegments[0x0E] = (uintptr_t)gGfxMasterDL;
pool->headMagic = GFXPOOL_HEAD_MAGIC;
pool->tailMagic = GFXPOOL_TAIL_MAGIC;
Graph_InitTHGA(&gfxCtx->polyOpa, pool->polyOpaBuffer, sizeof(pool->polyOpaBuffer));
Graph_InitTHGA(&gfxCtx->polyXlu, pool->polyXluBuffer, sizeof(pool->polyXluBuffer));
Graph_InitTHGA(&gfxCtx->overlay, pool->overlayBuffer, sizeof(pool->overlayBuffer));
Graph_InitTHGA(&gfxCtx->work, pool->workBuffer, sizeof(pool->workBuffer));
Graph_InitTHGA(&gfxCtx->debug, pool->debugBuffer, sizeof(pool->debugBuffer));
gfxCtx->polyOpaBuffer = pool->polyOpaBuffer;
gfxCtx->polyXluBuffer = pool->polyXluBuffer;
gfxCtx->overlayBuffer = pool->overlayBuffer;
gfxCtx->workBuffer = pool->workBuffer;
gfxCtx->debugBuffer = pool->debugBuffer;
gfxCtx->curFrameBuffer = SysCfb_GetFramebuffer(gfxCtx->framebufferIndex % 2);
gSegments[0x0F] = (uintptr_t)gfxCtx->curFrameBuffer;
gfxCtx->zbuffer = SysCfb_GetZBuffer();
gSPBranchList(&gGfxMasterDL->disps[0], pool->polyOpaBuffer);
gSPBranchList(&gGfxMasterDL->disps[1], pool->polyXluBuffer);
gSPBranchList(&gGfxMasterDL->disps[2], pool->overlayBuffer);
gSPBranchList(&gGfxMasterDL->disps[3], pool->workBuffer);
gSPEndDisplayList(&gGfxMasterDL->disps[4]);
gSPBranchList(&gGfxMasterDL->debugDisp[0], pool->debugBuffer);
// Enable RT64 extended GBI mode
OPEN_DISPS(gfxCtx);
gEXEnable(POLY_OPA_DISP++);
// gEXPrint(POLY_OPA_DISP++);
CLOSE_DISPS(gfxCtx);
}
// Adjusts an x-coordinate to the relative to be given origin
s16 adjust_x(s16 xPos, u32 origin) {
switch (origin) {
default:
return xPos - margin_reduction;
case G_EX_ORIGIN_RIGHT:
return xPos - SCREEN_WIDTH + margin_reduction;
case G_EX_ORIGIN_CENTER:
return xPos - (SCREEN_WIDTH / 2);
}
}
// Adjusts an x-coordinate with 2 fractional bits to be relative to the given origin
s16 adjust_x_fractional(s16 xPos, u32 origin) {
switch (origin) {
default:
return xPos - (margin_reduction << 2);
case G_EX_ORIGIN_RIGHT:
return xPos - (SCREEN_WIDTH << 2) + (margin_reduction << 2);
case G_EX_ORIGIN_CENTER:
return xPos - ((SCREEN_WIDTH / 2) << 2);
}
}
typedef enum {
Y_ORIGIN_TOP,
Y_ORIGIN_CENTER,
Y_ORIGIN_BOTTOM
} YOrigin;
// Adjusts a top y-coordinate to be relative to the given origin
s16 adjust_y(s16 yPos, YOrigin origin) {
switch (origin) {
default:
return yPos - margin_reduction;
case Y_ORIGIN_CENTER:
return yPos;
case Y_ORIGIN_BOTTOM:
return yPos + margin_reduction;
}
}
// Adjusts a y-coordinate with 2 fractional bits to be relative to the given origin
s16 adjust_y_fractional(s16 yPos, YOrigin origin) {
switch (origin) {
default:
return yPos - (margin_reduction << 2);
case Y_ORIGIN_CENTER:
return yPos;
case Y_ORIGIN_BOTTOM:
return yPos + (margin_reduction << 2);
}
}
/**
* Draw an IA8 texture on a rectangle with a shadow slightly offset to the bottom-right
*
* @param gfx the display list pointer
* @param texture
* @param textureWidth texture image width in texels
* @param textureHeight texture image height in texels
* @param rectLeft the x-coordinate of upper-left corner of rectangle
* @param rectTop the y-coordinate of upper-left corner of rectangle
* @param rectWidth rectangle width in texels
* @param rectHeight rectangle height in texels
* @param dsdx the change in s for each change in x (s5.10)
* @param dtdy the change in t for each change in y (s5.10)
* @param r texture red
* @param g texture green
* @param b texture blue
* @param a texture alpha
* @return Gfx* the display list pointer
*/
Gfx* GfxEx_DrawTexRectIA8_DropShadow(Gfx* gfx, TexturePtr texture, s16 textureWidth, s16 textureHeight, s16 rectLeft,
s16 rectTop, s16 rectWidth, s16 rectHeight, u16 dsdx, u16 dtdy, s16 r, s16 g, s16 b,
s16 a, u32 origin_x, u32 origin_y) {
s16 dropShadowAlpha = a;
if (a > 100) {
dropShadowAlpha = 100;
}
rectLeft = adjust_x(rectLeft, origin_x);
rectTop = adjust_x(rectTop, origin_y);
gDPPipeSync(gfx++);
gDPSetPrimColor(gfx++, 0, 0, 0, 0, 0, dropShadowAlpha);
gDPLoadTextureBlock(gfx++, texture, G_IM_FMT_IA, G_IM_SIZ_8b, textureWidth, textureHeight, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
gEXTextureRectangle(gfx++, origin_x, origin_x, (rectLeft + 2) * 4, (rectTop + 2) * 4, (rectLeft + rectWidth + 2) * 4,
(rectTop + rectHeight + 2) * 4, G_TX_RENDERTILE, 0, 0, dsdx, dtdy);
gDPPipeSync(gfx++);
gDPSetPrimColor(gfx++, 0, 0, r, g, b, a);
gEXTextureRectangle(gfx++, origin_x, origin_x, rectLeft * 4, rectTop * 4, (rectLeft + rectWidth) * 4, (rectTop + rectHeight) * 4,
G_TX_RENDERTILE, 0, 0, dsdx, dtdy);
return gfx;
}
/**
* Draw a colored rectangle with a shadow slightly offset to the bottom-right
*
* @param gfx the display list pointer
* @param rectLeft the x-coordinate of upper-left corner of rectangle
* @param rectTop the y-coordinate of upper-left corner of rectangle
* @param rectWidth rectangle width in texels
* @param rectHeight rectangle height in texels
* @param dsdx the change in s for each change in x (s5.10)
* @param dtdy the change in t for each change in y (s5.10)
* @param r // rectangle red
* @param g // rectangle green
* @param b // rectangle blue
* @param a // rectangle alpha
* @return Gfx* the display list pointer
*/
Gfx* GfxEx_DrawRect_DropShadow(Gfx* gfx, s16 rectLeft, s16 rectTop, s16 rectWidth, s16 rectHeight, u16 dsdx, u16 dtdy,
s16 r, s16 g, s16 b, s16 a, u32 origin_x, u32 origin_y) {
s16 dropShadowAlpha = a;
if (a > 100) {
dropShadowAlpha = 100;
}
rectLeft = adjust_x(rectLeft, origin_x);
rectTop = adjust_x(rectTop, origin_y);
gDPPipeSync(gfx++);
gDPSetPrimColor(gfx++, 0, 0, 0, 0, 0, dropShadowAlpha);
gEXTextureRectangle(gfx++, origin_x, origin_x, (rectLeft + 2) * 4, (rectTop + 2) * 4, (rectLeft + rectWidth + 2) * 4,
(rectTop + rectHeight + 2) * 4, G_TX_RENDERTILE, 0, 0, dsdx, dtdy);
gDPPipeSync(gfx++);
gDPSetPrimColor(gfx++, 0, 0, r, g, b, a);
gEXTextureRectangle(gfx++, origin_x, origin_x, rectLeft * 4, rectTop * 4, (rectLeft + rectWidth) * 4, (rectTop + rectHeight) * 4,
G_TX_RENDERTILE, 0, 0, dsdx, dtdy);
return gfx;
}
/**
* Draw an IA8 texture on a rectangle with a shadow slightly offset to the bottom-right with additional texture offsets
*
* @param gfx the display list pointer
* @param texture
* @param textureWidth texture image width in texels
* @param textureHeight texture image height in texels
* @param rectLeft the x-coordinate of upper-left corner of rectangle
* @param rectTop the y-coordinate of upper-left corner of rectangle
* @param rectWidth rectangle width in texels
* @param rectHeight rectangle height in texels
* @param dsdx the change in s for each change in x (s5.10)
* @param dtdy the change in t for each change in y (s5.10)
* @param r // texture red
* @param g // texture green
* @param b // texture blue
* @param a // texture alpha
* @param masks specify the mask for the s axis
* @param rects the texture coordinate s of upper-left corner of rectangle (s10.5)
* @return Gfx* the display list pointer
*/
Gfx* GfxEx_DrawTexRectIA8_DropShadowOffset(Gfx* gfx, TexturePtr texture, s16 textureWidth, s16 textureHeight,
s16 rectLeft, s16 rectTop, s16 rectWidth, s16 rectHeight, u16 dsdx, u16 dtdy,
s16 r, s16 g, s16 b, s16 a, s32 masks, s32 rects, u32 origin_x, u32 origin_y) {
s16 dropShadowAlpha = a;
if (a > 100) {
dropShadowAlpha = 100;
}
rectLeft = adjust_x(rectLeft, origin_x);
rectTop = adjust_x(rectTop, origin_y);
gDPPipeSync(gfx++);
gDPSetPrimColor(gfx++, 0, 0, 0, 0, 0, dropShadowAlpha);
gDPLoadTextureBlock(gfx++, texture, G_IM_FMT_IA, G_IM_SIZ_8b, textureWidth, textureHeight, 0,
G_TX_MIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, masks, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
gEXTextureRectangle(gfx++, origin_x, origin_x, (rectLeft + 2) * 4, (rectTop + 2) * 4, (rectLeft + rectWidth + 2) * 4,
(rectTop + rectHeight + 2) * 4, G_TX_RENDERTILE, rects, 0, dsdx, dtdy);
gDPPipeSync(gfx++);
gDPSetPrimColor(gfx++, 0, 0, r, g, b, a);
gEXTextureRectangle(gfx++, origin_x, origin_x, rectLeft * 4, rectTop * 4, (rectLeft + rectWidth) * 4, (rectTop + rectHeight) * 4,
G_TX_RENDERTILE, rects, 0, dsdx, dtdy);
return gfx;
}
/**
* Draw an IA8 texture on a rectangle
*
* @param gfx the display list pointer
* @param texture
* @param textureWidth texture image width in texels
* @param textureHeight texture image height in texels
* @param rectLeft the x-coordinate of upper-left corner of rectangle
* @param rectTop the y-coordinate of upper-left corner of rectangle
* @param rectWidth rectangle width in texels
* @param rectHeight rectangle height in texels
* @param dsdx the change in s for each change in x (s5.10)
* @param dtdy the change in t for each change in y (s5.10)
* @return Gfx* the display list pointer
*/
Gfx* GfxEx_DrawTexRectIA8(Gfx* gfx, TexturePtr texture, s16 textureWidth, s16 textureHeight, s16 rectLeft, s16 rectTop,
s16 rectWidth, s16 rectHeight, u16 dsdx, u16 dtdy, u32 origin_x, u32 origin_y) {
gDPLoadTextureBlock(gfx++, texture, G_IM_FMT_IA, G_IM_SIZ_8b, textureWidth, textureHeight, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
rectLeft = adjust_x(rectLeft, origin_x);
rectTop = adjust_y(rectTop, origin_y);
gEXTextureRectangle(gfx++, origin_x, origin_x, rectLeft << 2, rectTop << 2, (rectLeft + rectWidth) << 2, (rectTop + rectHeight) << 2,
G_TX_RENDERTILE, 0, 0, dsdx, dtdy);
return gfx;
}
/**
* Draw an I8 texture on a rectangle
*
* @param gfx the display list pointer
* @param texture
* @param textureWidth texture image width in texels
* @param textureHeight texture image height in texels
* @param rectLeft the x-coordinate of upper-left corner of rectangle
* @param rectTop the y-coordinate of upper-left corner of rectangle
* @param rectWidth rectangle width in texels
* @param rectHeight rectangle height in texels
* @param dsdx the change in s for each change in x (s5.10)
* @param dtdy the change in t for each change in y (s5.10)
* @return Gfx* the display list pointer
*/
Gfx* GfxEx_DrawTexRectI8(Gfx* gfx, TexturePtr texture, s16 textureWidth, s16 textureHeight, s16 rectLeft, s16 rectTop,
s16 rectWidth, s16 rectHeight, u16 dsdx, u16 dtdy, u32 origin_x, u32 origin_y) {
gDPLoadTextureBlock(gfx++, texture, G_IM_FMT_I, G_IM_SIZ_8b, textureWidth, textureHeight, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
rectLeft = adjust_x(rectLeft, origin_x);
rectTop = adjust_y(rectTop, origin_y);
gEXTextureRectangle(gfx++, origin_x, origin_x, rectLeft << 2, rectTop << 2, (rectLeft + rectWidth) << 2, (rectTop + rectHeight) << 2,
G_TX_RENDERTILE, 0, 0, dsdx, dtdy);
return gfx;
}
extern u8 gTatlCUpENGTex[];
extern u8 gTatlCUpGERTex[];
extern u8 gTatlCUpFRATex[];
extern u8 gTatlCUpESPTex[];
extern u8 gButtonBackgroundTex[];
extern s16 D_801BF9D4[];
extern s16 D_801BF9DC[];
extern s16 D_801BF9E4[];
extern s16 D_801BF9BC[];
extern u8 gAmmoDigit0Tex[];
typedef enum {
/* 0 */ PICTO_BOX_STATE_OFF, // Not using the pictograph
/* 1 */ PICTO_BOX_STATE_LENS, // Looking through the lens of the pictograph
/* 2 */ PICTO_BOX_STATE_SETUP_PHOTO, // Looking at the photo currently taken
/* 3 */ PICTO_BOX_STATE_PHOTO
} PictoBoxState;
extern s16 sPictoState;
extern u16 sCUpInvisible;
extern u16 sCUpTimer;
#define DO_ACTION_TEX_WIDTH 48
#define DO_ACTION_TEX_HEIGHT 16
#define DO_ACTION_TEX_SIZE ((DO_ACTION_TEX_WIDTH * DO_ACTION_TEX_HEIGHT) / 2)
// Modify item button drawing to use the extended GBI texture rectangles for widescreen support
void Interface_DrawItemButtons(PlayState* play) {
static TexturePtr cUpLabelTextures[] = {
gTatlCUpENGTex, gTatlCUpENGTex, gTatlCUpGERTex, gTatlCUpFRATex, gTatlCUpESPTex,
};
static s16 startButtonLeftPos[] = {
// Remnant of OoT
130, 136, 136, 136, 136,
};
static s16 D_801BFAF4[] = {
0x1D, // EQUIP_SLOT_B
0x1B, // EQUIP_SLOT_C_LEFT
0x1B, // EQUIP_SLOT_C_DOWN
0x1B, // EQUIP_SLOT_C_RIGHT
};
InterfaceContext* interfaceCtx = &play->interfaceCtx;
Player* player = GET_PLAYER(play);
PauseContext* pauseCtx = &play->pauseCtx;
MessageContext* msgCtx = &play->msgCtx;
s16 temp; // Used as both an alpha value and a button index
s32 pad;
OPEN_DISPS(play->state.gfxCtx);
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
// B Button Color & Texture
OVERLAY_DISP = GfxEx_DrawTexRectIA8_DropShadow(
OVERLAY_DISP, gButtonBackgroundTex, 0x20, 0x20, D_801BF9D4[EQUIP_SLOT_B], D_801BF9DC[EQUIP_SLOT_B],
D_801BFAF4[EQUIP_SLOT_B], D_801BFAF4[EQUIP_SLOT_B], D_801BF9E4[EQUIP_SLOT_B] * 2, D_801BF9E4[EQUIP_SLOT_B] * 2,
100, 255, 120, interfaceCtx->bAlpha, G_EX_ORIGIN_RIGHT, Y_ORIGIN_TOP);
gDPPipeSync(OVERLAY_DISP++);
// C-Left Button Color & Texture
OVERLAY_DISP = GfxEx_DrawRect_DropShadow(OVERLAY_DISP, D_801BF9D4[EQUIP_SLOT_C_LEFT], D_801BF9DC[EQUIP_SLOT_C_LEFT],
D_801BFAF4[EQUIP_SLOT_C_LEFT], D_801BFAF4[EQUIP_SLOT_C_LEFT],
D_801BF9E4[EQUIP_SLOT_C_LEFT] * 2, D_801BF9E4[EQUIP_SLOT_C_LEFT] * 2, 255,
240, 0, interfaceCtx->cLeftAlpha, G_EX_ORIGIN_RIGHT, Y_ORIGIN_TOP);
// C-Down Button Color & Texture
OVERLAY_DISP = GfxEx_DrawRect_DropShadow(OVERLAY_DISP, D_801BF9D4[EQUIP_SLOT_C_DOWN], D_801BF9DC[EQUIP_SLOT_C_DOWN],
D_801BFAF4[EQUIP_SLOT_C_DOWN], D_801BFAF4[EQUIP_SLOT_C_DOWN],
D_801BF9E4[EQUIP_SLOT_C_DOWN] * 2, D_801BF9E4[EQUIP_SLOT_C_DOWN] * 2, 255,
240, 0, interfaceCtx->cDownAlpha, G_EX_ORIGIN_RIGHT, Y_ORIGIN_TOP);
// C-Right Button Color & Texture
OVERLAY_DISP = GfxEx_DrawRect_DropShadow(OVERLAY_DISP, D_801BF9D4[EQUIP_SLOT_C_RIGHT], D_801BF9DC[EQUIP_SLOT_C_RIGHT],
D_801BFAF4[EQUIP_SLOT_C_RIGHT], D_801BFAF4[EQUIP_SLOT_C_RIGHT],
D_801BF9E4[EQUIP_SLOT_C_RIGHT] * 2, D_801BF9E4[EQUIP_SLOT_C_RIGHT] * 2, 255,
240, 0, interfaceCtx->cRightAlpha, G_EX_ORIGIN_RIGHT, Y_ORIGIN_TOP);
if (!IS_PAUSE_STATE_GAMEOVER) {
if ((play->pauseCtx.state != PAUSE_STATE_OFF) || (play->pauseCtx.debugEditor != DEBUG_EDITOR_NONE)) {
OVERLAY_DISP = GfxEx_DrawRect_DropShadow(OVERLAY_DISP, 0x88, 0x11, 0x16, 0x16, 0x5B6, 0x5B6, 0xFF, 0x82, 0x3C,
interfaceCtx->startAlpha, G_EX_ORIGIN_RIGHT, Y_ORIGIN_TOP);
// Start Button Texture, Color & Label
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->startAlpha);
gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, 0);
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0,
PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0);
gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->doActionSegment + DO_ACTION_TEX_SIZE * 2, G_IM_FMT_IA,
DO_ACTION_TEX_WIDTH, DO_ACTION_TEX_HEIGHT, 0, G_TX_NOMIRROR | G_TX_WRAP,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
gEXTextureRectangle(OVERLAY_DISP++, G_EX_ORIGIN_RIGHT, G_EX_ORIGIN_RIGHT,
adjust_x(126, G_EX_ORIGIN_RIGHT) * 4, adjust_y(21, Y_ORIGIN_TOP) * 4,
adjust_x(181, G_EX_ORIGIN_RIGHT) * 4, adjust_y(39, Y_ORIGIN_TOP) * 4,
G_TX_RENDERTILE, 0, 0, 0x04A6, 0x04A6);
}
}
if (interfaceCtx->tatlCalling && (play->pauseCtx.state == PAUSE_STATE_OFF) &&
(play->pauseCtx.debugEditor == DEBUG_EDITOR_NONE) && (play->csCtx.state == CS_STATE_IDLE) &&
(sPictoState == PICTO_BOX_STATE_OFF)) {
if (sCUpInvisible == 0) {
// C-Up Button Texture, Color & Label (Tatl Text)
gDPPipeSync(OVERLAY_DISP++);
if ((gSaveContext.hudVisibility == HUD_VISIBILITY_NONE) ||
(gSaveContext.hudVisibility == HUD_VISIBILITY_NONE_ALT) ||
(gSaveContext.hudVisibility == HUD_VISIBILITY_A_HEARTS_MAGIC_WITH_OVERWRITE) ||
(msgCtx->msgMode != MSGMODE_NONE)) {
temp = 0;
} else if (player->stateFlags1 & PLAYER_STATE1_200000) {
temp = 70;
} else {
temp = interfaceCtx->aAlpha;
}
OVERLAY_DISP =
GfxEx_DrawRect_DropShadow(OVERLAY_DISP, 0xFE, 0x10, 0x10, 0x10, 0x800, 0x800, 0xFF, 0xF0, 0, temp, G_EX_ORIGIN_RIGHT, Y_ORIGIN_TOP);
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, temp);
gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, 0);
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0,
PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0);
gDPLoadTextureBlock_4b(OVERLAY_DISP++, cUpLabelTextures[gSaveContext.options.language], G_IM_FMT_IA, 32, 12,
0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK,
G_TX_NOLOD, G_TX_NOLOD);
gEXTextureRectangle(OVERLAY_DISP++, G_EX_ORIGIN_RIGHT, G_EX_ORIGIN_RIGHT,
adjust_x(247, G_EX_ORIGIN_RIGHT) * 4, adjust_y(18, Y_ORIGIN_TOP) * 4,
adjust_x(279, G_EX_ORIGIN_RIGHT) * 4, adjust_y(30, Y_ORIGIN_TOP) * 4, G_TX_RENDERTILE, 0, 0, 1 << 10,
1 << 10);
}
sCUpTimer--;
if (sCUpTimer == 0) {
sCUpInvisible ^= 1;
sCUpTimer = 10;
}
}
gDPPipeSync(OVERLAY_DISP++);
// Empty C Button Arrows
for (temp = EQUIP_SLOT_C_LEFT; temp <= EQUIP_SLOT_C_RIGHT; temp++) {
if (GET_CUR_FORM_BTN_ITEM(temp) > 0xF0) {
if (temp == EQUIP_SLOT_C_LEFT) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 240, 0, interfaceCtx->cLeftAlpha);
} else if (temp == EQUIP_SLOT_C_DOWN) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 240, 0, interfaceCtx->cDownAlpha);
} else { // EQUIP_SLOT_C_RIGHT
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 240, 0, interfaceCtx->cRightAlpha);
}
OVERLAY_DISP = GfxEx_DrawTexRectIA8(OVERLAY_DISP, ((u8*)gButtonBackgroundTex + ((32 * 32) * (temp + 1))),
0x20, 0x20, D_801BF9D4[temp], D_801BF9DC[temp], D_801BFAF4[temp],
D_801BFAF4[temp], D_801BF9E4[temp] * 2, D_801BF9E4[temp] * 2, G_EX_ORIGIN_RIGHT, Y_ORIGIN_TOP);
}
}
CLOSE_DISPS(play->state.gfxCtx);
}
// Modify item icon drawing to use the extended GBI texture rectangles for widescreen support
void Interface_DrawItemIconTexture(PlayState* play, TexturePtr texture, s16 button) {
static s16 D_801BFAFC[] = { 30, 24, 24, 24 };
OPEN_DISPS(play->state.gfxCtx);
gDPLoadTextureBlock(OVERLAY_DISP++, texture, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, 0, G_TX_NOMIRROR | G_TX_WRAP,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
gEXTextureRectangle(OVERLAY_DISP++, G_EX_ORIGIN_RIGHT, G_EX_ORIGIN_RIGHT,
adjust_x(D_801BF9D4[button], G_EX_ORIGIN_RIGHT) * 4, adjust_y(D_801BF9DC[button], Y_ORIGIN_TOP) * 4,
adjust_x(D_801BF9D4[button] + D_801BFAFC[button], G_EX_ORIGIN_RIGHT) * 4, adjust_y(D_801BF9DC[button] + D_801BFAFC[button], Y_ORIGIN_TOP) * 4,
G_TX_RENDERTILE, 0, 0, D_801BF9BC[button] << 1, D_801BF9BC[button] << 1);
CLOSE_DISPS(play->state.gfxCtx);
}
// Modify drawing A button for widescreen
extern f32 D_801BF9CC[];
void Interface_SetPerspectiveView(PlayState* play, s32 topY, s32 bottomY, s32 leftX, s32 rightX);
void View_ViewportToVp(Vp* dest, Viewport* src);
void ViewEx_SetScissor(Gfx** gfx, s32 ulx, s32 uly, s32 lrx, s32 lry, u32 lorigin, u32 rorigin) {
Gfx* gfxp = *gfx;
ulx = adjust_x(ulx, lorigin);
lrx = adjust_x(lrx, rorigin);
gEXSetScissor(gfxp++, G_SC_NON_INTERLACE, lorigin, rorigin, ulx, uly, lrx, lry);
*gfx = gfxp;
}
void View_SetScissor(Gfx** gfx, s32 ulx, s32 uly, s32 lrx, s32 lry);
/**
* Apply scissor, viewport, view and projection (perspective) to OVERLAY_DISP.
*/
s32 ViewEx_ApplyPerspectiveToOverlay(View* view, u32 origin_x, u32 origin_y) {
f32 aspect;
s32 width;
s32 height;
Vp* vp;
Mtx* projection;
Mtx* viewing;
GraphicsContext* gfxCtx;
s32 pad;
gfxCtx = view->gfxCtx;
OPEN_DISPS(gfxCtx);
vp = GRAPH_ALLOC(gfxCtx, sizeof(Vp));
View_ViewportToVp(vp, &view->viewport);
view->vp = *vp;
gDPPipeSync(OVERLAY_DISP++);
{
s32 pad;
Gfx* overlay;
overlay = OVERLAY_DISP;
ViewEx_SetScissor(&overlay, view->viewport.leftX, view->viewport.topY, view->viewport.rightX,
view->viewport.bottomY, origin_x, origin_x);
OVERLAY_DISP = overlay;
}
vp->vp.vtrans[0] = adjust_x_fractional(vp->vp.vtrans[0], origin_x);
vp->vp.vtrans[1] = adjust_y_fractional(vp->vp.vtrans[1], origin_y);
gEXViewport(OVERLAY_DISP++, origin_x, vp);
projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
view->projectionPtr = projection;
width = view->viewport.rightX - view->viewport.leftX;
height = view->viewport.bottomY - view->viewport.topY;
aspect = (f32)width / (f32)height;
guPerspective(projection, &view->perspNorm, view->fovy, aspect, view->zNear, view->zFar, view->scale);
view->projection = *projection;
gSPPerspNormalize(OVERLAY_DISP++, view->perspNorm);
gSPMatrix(OVERLAY_DISP++, projection, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
viewing = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
view->viewingPtr = viewing;
// This check avoids a divide-by-zero in guLookAt if eye == at
if (view->eye.x == view->at.x && view->eye.y == view->at.y && view->eye.z == view->at.z) {
view->eye.z += 2.0f;
}
guLookAt(viewing, view->eye.x, view->eye.y, view->eye.z, view->at.x, view->at.y, view->at.z, view->up.x, view->up.y,
view->up.z);
view->viewing = *viewing;
gSPMatrix(OVERLAY_DISP++, viewing, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
CLOSE_DISPS(gfxCtx);
return 1;
}
void InterfaceEx_SetPerspectiveView(PlayState* play, s32 topY, s32 bottomY, s32 leftX, s32 rightX, u32 origin_x, u32 origin_y) {
InterfaceContext* interfaceCtx = &play->interfaceCtx;
Vec3f eye;
Vec3f at;
Vec3f up;
eye.x = eye.y = eye.z = 0.0f;
at.x = at.y = 0.0f;
at.z = -1.0f;
up.x = up.z = 0.0f;
up.y = 1.0f;
View_LookAt(&interfaceCtx->view, &eye, &at, &up);
interfaceCtx->viewport.topY = topY;
interfaceCtx->viewport.bottomY = bottomY;
interfaceCtx->viewport.leftX = leftX;
interfaceCtx->viewport.rightX = rightX;
View_SetViewport(&interfaceCtx->view, &interfaceCtx->viewport);
View_SetPerspective(&interfaceCtx->view, 60.0f, 10.0f, 60.0f);
ViewEx_ApplyPerspectiveToOverlay(&interfaceCtx->view, origin_x, origin_y);
}
void Interface_DrawAButton(PlayState* play) {
InterfaceContext* interfaceCtx = &play->interfaceCtx;
s16 aAlpha;
OPEN_DISPS(play->state.gfxCtx);
aAlpha = interfaceCtx->aAlpha;
if (aAlpha > 100) {
aAlpha = 100;
}
Gfx_SetupDL42_Overlay(play->state.gfxCtx);
InterfaceEx_SetPerspectiveView(play, 25 + R_A_BTN_Y_OFFSET, 70 + R_A_BTN_Y_OFFSET, 192, 237, G_EX_ORIGIN_RIGHT, Y_ORIGIN_TOP);
gSPClearGeometryMode(OVERLAY_DISP++, G_CULL_BOTH);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
gDPSetAlphaCompare(OVERLAY_DISP++, G_AC_THRESHOLD);
Matrix_Translate(0.0f, 0.0f, -38.0f, MTXMODE_NEW);
Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_APPLY);
Matrix_RotateXFApply(interfaceCtx->aButtonRoll / 10000.0f);
// Draw A button Shadow
gSPMatrix(OVERLAY_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gDPPipeSync(OVERLAY_DISP++);
gSPVertex(OVERLAY_DISP++, &interfaceCtx->actionVtx[4], 4, 0);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 0, 0, aAlpha);
OVERLAY_DISP = Gfx_DrawTexQuadIA8(OVERLAY_DISP, gButtonBackgroundTex, 32, 32, 0);
// Draw A Button Colored
gDPPipeSync(OVERLAY_DISP++);
InterfaceEx_SetPerspectiveView(play, 23 + R_A_BTN_Y_OFFSET, 68 + R_A_BTN_Y_OFFSET, 190, 235, G_EX_ORIGIN_RIGHT, Y_ORIGIN_TOP);
gSPVertex(OVERLAY_DISP++, &interfaceCtx->actionVtx[0], 4, 0);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 100, 200, 255, interfaceCtx->aAlpha);
gSP1Quadrangle(OVERLAY_DISP++, 0, 2, 3, 1, 0);
// Draw A Button Do-Action
gDPPipeSync(OVERLAY_DISP++);
InterfaceEx_SetPerspectiveView(play, 23 + R_A_BTN_Y_OFFSET, 68 + R_A_BTN_Y_OFFSET, 190, 235, G_EX_ORIGIN_RIGHT, Y_ORIGIN_TOP);
gSPSetGeometryMode(OVERLAY_DISP++, G_CULL_BACK);
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE,
ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->aAlpha);
gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, 0);
Matrix_Translate(0.0f, 0.0f, D_801BF9CC[gSaveContext.options.language] / 10.0f, MTXMODE_NEW);
Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_APPLY);
Matrix_RotateXFApply(interfaceCtx->aButtonRoll / 10000.0f);
gSPMatrix(OVERLAY_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPVertex(OVERLAY_DISP++, &interfaceCtx->actionVtx[8], 4, 0);
// Draw Action Label
if (((interfaceCtx->aButtonState <= A_BTN_STATE_1) || (interfaceCtx->aButtonState == A_BTN_STATE_3))) {
OVERLAY_DISP = Gfx_DrawTexQuad4b(OVERLAY_DISP, interfaceCtx->doActionSegment, 3, DO_ACTION_TEX_WIDTH,
DO_ACTION_TEX_HEIGHT, 0);
} else {
OVERLAY_DISP = Gfx_DrawTexQuad4b(OVERLAY_DISP, interfaceCtx->doActionSegment + DO_ACTION_TEX_SIZE, 3,
DO_ACTION_TEX_WIDTH, DO_ACTION_TEX_HEIGHT, 0);
}
CLOSE_DISPS(play->state.gfxCtx);
}
extern s16 D_801BFB04[];
extern s16 D_801BFB0C[];
// Modify item ammo count drawing to use the extended GBI texture rectangles for widescreen support
void Interface_DrawAmmoCount(PlayState* play, s16 button, s16 alpha) {
u8 i;
u16 ammo;
OPEN_DISPS(play->state.gfxCtx);
i = ((void)0, GET_CUR_FORM_BTN_ITEM(button));
if ((i == ITEM_DEKU_STICK) || (i == ITEM_DEKU_NUT) || (i == ITEM_BOMB) || (i == ITEM_BOW) ||
((i >= ITEM_BOW_FIRE) && (i <= ITEM_BOW_LIGHT)) || (i == ITEM_BOMBCHU) || (i == ITEM_POWDER_KEG) ||
(i == ITEM_MAGIC_BEANS) || (i == ITEM_PICTOGRAPH_BOX)) {
if ((i >= ITEM_BOW_FIRE) && (i <= ITEM_BOW_LIGHT)) {
i = ITEM_BOW;
}
ammo = AMMO(i);
if (i == ITEM_PICTOGRAPH_BOX) {
if (!CHECK_QUEST_ITEM(QUEST_PICTOGRAPH)) {
ammo = 0;
} else {
ammo = 1;
}
}
gDPPipeSync(OVERLAY_DISP++);
if ((button == EQUIP_SLOT_B) && (gSaveContext.minigameStatus == MINIGAME_STATUS_ACTIVE)) {
ammo = play->interfaceCtx.minigameAmmo;
} else if ((button == EQUIP_SLOT_B) && (play->unk_1887C > 1)) {
ammo = play->unk_1887C - 1;
} else if (((i == ITEM_BOW) && (AMMO(i) == CUR_CAPACITY(UPG_QUIVER))) ||
((i == ITEM_BOMB) && (AMMO(i) == CUR_CAPACITY(UPG_BOMB_BAG))) ||
((i == ITEM_DEKU_STICK) && (AMMO(i) == CUR_CAPACITY(UPG_DEKU_STICKS))) ||
((i == ITEM_DEKU_NUT) && (AMMO(i) == CUR_CAPACITY(UPG_DEKU_NUTS))) ||
((i == ITEM_BOMBCHU) && (AMMO(i) == CUR_CAPACITY(UPG_BOMB_BAG))) ||
((i == ITEM_POWDER_KEG) && (ammo == 1)) || ((i == ITEM_PICTOGRAPH_BOX) && (ammo == 1)) ||
((i == ITEM_MAGIC_BEANS) && (ammo == 20))) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 120, 255, 0, alpha);
}
if ((u32)ammo == 0) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 100, 100, 100, alpha);
}
for (i = 0; ammo >= 10; i++) {
ammo -= 10;
}
// Draw upper digit (tens)
if ((u32)i != 0) {
OVERLAY_DISP = GfxEx_DrawTexRectIA8(OVERLAY_DISP, ((u8*)gAmmoDigit0Tex + ((8 * 8) * i)), 8, 8,
D_801BFB04[button], D_801BFB0C[button], 8, 8, 1 << 10, 1 << 10, G_EX_ORIGIN_RIGHT, Y_ORIGIN_TOP);
}
// Draw lower digit (ones)
OVERLAY_DISP = GfxEx_DrawTexRectIA8(OVERLAY_DISP, ((u8*)gAmmoDigit0Tex + ((8 * 8) * ammo)), 8, 8,
D_801BFB04[button] + 6, D_801BFB0C[button], 8, 8, 1 << 10, 1 << 10, G_EX_ORIGIN_RIGHT, Y_ORIGIN_TOP);
}
CLOSE_DISPS(play->state.gfxCtx);
}
// Modify magic meter drawing
extern u8 gMagicMeterEndTex[];
extern u8 gMagicMeterFillTex[];
extern u8 gMagicMeterMidTex[];
extern s16 sMagicMeterOutlinePrimBlue;
extern s16 sMagicMeterOutlinePrimGreen;
extern s16 sMagicMeterOutlinePrimRed;
void Magic_DrawMeter(PlayState* play) {
InterfaceContext* interfaceCtx = &play->interfaceCtx;
s16 magicBarY;
OPEN_DISPS(play->state.gfxCtx);
if (gSaveContext.save.saveInfo.playerData.magicLevel != 0) {
if (gSaveContext.save.saveInfo.playerData.healthCapacity > 0xA0) {
magicBarY = 42; // two rows of hearts
} else {
magicBarY = 34; // one row of hearts
}
Gfx_SetupDL39_Overlay(play->state.gfxCtx);
gDPSetEnvColor(OVERLAY_DISP++, 100, 50, 50, 255);
OVERLAY_DISP = GfxEx_DrawTexRectIA8_DropShadow(
OVERLAY_DISP, gMagicMeterEndTex, 8, 16, 18, magicBarY, 8, 16, 1 << 10, 1 << 10, sMagicMeterOutlinePrimRed,
sMagicMeterOutlinePrimGreen, sMagicMeterOutlinePrimBlue, interfaceCtx->magicAlpha, G_EX_ORIGIN_LEFT, Y_ORIGIN_TOP);
OVERLAY_DISP = GfxEx_DrawTexRectIA8_DropShadow(OVERLAY_DISP, gMagicMeterMidTex, 24, 16, 26, magicBarY,
((void)0, gSaveContext.magicCapacity), 16, 1 << 10, 1 << 10,
sMagicMeterOutlinePrimRed, sMagicMeterOutlinePrimGreen,
sMagicMeterOutlinePrimBlue, interfaceCtx->magicAlpha, G_EX_ORIGIN_LEFT, Y_ORIGIN_TOP);
OVERLAY_DISP = GfxEx_DrawTexRectIA8_DropShadowOffset(
OVERLAY_DISP, gMagicMeterEndTex, 8, 16, ((void)0, gSaveContext.magicCapacity) + 26, magicBarY, 8, 16,
1 << 10, 1 << 10, sMagicMeterOutlinePrimRed, sMagicMeterOutlinePrimGreen, sMagicMeterOutlinePrimBlue,
interfaceCtx->magicAlpha, 3, 0x100, G_EX_ORIGIN_LEFT, Y_ORIGIN_TOP);
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, 0, 0, 0, PRIMITIVE, PRIMITIVE,
ENVIRONMENT, TEXEL0, ENVIRONMENT, 0, 0, 0, PRIMITIVE);
gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, 255);
if (gSaveContext.magicState == MAGIC_STATE_METER_FLASH_2) {
// Yellow part of the meter indicating the amount of magic to be subtracted
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 250, 250, 0, interfaceCtx->magicAlpha);
gDPLoadTextureBlock_4b(OVERLAY_DISP++, gMagicMeterFillTex, G_IM_FMT_I, 16, 16, 0, G_TX_NOMIRROR | G_TX_WRAP,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
gEXTextureRectangle(OVERLAY_DISP++, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT,
adjust_x(26, G_EX_ORIGIN_LEFT) * 4, adjust_y(magicBarY + 3, Y_ORIGIN_TOP) << 2,
adjust_x(gSaveContext.save.saveInfo.playerData.magic + 26, G_EX_ORIGIN_LEFT) * 4, adjust_y(magicBarY + 10, Y_ORIGIN_TOP) << 2,
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
// Fill the rest of the meter with the normal magic color
gDPPipeSync(OVERLAY_DISP++);
if (CHECK_WEEKEVENTREG(WEEKEVENTREG_DRANK_CHATEAU_ROMANI)) {
// Blue magic
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 0, 200, interfaceCtx->magicAlpha);
} else {
// Green magic (default)
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 200, 0, interfaceCtx->magicAlpha);
}
gEXTextureRectangle(
OVERLAY_DISP++, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT,
adjust_x(26, G_EX_ORIGIN_LEFT) * 4, adjust_y(magicBarY + 3, Y_ORIGIN_TOP) << 2,
adjust_x(gSaveContext.save.saveInfo.playerData.magic - gSaveContext.magicToConsume + 26, G_EX_ORIGIN_LEFT) * 4, adjust_y(magicBarY + 10, Y_ORIGIN_TOP) << 2,
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
} else {
// Fill the whole meter with the normal magic color
if (CHECK_WEEKEVENTREG(WEEKEVENTREG_DRANK_CHATEAU_ROMANI)) {
// Blue magic
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 0, 200, interfaceCtx->magicAlpha);
} else {
// Green magic (default)
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 200, 0, interfaceCtx->magicAlpha);
}
gDPLoadTextureBlock_4b(OVERLAY_DISP++, gMagicMeterFillTex, G_IM_FMT_I, 16, 16, 0, G_TX_NOMIRROR | G_TX_WRAP,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
gEXTextureRectangle(OVERLAY_DISP++, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT,
adjust_x(26, G_EX_ORIGIN_LEFT) * 4, adjust_y(magicBarY + 3, Y_ORIGIN_TOP) << 2,
adjust_x(gSaveContext.save.saveInfo.playerData.magic + 26, G_EX_ORIGIN_LEFT) * 4, adjust_y(magicBarY + 10, Y_ORIGIN_TOP) << 2,
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
}
}
CLOSE_DISPS(play->state.gfxCtx);
}
// Modify life meter drawing
extern u8 gHeartEmptyTex[];
extern u8 gHeartFullTex[];
extern u8 gHeartHalfTex[];
extern u8 gHeartQuarterTex[];
extern u8 gHeartShapeTex[];
extern u8 gHeartThreeQuarterTex[];
static TexturePtr sHeartTextures[] = {
gHeartFullTex, gHeartQuarterTex, gHeartQuarterTex, gHeartQuarterTex,
gHeartQuarterTex, gHeartQuarterTex, gHeartHalfTex, gHeartHalfTex,
gHeartHalfTex, gHeartHalfTex, gHeartHalfTex, gHeartThreeQuarterTex,
gHeartThreeQuarterTex, gHeartThreeQuarterTex, gHeartThreeQuarterTex, gHeartThreeQuarterTex,
};
extern u8 gDefenseHeartEmptyTex[];
extern u8 gDefenseHeartFullTex[];
extern u8 gDefenseHeartHalfTex[];
extern u8 gDefenseHeartQuarterTex[];
extern u8 gDefenseHeartThreeQuarterTex[];
static TexturePtr sHeartDDTextures[] = {
gDefenseHeartFullTex, gDefenseHeartQuarterTex, gDefenseHeartQuarterTex,
gDefenseHeartQuarterTex, gDefenseHeartQuarterTex, gDefenseHeartQuarterTex,
gDefenseHeartHalfTex, gDefenseHeartHalfTex, gDefenseHeartHalfTex,
gDefenseHeartHalfTex, gDefenseHeartHalfTex, gDefenseHeartThreeQuarterTex,
gDefenseHeartThreeQuarterTex, gDefenseHeartThreeQuarterTex, gDefenseHeartThreeQuarterTex,
gDefenseHeartThreeQuarterTex,
};
extern s16 sBeatingHeartsDDPrim[3];
extern s16 sBeatingHeartsDDEnv[3];
extern s16 sHeartsDDPrim[2][3];
extern s16 sHeartsDDEnv[2][3];
void LifeMeter_Draw(PlayState* play) {
s32 pad[5];
TexturePtr heartTex;
s32 curColorSet;
f32 offsetX;
f32 offsetY;
s32 i;
f32 posY;
f32 posX;
f32 halfTexSize;
f32 temp_f4;
GraphicsContext* gfxCtx = play->state.gfxCtx;
InterfaceContext* interfaceCtx = &play->interfaceCtx;
Vtx* beatingHeartVtx = interfaceCtx->beatingHeartVtx;
s32 fractionHeartCount = gSaveContext.save.saveInfo.playerData.health % 0x10;
s16 healthCapacity = gSaveContext.save.saveInfo.playerData.healthCapacity / 0x10;
s16 fullHeartCount = gSaveContext.save.saveInfo.playerData.health / 0x10;
s32 pad2;
f32 lifesize = interfaceCtx->lifeSizeChange * 0.1f;
u32 curCombineModeSet = 0;
TexturePtr temp = NULL;
s32 ddCount = gSaveContext.save.saveInfo.inventory.defenseHearts - 1;
OPEN_DISPS(gfxCtx);
if ((gSaveContext.save.saveInfo.playerData.health % 0x10) == 0) {
fullHeartCount--;
}
offsetY = 0.0f;
offsetX = 0.0f;
curColorSet = -1;
for (i = 0; i < healthCapacity; i++) {
if ((ddCount < 0) || (ddCount < i)) {
if (i < fullHeartCount) {
if (curColorSet != 0) {
curColorSet = 0;
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, interfaceCtx->heartsPrimR[0], interfaceCtx->heartsPrimG[0],
interfaceCtx->heartsPrimB[0], interfaceCtx->healthAlpha);
gDPSetEnvColor(OVERLAY_DISP++, interfaceCtx->heartsEnvR[0], interfaceCtx->heartsEnvG[0],
interfaceCtx->heartsEnvB[0], 255);
}
} else if (i == fullHeartCount) {
if (curColorSet != 1) {
curColorSet = 1;
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, interfaceCtx->beatingHeartPrim[0],
interfaceCtx->beatingHeartPrim[1], interfaceCtx->beatingHeartPrim[2],
interfaceCtx->healthAlpha);
gDPSetEnvColor(OVERLAY_DISP++, interfaceCtx->beatingHeartEnv[0], interfaceCtx->beatingHeartEnv[1],
interfaceCtx->beatingHeartEnv[2], 255);
}
} else if (fullHeartCount < i) {
if (curColorSet != 2) {
curColorSet = 2;
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, interfaceCtx->heartsPrimR[0], interfaceCtx->heartsPrimG[0],
interfaceCtx->heartsPrimB[0], interfaceCtx->healthAlpha);
gDPSetEnvColor(OVERLAY_DISP++, interfaceCtx->heartsEnvR[0], interfaceCtx->heartsEnvG[0],
interfaceCtx->heartsEnvB[0], 255);
}
} else {
if (curColorSet != 3) {
curColorSet = 3;
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, interfaceCtx->heartsPrimR[1], interfaceCtx->heartsPrimG[1],
interfaceCtx->heartsPrimB[1], interfaceCtx->healthAlpha);
gDPSetEnvColor(OVERLAY_DISP++, interfaceCtx->heartsEnvR[1], interfaceCtx->heartsEnvG[1],
interfaceCtx->heartsEnvB[1], 255);
}
}
if (i < fullHeartCount) {
heartTex = gHeartFullTex;
} else if (i == fullHeartCount) {
heartTex = sHeartTextures[fractionHeartCount];
} else {
heartTex = gHeartEmptyTex;
}
} else {
if (i < fullHeartCount) {
if (curColorSet != 4) {
curColorSet = 4;
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, sHeartsDDPrim[0][0], sHeartsDDPrim[0][1], sHeartsDDPrim[0][2],
interfaceCtx->healthAlpha);
gDPSetEnvColor(OVERLAY_DISP++, sHeartsDDEnv[0][0], sHeartsDDEnv[0][1], sHeartsDDEnv[0][2], 255);
}
} else if (i == fullHeartCount) {
if (curColorSet != 5) {
curColorSet = 5;
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, sBeatingHeartsDDPrim[0], sBeatingHeartsDDPrim[1],
sBeatingHeartsDDPrim[2], interfaceCtx->healthAlpha);
gDPSetEnvColor(OVERLAY_DISP++, sBeatingHeartsDDEnv[0], sBeatingHeartsDDEnv[1],
sBeatingHeartsDDEnv[2], 255);
}
} else if (i > fullHeartCount) {
if (curColorSet != 6) {
curColorSet = 6;
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, sHeartsDDPrim[0][0], sHeartsDDPrim[0][1], sHeartsDDPrim[0][2],
interfaceCtx->healthAlpha);
gDPSetEnvColor(OVERLAY_DISP++, sHeartsDDEnv[0][0], sHeartsDDEnv[0][1], sHeartsDDEnv[0][2], 255);
}
} else if (curColorSet != 7) {
curColorSet = 7;
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, sHeartsDDPrim[1][0], sHeartsDDPrim[1][1], sHeartsDDPrim[1][2],
interfaceCtx->healthAlpha);
gDPSetEnvColor(OVERLAY_DISP++, sHeartsDDEnv[1][0], sHeartsDDEnv[1][1], sHeartsDDEnv[1][2], 255);
}
if (i < fullHeartCount) {
heartTex = gDefenseHeartFullTex;
} else if (i == fullHeartCount) {
heartTex = sHeartDDTextures[fractionHeartCount];
} else {
heartTex = gDefenseHeartEmptyTex;
}
}
if (temp != heartTex) {
temp = heartTex;
gDPLoadTextureBlock(OVERLAY_DISP++, heartTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 16, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK,
G_TX_NOLOD, G_TX_NOLOD);
}
if (i != fullHeartCount) {
if ((ddCount < 0) || (i > ddCount)) {
if (curCombineModeSet != 1) {
curCombineModeSet = 1;
Gfx_SetupDL39_Overlay(gfxCtx);
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE,
0, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0);
}
} else if (curCombineModeSet != 3) {
curCombineModeSet = 3;
Gfx_SetupDL39_Overlay(gfxCtx);
gDPSetCombineLERP(OVERLAY_DISP++, ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0,
ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0);
}
posY = 26.0f + offsetY;
posX = 30.0f + offsetX;
temp_f4 = 1.0f;
temp_f4 /= 0.68f;
temp_f4 *= 1 << 10;
halfTexSize = 8.0f;
halfTexSize *= 0.68f;
gEXTextureRectangle(OVERLAY_DISP++, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT,
adjust_x(posX - halfTexSize, G_EX_ORIGIN_LEFT) * 4, adjust_y(posY - halfTexSize, Y_ORIGIN_TOP) * 4,
adjust_x(posX + halfTexSize, G_EX_ORIGIN_LEFT) * 4, adjust_y(posY + halfTexSize, Y_ORIGIN_TOP) * 4,
G_TX_RENDERTILE, 0, 0, (s32)temp_f4, (s32)temp_f4);
} else {
Mtx* mtx;
if ((ddCount < 0) || (ddCount < i)) {
if (curCombineModeSet != 2) {
curCombineModeSet = 2;
Gfx_SetupDL42_Overlay(gfxCtx);
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE,
0, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0);
gDPSetAlphaCompare(OVERLAY_DISP++, G_AC_THRESHOLD);
}
} else {
if (curCombineModeSet != 4) {
curCombineModeSet = 4;
Gfx_SetupDL42_Overlay(gfxCtx);
gDPSetCombineLERP(OVERLAY_DISP++, ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, TEXEL0, 0, PRIMITIVE,
0, ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0);
gDPSetAlphaCompare(OVERLAY_DISP++, G_AC_THRESHOLD);
}
}
mtx = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
Vp* vp = GRAPH_ALLOC(gfxCtx, sizeof(Vp));
View_ViewportToVp(vp, &play->view.viewport);
vp->vp.vtrans[0] = adjust_x_fractional(vp->vp.vtrans[0], G_EX_ORIGIN_LEFT);
vp->vp.vtrans[1] = adjust_y_fractional(vp->vp.vtrans[1], Y_ORIGIN_TOP);
gEXViewport(OVERLAY_DISP++, G_EX_ORIGIN_LEFT, vp);
Mtx_SetTranslateScaleMtx(mtx, 1.0f - (0.32f * lifesize), 1.0f - (0.32f * lifesize),
1.0f - (0.32f * lifesize), -130.0f + offsetX, 94.5f - offsetY, 0.0f);
gSPMatrix(OVERLAY_DISP++, mtx, G_MTX_LOAD | G_MTX_MODELVIEW);
gSPVertex(OVERLAY_DISP++, beatingHeartVtx, 4, 0);
gSP1Quadrangle(OVERLAY_DISP++, 0, 2, 3, 1, 0);
// Restore the old viewport
Vp* old_vp = GRAPH_ALLOC(gfxCtx, sizeof(Vp));
View_ViewportToVp(old_vp, &play->view.viewport);
gSPViewport(OVERLAY_DISP++, old_vp);
}
offsetX += 10.0f;
if (i == 9) {
offsetY += 10.0f;
offsetX = 0.0f;
}
}
CLOSE_DISPS(gfxCtx);
}
// Modify interface drawing (rupees, key counter, etc.)
extern TexturePtr sStoryTextures[];
extern TexturePtr sStoryTLUTs[];
extern Color_RGB16 sRupeeCounterIconPrimColors[];
extern Color_RGB16 sRupeeCounterIconEnvColors[];
extern u8 gRupeeCounterIconTex[];
extern s16 sRupeeDigitsFirst[];
extern s16 sRupeeDigitsCount[];
extern u8 gSmallKeyCounterIconTex[];
extern u8 gCounterDigit0Tex[];
extern u8 gGoldSkulltulaCounterIconTex[];
extern Color_RGB16 sMinigameCountdownPrimColors[];
extern TexturePtr sMinigameCountdownTextures[];
extern s16 sMinigameCountdownTexWidths[];
extern u8 gPictoBoxFocusBorderTex[];
extern u8 gPictoBoxFocusIconTex[];
extern u8 gPictoBoxFocusTextTex[];
static Gfx sScreenFillSetupDL[] = {
gsDPPipeSync(),
gsSPClearGeometryMode(G_ZBUFFER | G_SHADE | G_CULL_BOTH | G_FOG | G_LIGHTING | G_TEXTURE_GEN |
G_TEXTURE_GEN_LINEAR | G_LOD | G_SHADING_SMOOTH),
gsDPSetOtherMode(G_AD_DISABLE | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_NONE | G_TL_TILE |
G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_1PRIMITIVE,
G_AC_NONE | G_ZS_PIXEL | G_RM_CLD_SURF | G_RM_CLD_SURF2),
gsDPSetCombineMode(G_CC_PRIMITIVE, G_CC_PRIMITIVE),
gsSPEndDisplayList(),
};
void Interface_DrawBButtonIcons(PlayState* play);
void Interface_DrawCButtonIcons(PlayState* play);
void Interface_DrawClock(PlayState* play);
void Interface_DrawMinigameIcons(PlayState* play);
void Interface_DrawPauseMenuEquippingIcons(PlayState* play);
void Interface_DrawPerfectLetters(PlayState* play);
void Interface_DrawTimers(PlayState* play);
void Interface_SetOrthoView(InterfaceContext* interfaceCtx);
void Interface_SetVertices(PlayState* play);
void Interface_Draw(PlayState* play) {
s32 pad;
InterfaceContext* interfaceCtx = &play->interfaceCtx;
Player* player = GET_PLAYER(play);
Gfx* gfx;
s16 sp2CE;
s16 sp2CC;
s16 sp2CA;
s16 sp2C8;
PauseContext* pauseCtx = &play->pauseCtx;
f32 minigameCountdownScale;
s16 counterDigits[4];
s16 magicAlpha;
OPEN_DISPS(play->state.gfxCtx);
gSPSegment(OVERLAY_DISP++, 0x02, interfaceCtx->parameterSegment);
gSPSegment(OVERLAY_DISP++, 0x09, interfaceCtx->doActionSegment);
gSPSegment(OVERLAY_DISP++, 0x08, interfaceCtx->iconItemSegment);
gSPSegment(OVERLAY_DISP++, 0x0B, interfaceCtx->mapSegment);
if (pauseCtx->debugEditor == DEBUG_EDITOR_NONE) {
Interface_SetVertices(play);
Interface_SetOrthoView(interfaceCtx);
// Draw Grandma's Story
if (interfaceCtx->storyDmaStatus == STORY_DMA_DONE) {
gSPSegment(OVERLAY_DISP++, 0x07, interfaceCtx->storySegment);
Gfx_SetupDL39_Opa(play->state.gfxCtx);
gDPSetTextureFilter(POLY_OPA_DISP++, G_TF_POINT);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha);
// Load in Grandma's Story
gSPLoadUcodeL(OVERLAY_DISP++, gspS2DEX2_fifo);
gfx = OVERLAY_DISP;
Prerender_DrawBackground2D(&gfx, sStoryTextures[interfaceCtx->storyType],
sStoryTLUTs[interfaceCtx->storyType], SCREEN_WIDTH, SCREEN_HEIGHT, 2, 1, 0x8000,
0x100, 0.0f, 0.0f, 1.0f, 1.0f, 0);
OVERLAY_DISP = gfx;
gSPLoadUcode(OVERLAY_DISP++, SysUcode_GetUCode(), SysUcode_GetUCodeData());
gDPPipeSync(OVERLAY_DISP++);
// Fill the screen with a black rectangle
gDPSetRenderMode(OVERLAY_DISP++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 0, 0, R_STORY_FILL_SCREEN_ALPHA);
gDPFillRectangle(OVERLAY_DISP++, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
}
gEXSetScissor(OVERLAY_DISP++, G_SC_NON_INTERLACE, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_RIGHT, 0, 0, 0, SCREEN_HEIGHT);
LifeMeter_Draw(play);
Gfx_SetupDL39_Overlay(play->state.gfxCtx);
// Draw Rupee Icon
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, sRupeeCounterIconPrimColors[CUR_UPG_VALUE(UPG_WALLET)].r,
sRupeeCounterIconPrimColors[CUR_UPG_VALUE(UPG_WALLET)].g,
sRupeeCounterIconPrimColors[CUR_UPG_VALUE(UPG_WALLET)].b, interfaceCtx->magicAlpha);
gDPSetEnvColor(OVERLAY_DISP++, sRupeeCounterIconEnvColors[CUR_UPG_VALUE(UPG_WALLET)].r,
sRupeeCounterIconEnvColors[CUR_UPG_VALUE(UPG_WALLET)].g,
sRupeeCounterIconEnvColors[CUR_UPG_VALUE(UPG_WALLET)].b, 255);
OVERLAY_DISP =
GfxEx_DrawTexRectIA8(OVERLAY_DISP, gRupeeCounterIconTex, 16, 16, 26, 206, 16, 16, 1 << 10, 1 << 10, G_EX_ORIGIN_LEFT, Y_ORIGIN_BOTTOM);
switch (play->sceneId) {
case SCENE_INISIE_N:
case SCENE_INISIE_R:
case SCENE_MITURIN:
case SCENE_HAKUGIN:
case SCENE_SEA:
if (DUNGEON_KEY_COUNT(gSaveContext.mapIndex) >= 0) {
// Small Key Icon
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 200, 230, 255, interfaceCtx->magicAlpha);
gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 20, 255);
OVERLAY_DISP = GfxEx_DrawTexRectIA8(OVERLAY_DISP, gSmallKeyCounterIconTex, 16, 16, 26, 190, 16, 16,
1 << 10, 1 << 10, G_EX_ORIGIN_LEFT, Y_ORIGIN_BOTTOM);
// Small Key Counter
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineLERP(OVERLAY_DISP++, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE,
TEXEL0, 0, PRIMITIVE, 0);
counterDigits[2] = 0;
counterDigits[3] = DUNGEON_KEY_COUNT(gSaveContext.mapIndex);
while (counterDigits[3] >= 10) {
counterDigits[2]++;
counterDigits[3] -= 10;
}
sp2CA = 42;
if (counterDigits[2] != 0) {
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 0, 0, interfaceCtx->magicAlpha);
OVERLAY_DISP =
GfxEx_DrawTexRectI8(OVERLAY_DISP, (u8*)gCounterDigit0Tex + (8 * 16 * counterDigits[2]), 8, 16,
43, 191, 8, 16, 1 << 10, 1 << 10, G_EX_ORIGIN_LEFT, Y_ORIGIN_BOTTOM);
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->magicAlpha);
gEXTextureRectangle(OVERLAY_DISP++, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT,
adjust_x(42, G_EX_ORIGIN_LEFT) * 4, adjust_y(190, Y_ORIGIN_BOTTOM) * 4,
adjust_x(50, G_EX_ORIGIN_LEFT) * 4, adjust_y(206, Y_ORIGIN_BOTTOM) * 4,
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
sp2CA += 8;
}
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 0, 0, interfaceCtx->magicAlpha);
OVERLAY_DISP = GfxEx_DrawTexRectI8(OVERLAY_DISP, (u8*)gCounterDigit0Tex + (8 * 16 * counterDigits[3]),
8, 16, sp2CA + 1, 191, 8, 16, 1 << 10, 1 << 10, G_EX_ORIGIN_LEFT, Y_ORIGIN_BOTTOM);
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->magicAlpha);
gEXTextureRectangle(OVERLAY_DISP++, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT,
adjust_x(sp2CA, G_EX_ORIGIN_LEFT) * 4, adjust_y(190, Y_ORIGIN_BOTTOM) * 4,
adjust_x(sp2CA + 8, G_EX_ORIGIN_LEFT) * 4, adjust_y(206, Y_ORIGIN_BOTTOM) * 4,
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
}
break;
case SCENE_KINSTA1:
case SCENE_KINDAN2:
// Gold Skulltula Icon
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->magicAlpha);
gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, 255);
gDPLoadTextureBlock(OVERLAY_DISP++, gGoldSkulltulaCounterIconTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 24, 24,
0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK,
G_TX_NOLOD, G_TX_NOLOD);
gEXTextureRectangle(OVERLAY_DISP++, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT,
adjust_x(20, G_EX_ORIGIN_LEFT), adjust_y(187, Y_ORIGIN_BOTTOM) * 4,
adjust_x(44, G_EX_ORIGIN_LEFT), adjust_y(205, Y_ORIGIN_BOTTOM) * 4,
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
// Gold Skulluta Counter
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineLERP(OVERLAY_DISP++, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE,
TEXEL0, 0, PRIMITIVE, 0);
counterDigits[2] = 0;
counterDigits[3] = Inventory_GetSkullTokenCount(play->sceneId);
while (counterDigits[3] >= 10) {
counterDigits[2]++;
counterDigits[3] -= 10;
}
sp2CA = 42;
if (counterDigits[2] != 0) {
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 0, 0, interfaceCtx->magicAlpha);
OVERLAY_DISP = GfxEx_DrawTexRectI8(OVERLAY_DISP, (u8*)gCounterDigit0Tex + (8 * 16 * counterDigits[2]),
8, 16, 43, 191, 8, 16, 1 << 10, 1 << 10, G_EX_ORIGIN_LEFT, Y_ORIGIN_BOTTOM);
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->magicAlpha);
gEXTextureRectangle(OVERLAY_DISP++, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT,
adjust_x(42, G_EX_ORIGIN_LEFT), adjust_y(190, Y_ORIGIN_BOTTOM) * 4,
adjust_x(50, G_EX_ORIGIN_LEFT), adjust_y(206, Y_ORIGIN_BOTTOM) * 4,
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
sp2CA += 8;
}
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 0, 0, interfaceCtx->magicAlpha);
OVERLAY_DISP = GfxEx_DrawTexRectI8(OVERLAY_DISP, (u8*)gCounterDigit0Tex + (8 * 16 * counterDigits[3]), 8,
16, sp2CA + 1, 191, 8, 16, 1 << 10, 1 << 10, G_EX_ORIGIN_LEFT, Y_ORIGIN_BOTTOM);
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->magicAlpha);
gEXTextureRectangle(OVERLAY_DISP++, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT,
adjust_x(sp2CA, G_EX_ORIGIN_LEFT) * 4, adjust_y(190, Y_ORIGIN_BOTTOM) * 4,
adjust_x(sp2CA + 8, G_EX_ORIGIN_LEFT) * 4, adjust_y(206, Y_ORIGIN_BOTTOM) * 4,
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
break;
default:
break;
}
// Rupee Counter
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineLERP(OVERLAY_DISP++, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE, TEXEL0, 0,
PRIMITIVE, 0);
counterDigits[0] = counterDigits[1] = 0;
counterDigits[2] = gSaveContext.save.saveInfo.playerData.rupees;
if ((counterDigits[2] > 9999) || (counterDigits[2] < 0)) {
counterDigits[2] &= 0xDDD;
}
while (counterDigits[2] >= 100) {
counterDigits[0]++;
counterDigits[2] -= 100;
}
while (counterDigits[2] >= 10) {
counterDigits[1]++;
counterDigits[2] -= 10;
}
sp2CC = sRupeeDigitsFirst[CUR_UPG_VALUE(UPG_WALLET)];
sp2C8 = sRupeeDigitsCount[CUR_UPG_VALUE(UPG_WALLET)];
magicAlpha = interfaceCtx->magicAlpha;
if (magicAlpha > 180) {
magicAlpha = 180;
}
for (sp2CE = 0, sp2CA = 42; sp2CE < sp2C8; sp2CE++, sp2CC++, sp2CA += 8) {
gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 0, 0, magicAlpha);
OVERLAY_DISP = GfxEx_DrawTexRectI8(OVERLAY_DISP, (u8*)gCounterDigit0Tex + (8 * 16 * counterDigits[sp2CC]), 8,
16, sp2CA + 1, 207, 8, 16, 1 << 10, 1 << 10, G_EX_ORIGIN_LEFT, Y_ORIGIN_BOTTOM);
gDPPipeSync(OVERLAY_DISP++);
if (gSaveContext.save.saveInfo.playerData.rupees == CUR_CAPACITY(UPG_WALLET)) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 120, 255, 0, interfaceCtx->magicAlpha);
} else if (gSaveContext.save.saveInfo.playerData.rupees != 0) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->magicAlpha);
} else {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 100, 100, 100, interfaceCtx->magicAlpha);
}
gEXTextureRectangle(OVERLAY_DISP++, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT,
adjust_x(sp2CA, G_EX_ORIGIN_LEFT) * 4, adjust_y(206, Y_ORIGIN_BOTTOM) * 4,
adjust_x(sp2CA + 8, G_EX_ORIGIN_LEFT) * 4, adjust_y(222, Y_ORIGIN_BOTTOM) * 4,
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
}
Magic_DrawMeter(play);
Minimap_Draw(play);
if ((R_PAUSE_BG_PRERENDER_STATE != 2) && (R_PAUSE_BG_PRERENDER_STATE != 3)) {
Target_Draw(&play->actorCtx.targetCtx, play);
}
Gfx_SetupDL39_Overlay(play->state.gfxCtx);
Interface_DrawItemButtons(play);
if (player->transformation == GET_PLAYER_FORM) {
Interface_DrawBButtonIcons(play);
}
Interface_DrawCButtonIcons(play);
Interface_DrawAButton(play);
Interface_DrawPauseMenuEquippingIcons(play);
// Draw either the minigame countdown or the three-day clock
if ((play->pauseCtx.state == PAUSE_STATE_OFF) && (play->pauseCtx.debugEditor == DEBUG_EDITOR_NONE)) {
if ((interfaceCtx->minigameState != MINIGAME_STATE_NONE) &&
(interfaceCtx->minigameState < MINIGAME_STATE_NO_COUNTDOWN_SETUP)) {
// Minigame Countdown
if (((u32)interfaceCtx->minigameState % 2) == 0) {
sp2CE = (interfaceCtx->minigameState >> 1) - 1;
minigameCountdownScale = interfaceCtx->minigameCountdownScale / 100.0f;
if (sp2CE == 3) {
interfaceCtx->actionVtx[40 + 0].v.ob[0] = interfaceCtx->actionVtx[40 + 2].v.ob[0] = -20;
interfaceCtx->actionVtx[40 + 1].v.ob[0] = interfaceCtx->actionVtx[40 + 3].v.ob[0] =
interfaceCtx->actionVtx[40 + 0].v.ob[0] + 40;
interfaceCtx->actionVtx[40 + 1].v.tc[0] = interfaceCtx->actionVtx[40 + 3].v.tc[0] = 40 << 5;
}
interfaceCtx->actionVtx[40 + 2].v.tc[1] = interfaceCtx->actionVtx[40 + 3].v.tc[1] = 32 << 5;
Gfx_SetupDL42_Overlay(play->state.gfxCtx);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
gDPSetAlphaCompare(OVERLAY_DISP++, G_AC_THRESHOLD);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, sMinigameCountdownPrimColors[sp2CE].r,
sMinigameCountdownPrimColors[sp2CE].g, sMinigameCountdownPrimColors[sp2CE].b,
interfaceCtx->minigameCountdownAlpha);
Matrix_Translate(0.0f, -40.0f, 0.0f, MTXMODE_NEW);
Matrix_Scale(minigameCountdownScale, minigameCountdownScale, 0.0f, MTXMODE_APPLY);
gSPMatrix(OVERLAY_DISP++, Matrix_NewMtx(play->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPVertex(OVERLAY_DISP++, &interfaceCtx->actionVtx[40], 4, 0);
OVERLAY_DISP = Gfx_DrawTexQuadIA8(OVERLAY_DISP, sMinigameCountdownTextures[sp2CE],
sMinigameCountdownTexWidths[sp2CE], 32, 0);
}
} else {
Interface_DrawClock(play);
}
}
// Draw the letters of minigame perfect
if (interfaceCtx->perfectLettersOn) {
Interface_DrawPerfectLetters(play);
}
Interface_DrawMinigameIcons(play);
Interface_DrawTimers(play);
}
// Draw pictograph focus icons
if (sPictoState == PICTO_BOX_STATE_LENS) {
Gfx_SetupDL39_Overlay(play->state.gfxCtx);
gDPSetAlphaCompare(OVERLAY_DISP++, G_AC_THRESHOLD);
gDPSetRenderMode(OVERLAY_DISP++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 155, 255);
gDPLoadTextureBlock_4b(OVERLAY_DISP++, gPictoBoxFocusBorderTex, G_IM_FMT_IA, 16, 16, 0, G_TX_MIRROR | G_TX_WRAP,
G_TX_MIRROR | G_TX_WRAP, 4, 4, G_TX_NOLOD, G_TX_NOLOD);
gSPTextureRectangle(OVERLAY_DISP++, R_PICTO_FOCUS_BORDER_TOPLEFT_X << 2, R_PICTO_FOCUS_BORDER_TOPLEFT_Y << 2,
(R_PICTO_FOCUS_BORDER_TOPLEFT_X << 2) + (16 << 2),
(R_PICTO_FOCUS_BORDER_TOPLEFT_Y << 2) + (16 << 2), G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
gSPTextureRectangle(OVERLAY_DISP++, R_PICTO_FOCUS_BORDER_TOPRIGHT_X << 2, R_PICTO_FOCUS_BORDER_TOPRIGHT_Y << 2,
(R_PICTO_FOCUS_BORDER_TOPRIGHT_X << 2) + (16 << 2),
(R_PICTO_FOCUS_BORDER_TOPRIGHT_Y << 2) + (16 << 2), G_TX_RENDERTILE, 512, 0, 1 << 10,
1 << 10);
gSPTextureRectangle(
OVERLAY_DISP++, R_PICTO_FOCUS_BORDER_BOTTOMLEFT_X << 2, R_PICTO_FOCUS_BORDER_BOTTOMLEFT_Y << 2,
(R_PICTO_FOCUS_BORDER_BOTTOMLEFT_X << 2) + (16 << 2), (R_PICTO_FOCUS_BORDER_BOTTOMLEFT_Y << 2) + (16 << 2),
G_TX_RENDERTILE, 0, 512, 1 << 10, 1 << 10);
gSPTextureRectangle(
OVERLAY_DISP++, R_PICTO_FOCUS_BORDER_BOTTOMRIGHT_X << 2, R_PICTO_FOCUS_BORDER_BOTTOMRIGHT_Y << 2,
(R_PICTO_FOCUS_BORDER_BOTTOMRIGHT_X << 2) + (16 << 2),
(R_PICTO_FOCUS_BORDER_BOTTOMRIGHT_Y << 2) + (16 << 2), G_TX_RENDERTILE, 512, 512, 1 << 10, 1 << 10);
gDPLoadTextureBlock_4b(OVERLAY_DISP++, gPictoBoxFocusIconTex, G_IM_FMT_I, 32, 16, 0, G_TX_NOMIRROR | G_TX_WRAP,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
gSPTextureRectangle(OVERLAY_DISP++, R_PICTO_FOCUS_ICON_X << 2, R_PICTO_FOCUS_ICON_Y << 2,
(R_PICTO_FOCUS_ICON_X << 2) + 0x80, (R_PICTO_FOCUS_ICON_Y << 2) + (16 << 2),
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
gDPLoadTextureBlock_4b(OVERLAY_DISP++, gPictoBoxFocusTextTex, G_IM_FMT_I, 32, 8, 0, G_TX_NOMIRROR | G_TX_WRAP,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
gSPTextureRectangle(OVERLAY_DISP++, R_PICTO_FOCUS_TEXT_X << 2, R_PICTO_FOCUS_TEXT_Y << 2,
(R_PICTO_FOCUS_TEXT_X << 2) + 0x80, (R_PICTO_FOCUS_TEXT_Y << 2) + 0x20, G_TX_RENDERTILE, 0,
0, 1 << 10, 1 << 10);
}
// Draw pictograph photo
if (sPictoState >= PICTO_BOX_STATE_SETUP_PHOTO) {
if (!(play->actorCtx.flags & ACTORCTX_FLAG_PICTO_BOX_ON)) {
Play_CompressI8ToI5((play->pictoPhotoI8 != NULL) ? play->pictoPhotoI8 : gWorkBuffer,
(u8*)gSaveContext.pictoPhotoI5, PICTO_PHOTO_WIDTH * PICTO_PHOTO_HEIGHT);
interfaceCtx->unk_222 = interfaceCtx->unk_224 = 0;
sPictoState = PICTO_BOX_STATE_OFF;
gSaveContext.hudVisibility = HUD_VISIBILITY_IDLE;
Interface_SetHudVisibility(HUD_VISIBILITY_ALL);
} else {
s16 pictoRectTop;
s16 pictoRectLeft;
if (sPictoState == PICTO_BOX_STATE_SETUP_PHOTO) {
sPictoState = PICTO_BOX_STATE_PHOTO;
Message_StartTextbox(play, 0xF8, NULL);
Interface_SetHudVisibility(HUD_VISIBILITY_NONE);
player->stateFlags1 |= PLAYER_STATE1_200;
}
gDPPipeSync(OVERLAY_DISP++);
gDPSetRenderMode(OVERLAY_DISP++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 200, 200, 200, 250);
gDPFillRectangle(OVERLAY_DISP++, 70, 22, 251, 151);
Gfx_SetupDL39_Overlay(play->state.gfxCtx);
gDPSetRenderMode(OVERLAY_DISP++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEI_PRIM, G_CC_MODULATEI_PRIM);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 250, 160, 160, 255);
// Picture is offset up by 33 pixels to give room for the message box at the bottom
pictoRectTop = PICTO_PHOTO_TOPLEFT_Y - 33;
for (sp2CC = 0; sp2CC < (PICTO_PHOTO_HEIGHT / 8); sp2CC++, pictoRectTop += 8) {
pictoRectLeft = PICTO_PHOTO_TOPLEFT_X;
gDPLoadTextureBlock(OVERLAY_DISP++,
(u8*)((play->pictoPhotoI8 != NULL) ? play->pictoPhotoI8 : gWorkBuffer) +
(0x500 * sp2CC),
G_IM_FMT_I, G_IM_SIZ_8b, PICTO_PHOTO_WIDTH, 8, 0, G_TX_NOMIRROR | G_TX_WRAP,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
gSPTextureRectangle(OVERLAY_DISP++, pictoRectLeft << 2, pictoRectTop << 2,
(pictoRectLeft + PICTO_PHOTO_WIDTH) << 2, (pictoRectTop << 2) + (8 << 2),
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
}
}
}
// Draw over the entire screen (used in gameover)
if (interfaceCtx->screenFillAlpha != 0) {
gDPPipeSync(OVERLAY_DISP++);
gSPDisplayList(OVERLAY_DISP++, sScreenFillSetupDL);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 0, 0, interfaceCtx->screenFillAlpha);
gSPDisplayList(OVERLAY_DISP++, D_0E000000.fillRect);
}
CLOSE_DISPS(play->state.gfxCtx);
}