summaryrefslogtreecommitdiff
path: root/src/code
diff options
context:
space:
mode:
authorengineer124 <engineer124engineer124@gmail.com>2023-10-26 21:19:22 +1100
committerengineer124 <engineer124engineer124@gmail.com>2023-10-26 21:19:22 +1100
commite46a451acea09783e9d9526c937fa559a4b1b6c5 (patch)
treeba0945a526819d8b1e14f4261f5aac34aff98251 /src/code
parent986e34c03664274d29c0fc9af07636e78ad2d997 (diff)
parentc3b19739c6e9d8da8a6d24afa818cfdad8c0ff42 (diff)
merge main
Diffstat (limited to 'src/code')
-rw-r--r--src/code/code_80140E80.c21
-rw-r--r--src/code/z_actor.c20
-rw-r--r--src/code/z_bgcheck.c1
-rw-r--r--src/code/z_camera.c1
-rw-r--r--src/code/z_collision_check.c1
-rw-r--r--src/code/z_demo.c43
-rw-r--r--src/code/z_eventmgr.c10
-rw-r--r--src/code/z_lifemeter.c1
-rw-r--r--src/code/z_message.c2
-rw-r--r--src/code/z_play.c37
-rw-r--r--src/code/z_player_lib.c6
-rw-r--r--src/code/z_visfbuf.c329
12 files changed, 381 insertions, 91 deletions
diff --git a/src/code/code_80140E80.c b/src/code/code_80140E80.c
deleted file mode 100644
index 56fcb663c..000000000
--- a/src/code/code_80140E80.c
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "global.h"
-
-#pragma GLOBAL_ASM("asm/non_matchings/code/code_80140E80/func_80140E80.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/code/code_80140E80/func_80140EA0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/code/code_80140E80/func_80140EAC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/code/code_80140E80/func_80141008.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/code/code_80140E80/func_8014116C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/code/code_80140E80/func_801411B4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/code/code_80140E80/func_80141200.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/code/code_80140E80/func_8014151C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/code/code_80140E80/func_80141678.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/code/code_80140E80/func_80141778.s")
diff --git a/src/code/z_actor.c b/src/code/z_actor.c
index 01a778227..70945722f 100644
--- a/src/code/z_actor.c
+++ b/src/code/z_actor.c
@@ -4,12 +4,14 @@
*/
#include "z64actor.h"
+#include "prevent_bss_reordering.h"
#include "fault.h"
#include "sys_cfb.h"
#include "loadfragment.h"
#include "z64horse.h"
#include "z64quake.h"
#include "z64rumble.h"
+
#include "overlays/actors/ovl_En_Horse/z_en_horse.h"
#include "overlays/actors/ovl_En_Part/z_en_part.h"
#include "overlays/actors/ovl_En_Box/z_en_box.h"
@@ -1393,31 +1395,31 @@ void Actor_MountHorse(PlayState* play, Player* player, Actor* horse) {
s32 func_800B7200(Player* player) {
return (player->stateFlags1 & (PLAYER_STATE1_80 | PLAYER_STATE1_20000000)) ||
- (player->csMode != PLAYER_CSMODE_NONE);
+ (player->csAction != PLAYER_CSACTION_NONE);
}
void Actor_SpawnHorse(PlayState* play, Player* player) {
Horse_Spawn(play, player);
}
-s32 func_800B724C(PlayState* play, Actor* actor, u8 csMode) {
+s32 func_800B724C(PlayState* play, Actor* actor, u8 csAction) {
Player* player = GET_PLAYER(play);
- if ((player->csMode == PLAYER_CSMODE_5) ||
- ((csMode == PLAYER_CSMODE_END) && (player->csMode == PLAYER_CSMODE_NONE))) {
+ if ((player->csAction == PLAYER_CSACTION_5) ||
+ ((csAction == PLAYER_CSACTION_END) && (player->csAction == PLAYER_CSACTION_NONE))) {
return false;
}
- player->csMode = csMode;
+ player->csAction = csAction;
player->csActor = actor;
player->unk_3BA = false;
return true;
}
-s32 func_800B7298(PlayState* play, Actor* actor, u8 csMode) {
+s32 func_800B7298(PlayState* play, Actor* actor, u8 csAction) {
Player* player = GET_PLAYER(play);
- if (func_800B724C(play, actor, csMode)) {
+ if (func_800B724C(play, actor, csAction)) {
player->unk_3BA = true;
return true;
}
@@ -1939,8 +1941,8 @@ s32 Actor_ProcessTalkRequest(Actor* actor, GameState* gameState) {
* - Positive values (`PLAYER_IA_NONE < exchangeItemAction < PLAYER_IA_MAX`):
* Offers the ability to initiate the conversation with an item from the player.
* Not all positive values are implemented properly for this to work.
- * Working ones are PLAYER_IA_PICTO_BOX and PLAYER_IA_BOTTLE_MIN <= exchangeItemAction < PLAYER_IA_MASK_MIN
- * Note: While PLAYER_IA_BEANS works, it is special cased to just plant the bean with no talking.
+ * Working ones are PLAYER_IA_PICTOGRAPH_BOX and PLAYER_IA_BOTTLE_MIN <= exchangeItemAction < PLAYER_IA_MASK_MIN
+ * Note: While PLAYER_IA_MAGIC_BEANS works, it is special cased to just plant the bean with no talking.
* - `PLAYER_IA_NONE`:
* Allows the player to speak to or check the actor (by pressing A).
* - `PLAYER_IA_MINUS1`:
diff --git a/src/code/z_bgcheck.c b/src/code/z_bgcheck.c
index ef2b7ea6a..baa16a60d 100644
--- a/src/code/z_bgcheck.c
+++ b/src/code/z_bgcheck.c
@@ -1,3 +1,4 @@
+#include "prevent_bss_reordering.h"
#include "global.h"
#include "fault.h"
#include "fixed_point.h"
diff --git a/src/code/z_camera.c b/src/code/z_camera.c
index cc5ad58ea..49c31864b 100644
--- a/src/code/z_camera.c
+++ b/src/code/z_camera.c
@@ -43,7 +43,6 @@
*
*/
-#include "prevent_bss_reordering.h"
#include "global.h"
#include "libc/string.h"
#include "z64quake.h"
diff --git a/src/code/z_collision_check.c b/src/code/z_collision_check.c
index e8a3a9017..753f24bb5 100644
--- a/src/code/z_collision_check.c
+++ b/src/code/z_collision_check.c
@@ -1,3 +1,4 @@
+#include "prevent_bss_reordering.h"
#include "global.h"
#include "z64collision_check.h"
diff --git a/src/code/z_demo.c b/src/code/z_demo.c
index 1123d3dc1..fa0419de4 100644
--- a/src/code/z_demo.c
+++ b/src/code/z_demo.c
@@ -1,3 +1,6 @@
+#include "prevent_bss_reordering.h"
+#include "prevent_bss_reordering2.h"
+
#include "PR/ultratypes.h"
// Variables are put before most headers as a hacky way to bypass bss reordering
@@ -8,37 +11,9 @@ struct CutsceneCamera sCutsceneCameraInfo;
u16 sCueTypeList[10];
u8 D_801F4DDC;
static s16 sBssPad;
-u8 gDisablePlayerCsModeStartPos;
+u8 gDisablePlayerCsActionStartPos;
s16 gDungeonBossWarpSceneId;
-#include "prevent_bss_reordering.h"
-#include "prevent_bss_reordering2.h"
-// clang-format off
-// Partial structs taken from "prevent_bss_reordering.h"
-struct Dummy200 { int x; };
-struct Dummy201 { int x; };
-struct Dummy202 { int x; };
-struct Dummy203 { int x; };
-struct Dummy204 { int x; };
-struct Dummy205 { int x; };
-struct Dummy206 { int x; };
-struct Dummy207 { int x; };
-struct Dummy208 { int x; };
-struct Dummy209 { int x; };
-struct Dummy210 { int x; };
-struct Dummy211 { int x; };
-struct Dummy212 { int x; };
-struct Dummy213 { int x; };
-struct Dummy214 { int x; };
-struct Dummy215 { int x; };
-struct Dummy216 { int x; };
-struct Dummy217 { int x; };
-struct Dummy218 { int x; };
-struct Dummy219 { int x; };
-struct Dummy220 { int x; };
-// clang-format on
-
-#include "global.h"
#include "z64quake.h"
#include "z64rumble.h"
#include "z64shrink_window.h"
@@ -72,7 +47,7 @@ void Cutscene_InitContext(PlayState* play, CutsceneContext* csCtx) {
sCueTypeList[i] = 0;
}
- gDisablePlayerCsModeStartPos = false;
+ gDisablePlayerCsActionStartPos = false;
Audio_SetCutsceneFlag(false);
}
@@ -364,12 +339,12 @@ void CutsceneCmd_Misc(PlayState* play, CutsceneContext* csCtx, CsCmdMisc* cmd) {
gSaveContext.save.playerForm = sCutsceneStoredPlayerForm;
break;
- case CS_MISC_DISABLE_PLAYER_CSMODE_START_POS:
- gDisablePlayerCsModeStartPos = true;
+ case CS_MISC_DISABLE_PLAYER_CSACTION_START_POS:
+ gDisablePlayerCsActionStartPos = true;
break;
- case CS_MISC_ENABLE_PLAYER_CSMODE_START_POS:
- gDisablePlayerCsModeStartPos = false;
+ case CS_MISC_ENABLE_PLAYER_CSACTION_START_POS:
+ gDisablePlayerCsActionStartPos = false;
break;
case CS_MISC_SAVE_ENTER_CLOCK_TOWN:
diff --git a/src/code/z_eventmgr.c b/src/code/z_eventmgr.c
index fed5ec48c..9f08806f9 100644
--- a/src/code/z_eventmgr.c
+++ b/src/code/z_eventmgr.c
@@ -213,7 +213,7 @@ void CutsceneManager_End(void) {
sCutsceneMgr.targetActor->flags &= ~ACTOR_FLAG_100000;
// fallthrough
case CS_START_1:
- func_800B7298(sCutsceneMgr.play, NULL, PLAYER_CSMODE_END);
+ func_800B7298(sCutsceneMgr.play, NULL, PLAYER_CSACTION_END);
sCutsceneMgr.startMethod = CS_START_0;
break;
@@ -338,13 +338,13 @@ s16 CutsceneManager_IsNext(s16 csId) {
}
/**
- * Start an actor cutscene, activate Player Cutscene Mode "Wait"
+ * Start an actor cutscene, activate Player Cutscene Action "Wait"
*/
s16 CutsceneManager_StartWithPlayerCs(s16 csId, Actor* actor) {
s16 startCsId = CutsceneManager_Start(csId, actor);
if (startCsId >= 0) {
- func_800B7298(sCutsceneMgr.play, NULL, PLAYER_CSMODE_WAIT);
+ func_800B7298(sCutsceneMgr.play, NULL, PLAYER_CSACTION_WAIT);
if (sCutsceneMgr.length == 0) {
CutsceneManager_Stop(sCutsceneMgr.csId);
}
@@ -354,13 +354,13 @@ s16 CutsceneManager_StartWithPlayerCs(s16 csId, Actor* actor) {
}
/**
- * Start an actor cutscene, activate Player Cutscene Mode "Wait", turn on ACTOR_FLAG_100000
+ * Start an actor cutscene, activate Player Cutscene Action "Wait", turn on ACTOR_FLAG_100000
*/
s16 CutsceneManager_StartWithPlayerCsAndSetFlag(s16 csId, Actor* actor) {
s16 startCsId = CutsceneManager_Start(csId, actor);
if (startCsId >= 0) {
- func_800B7298(sCutsceneMgr.play, NULL, PLAYER_CSMODE_WAIT);
+ func_800B7298(sCutsceneMgr.play, NULL, PLAYER_CSACTION_WAIT);
if (sCutsceneMgr.length == 0) {
CutsceneManager_Stop(sCutsceneMgr.csId);
}
diff --git a/src/code/z_lifemeter.c b/src/code/z_lifemeter.c
index 5d1299bbf..d9abe151d 100644
--- a/src/code/z_lifemeter.c
+++ b/src/code/z_lifemeter.c
@@ -1,3 +1,4 @@
+#include "prevent_bss_reordering.h"
#include "global.h"
#include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h"
#include "interface/parameter_static/parameter_static.h"
diff --git a/src/code/z_message.c b/src/code/z_message.c
index 3fb8f5bac..4d717d8df 100644
--- a/src/code/z_message.c
+++ b/src/code/z_message.c
@@ -5107,6 +5107,7 @@ void Message_Draw(PlayState* play) {
GraphicsContext* gfxCtx = play->state.gfxCtx;
OPEN_DISPS(gfxCtx);
+
polyOpa = POLY_OPA_DISP;
nextDisplayList = Graph_GfxPlusOne(polyOpa);
gSPDisplayList(OVERLAY_DISP++, nextDisplayList);
@@ -5118,6 +5119,7 @@ void Message_Draw(PlayState* play) {
gSPEndDisplayList(nextDisplayList++);
Graph_BranchDlist(polyOpa, nextDisplayList);
POLY_OPA_DISP = nextDisplayList;
+
CLOSE_DISPS(gfxCtx);
}
diff --git a/src/code/z_play.c b/src/code/z_play.c
index 174dedd1c..89e3f34c9 100644
--- a/src/code/z_play.c
+++ b/src/code/z_play.c
@@ -3,6 +3,7 @@
#include "regs.h"
#include "functions.h"
#include "z64vismono.h"
+#include "z64visfbuf.h"
// Variables are put before most headers as a hacky way to bypass bss reordering
s16 sTransitionFillTimer;
@@ -11,8 +12,8 @@ TransitionTile sTransitionTile;
s32 gTransitionTileState;
VisMono sPlayVisMono;
Color_RGBA8_u32 gVisMonoColor;
-Struct_80140E80 D_801F6D38;
-Struct_80140E80* D_801F6D4C;
+VisFbuf sPlayVisFbuf;
+VisFbuf* sPlayVisFbufInstance;
BombersNotebook sBombersNotebook;
u8 sBombersNotebookOpen;
u8 sMotionBlurStatus;
@@ -417,8 +418,8 @@ void Play_Destroy(GameState* thisx) {
ShrinkWindow_Destroy();
TransitionFade_Destroy(&this->unk_18E48);
VisMono_Destroy(&sPlayVisMono);
- func_80140EA0(D_801F6D4C);
- D_801F6D4C = NULL;
+ VisFbuf_Destroy(sPlayVisFbufInstance);
+ sPlayVisFbufInstance = NULL;
if (CHECK_WEEKEVENTREG(WEEKEVENTREG_92_80)) {
Actor_CleanupContext(&this->actorCtx, this);
@@ -1110,7 +1111,7 @@ void Play_PostWorldDraw(PlayState* this) {
Gfx* opa;
GraphicsContext* gfxCtx = this->state.gfxCtx;
- D_801F6D4C->scale = gSaveContext.screenScale / 1000.0f;
+ sPlayVisFbufInstance->scale = gSaveContext.screenScale / 1000.0f;
OPEN_DISPS(gfxCtx);
@@ -1118,7 +1119,7 @@ void Play_PostWorldDraw(PlayState* this) {
nextOpa = Graph_GfxPlusOne(opa);
gSPDisplayList(OVERLAY_DISP++, nextOpa);
- func_80141778(D_801F6D4C, &nextOpa, this->unk_18E60, gfxCtx);
+ VisFbuf_Draw(sPlayVisFbufInstance, &nextOpa, this->unk_18E60);
gSPEndDisplayList(nextOpa++);
Graph_BranchDlist(opa, nextOpa);
@@ -2311,18 +2312,18 @@ void Play_Init(GameState* thisx) {
VisMono_Init(&sPlayVisMono);
gVisMonoColor.a = 0;
- D_801F6D4C = &D_801F6D38;
- func_80140E80(D_801F6D4C);
- D_801F6D4C->lodProportion = 0.0f;
- D_801F6D4C->mode = 1;
- D_801F6D4C->primColor.r = 0;
- D_801F6D4C->primColor.g = 0;
- D_801F6D4C->primColor.b = 0;
- D_801F6D4C->primColor.a = 0;
- D_801F6D4C->envColor.r = 0;
- D_801F6D4C->envColor.g = 0;
- D_801F6D4C->envColor.b = 0;
- D_801F6D4C->envColor.a = 0;
+ sPlayVisFbufInstance = &sPlayVisFbuf;
+ VisFbuf_Init(sPlayVisFbufInstance);
+ sPlayVisFbufInstance->lodProportion = 0.0f;
+ sPlayVisFbufInstance->mode = VIS_FBUF_MODE_GENERAL;
+ sPlayVisFbufInstance->primColor.r = 0;
+ sPlayVisFbufInstance->primColor.g = 0;
+ sPlayVisFbufInstance->primColor.b = 0;
+ sPlayVisFbufInstance->primColor.a = 0;
+ sPlayVisFbufInstance->envColor.r = 0;
+ sPlayVisFbufInstance->envColor.g = 0;
+ sPlayVisFbufInstance->envColor.b = 0;
+ sPlayVisFbufInstance->envColor.a = 0;
CutsceneFlags_UnsetAll(this);
THA_GetRemaining(&this->state.tha);
zAllocSize = THA_GetRemaining(&this->state.tha);
diff --git a/src/code/z_player_lib.c b/src/code/z_player_lib.c
index 6c33a5565..486abcbda 100644
--- a/src/code/z_player_lib.c
+++ b/src/code/z_player_lib.c
@@ -495,7 +495,7 @@ void func_80123140(PlayState* play, Player* player) {
s32 Player_InBlockingCsMode(PlayState* play, Player* player) {
return (player->stateFlags1 & (PLAYER_STATE1_80 | PLAYER_STATE1_200 | PLAYER_STATE1_20000000)) ||
- (player->csMode != PLAYER_CSMODE_NONE) || (play->transitionTrigger == TRANS_TRIGGER_START) ||
+ (player->csAction != PLAYER_CSACTION_NONE) || (play->transitionTrigger == TRANS_TRIGGER_START) ||
(play->transitionMode != TRANS_MODE_OFF) || (player->stateFlags1 & PLAYER_STATE1_1) ||
(player->stateFlags3 & PLAYER_STATE3_80) || (play->actorCtx.unk268 != 0);
}
@@ -1297,9 +1297,9 @@ void func_80123C58(Player* player) {
}
void Player_SetEquipmentData(PlayState* play, Player* player) {
- if (player->csMode != PLAYER_CSMODE_134) {
+ if (player->csAction != PLAYER_CSACTION_134) {
player->currentShield = GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SHIELD);
- if ((player->transformation != PLAYER_FORM_ZORA) || (((player->currentBoots != PLAYER_BOOTS_ZORA_LAND)) &&
+ if ((player->transformation != PLAYER_FORM_ZORA) || ((player->currentBoots != PLAYER_BOOTS_ZORA_LAND) &&
(player->currentBoots != PLAYER_BOOTS_ZORA_UNDERWATER))) {
player->currentBoots = D_801BFF90[player->transformation];
}
diff --git a/src/code/z_visfbuf.c b/src/code/z_visfbuf.c
new file mode 100644
index 000000000..62242bcec
--- /dev/null
+++ b/src/code/z_visfbuf.c
@@ -0,0 +1,329 @@
+/**
+ * @file z_visfbuf.c
+ * @brief Copies images between color images (generally framebuffers), possibly with filling, scaling, and colour
+ * interpolation.
+ *
+ * Used for several transition effects, and in z_play to shrink the screen at the end of the First and Second Days.
+ *
+ * @note to use the functions in this file, with the exception of VisFbuf_Draw(), it is necessary to load the S2DEX2
+ * microcode first, and then re-load the 3D microcode afterwards for the rest of the drawing in the frame; see
+ * VisFbuf_Draw() for how to do this.
+ */
+
+#include "global.h"
+#include "z64visfbuf.h"
+#include "sys_cfb.h"
+
+#define SCALE_MIN 0.032f
+#define SCALE_MAX 1.0f //!< also unchanged scale
+
+void VisFbuf_Init(VisFbuf* this) {
+ bzero(this, sizeof(VisFbuf));
+}
+
+void VisFbuf_Destroy(VisFbuf* this) {
+}
+
+// internal, only used in VisFbuf_SetBg
+/**
+ * Draw a bg to the specified color image.
+ *
+ * @param[in,out] gfxP Pointer to current displaylist
+ * @param[in] bg BG object to draw
+ * @param[out] img Pointer to beginning of destination color image
+ * @param[in] width Output width in pixels
+ * @param[in] height Output height in pixels
+ * @param[in] cycleMode Which BG mode to use
+ */
+void VisFbuf_DrawBgToColorImage(Gfx** gfxP, uObjBg* bg, void* img, s32 width, s32 height, VisFbufBgMode cycleMode) {
+ Gfx* gfx = *gfxP;
+
+ gDPPipeSync(gfx++);
+ // Set up color image to draw bg to
+ gDPSetColorImage(gfx++, G_IM_FMT_RGBA, G_IM_SIZ_16b, width, img);
+ gDPSetScissor(gfx++, 0, 0, 0, width, height);
+
+ // Draw bg in appropriate type
+ gSPObjRenderMode(gfx++, G_OBJRM_ANTIALIAS | G_OBJRM_BILERP);
+ if (!!(cycleMode & VIS_FBUF_BG_CYC_COPY) != 0) { //! FAKE: may possibly be a better way
+ gSPBgRectCopy(gfx++, bg);
+ } else {
+ gSPBgRect1Cyc(gfx++, bg);
+ }
+
+ gDPPipeSync(gfx++);
+ // Reset the color image and scissor to frame's defaults
+ gDPSetColorImage(gfx++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gCfbWidth, D_0F000000);
+ gSPDisplayList(gfx++, D_0E000000.setScissor);
+
+ *gfxP = gfx;
+}
+
+// internal
+/**
+ * Set up a BG from a specified source image and draw it to the specified color image with
+ * VisFbuf_DrawBgToColorImage(), using the BG's settings. Use VisFbuf_SetBgSimple() or
+ * VisFbuf_SetBgGeneral()
+ *
+ * @param[out] gfxP Pointer to current displaylist
+ * @param[in] source Pointer to beginning of source color image
+ * @param[out] img Pointer to beginning of destination color image
+ * @param[in] width Output width in pixels
+ * @param[in] height Output height in pixels
+ * @param[in] x Left of drawn output
+ * @param[in] y Top of drawn output
+ * @param[in] scaleX Amount to rescale the image, (dsdx). No effect if `cycleMode` is `VIS_FBUF_BG_CYC_COPY`.
+ * @param[in] scaleY Amount to rescale the image, (dtdy). No effect if `cycleMode` is `VIS_FBUF_BG_CYC_COPY`.
+ * @param[in] cycleMode Which BG mode to use
+ */
+void VisFbuf_SetBg(Gfx** gfxP, void* source, void* img, s32 width, s32 height, f32 x, f32 y, f32 scaleX, f32 scaleY,
+ VisFbufBgMode cycleMode) {
+ Gfx* gfx = *gfxP;
+ Gfx* gfxTemp;
+ uObjBg* bg;
+
+ // Allocate for BG
+ gfxTemp = gfx;
+ bg = Graph_DlistAlloc(&gfxTemp, sizeof(uObjBg));
+ gfx = gfxTemp;
+
+ // Set up BG
+ bg->b.imageX = 0;
+ bg->b.imageW = width << 2;
+ bg->b.frameX = x * 4;
+ bg->b.frameW = width << 2;
+ bg->b.imageY = 0;
+ bg->b.imageH = height << 2;
+ bg->b.frameY = y * 4;
+ bg->b.frameH = height << 2;
+ bg->b.imageLoad = G_BGLT_LOADTILE;
+ bg->b.imageFmt = G_IM_FMT_RGBA;
+ bg->b.imageSiz = G_IM_SIZ_16b;
+ bg->b.imagePal = 0;
+ bg->b.imageFlip = 0;
+ bg->b.imagePtr = source;
+
+ if (!!(cycleMode & VIS_FBUF_BG_CYC_COPY) != 0) { //! FAKE: may possibly be a better way
+ guS2DInitBg(bg);
+ } else {
+ bg->s.scaleW = (s32)((1 << 10) / scaleX);
+ bg->s.scaleH = (s32)((1 << 10) / scaleY);
+ bg->s.imageYorig = bg->b.imageY;
+ }
+
+ // draw BG to `img`
+ VisFbuf_DrawBgToColorImage(&gfx, bg, img, width, height, cycleMode);
+
+ *gfxP = gfx;
+}
+
+// used in FbdemoWipe5 and internally
+// "default settings" wrapper for VisFbuf_SetBg
+/**
+ * Set up a BG from a specified source image and draw it to the specified color image with
+ * VisFbuf_DrawBgToColorImage(), using the BG's settings. Position uses the default (0,0), and no rescaling is done
+ * even if 1-cycle mode is enabled.
+ *
+ * @see VisFbuf_SetBg() for arguments.
+ */
+void VisFbuf_SetBgSimple(Gfx** gfxP, void* source, void* img, s32 width, s32 height, VisFbufBgMode cycleMode) {
+ VisFbuf_SetBg(gfxP, source, img, width, height, 0.0f, 0.0f, SCALE_MAX, SCALE_MAX, cycleMode);
+}
+
+// wrapper for VisFbuf_SetBg with general arguments, used in VisFbuf_ApplyEffects
+/**
+ * Set up a BG from a specified source image and draw it to the specified color image with
+ * VisFbuf_DrawBgToColorImage(). Fully general settings are available.
+ *
+ * @see VisFbuf_SetBg() for arguments.
+ */
+void VisFbuf_SetBgGeneral(Gfx** gfxP, void* source, void* img, s32 width, s32 height, f32 x, f32 y, f32 scaleX,
+ f32 scaleY, VisFbufBgMode cycleMode) {
+ VisFbuf_SetBg(gfxP, source, img, width, height, x, y, scaleX, scaleY, cycleMode);
+}
+
+// internal, used in VisFbuf_DrawGeneral
+/**
+ * Most general redrawing function.
+ *
+ * - Copies `source` to `img`,
+ * - fills the current framebuffer with `this->primColor`,
+ * - applies colour interpolation to `img`,
+ * - copies `img` back to `source`, with rescaling.
+ *
+ * @param[in] this
+ * @param[in,out] gfxP Pointer to current displaylist
+ * @param[in,out] source Pointer to beginning of in/out color image
+ * @param[out] img Pointer to beginning of destination color image
+ * @param[in] width Output width in pixels
+ * @param[in] height Output height in pixels
+ */
+void VisFbuf_ApplyEffects(VisFbuf* this, Gfx** gfxP, void* source, void* img, s32 width, s32 height) {
+ Gfx* gfx = *gfxP;
+ s32 pad[3];
+
+ gDPPipeSync(gfx++);
+ // copy source to img
+ gDPSetOtherMode(gfx++,
+ G_AD_PATTERN | G_CD_MAGICSQ | G_CK_NONE | G_TC_CONV | G_TF_POINT | G_TT_NONE | G_TL_TILE |
+ G_TD_CLAMP | G_TP_NONE | G_CYC_COPY | G_PM_NPRIMITIVE,
+ G_AC_NONE | G_ZS_PIXEL | G_RM_NOOP | G_RM_NOOP2);
+ VisFbuf_SetBgSimple(&gfx, source, img, width, height, VIS_FBUF_BG_CYC_COPY);
+
+ gDPPipeSync(gfx++);
+ // fill framebuffer with primColor
+ gDPSetOtherMode(gfx++,
+ G_AD_PATTERN | G_CD_MAGICSQ | G_CK_NONE | G_TC_CONV | G_TF_POINT | G_TT_NONE | G_TL_TILE |
+ G_TD_CLAMP | G_TP_NONE | G_CYC_FILL | G_PM_NPRIMITIVE,
+ G_AC_NONE | G_ZS_PIXEL | G_RM_NOOP | G_RM_NOOP2);
+ {
+ s32 color = GPACK_RGBA5551(this->primColor.r, this->primColor.g, (u32)this->primColor.b, 1);
+
+ gDPSetFillColor(gfx++, (color << 0x10) | color);
+ }
+ //! @bug VisFbuf_SetBgSimple() sets the current color image back to the frame's default framebuffer at the end,
+ //! so this will always fill in the default framebuffer, whatever are used as `source` and `img`. This does not
+ //! arise in-game since this function is always used with `source = D_0F000000`.
+ gDPFillRectangle(gfx++, 0, 0, width - 1, height - 1);
+
+ gDPPipeSync(gfx++);
+ // Set lod and primColor from struct, perform interpolation, draw image with scaling (this is the most general
+ // alteration this system can carry out).
+ {
+ s32 lodFrac = this->lodProportion * 255;
+
+ gDPSetLODColor(gfx++, G_SETPRIMCOLOR, 0, lodFrac, this->primColor.rgba);
+ }
+ if (this->envColor.a == 0) {
+ // Interpolate between primColor and texel color using lod (but with max alpha)
+ gDPSetOtherMode(gfx++,
+ G_AD_DISABLE | G_CD_DISABLE | 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_NPRIMITIVE,
+ G_AC_THRESHOLD | G_ZS_PIXEL | AA_EN | CVG_DST_CLAMP | ZMODE_OPA | CVG_X_ALPHA | ALPHA_CVG_SEL |
+ GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_BL, G_BL_1MA) |
+ GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_BL, G_BL_1MA));
+ gDPSetCombineLERP(gfx++, PRIMITIVE, TEXEL0, PRIM_LOD_FRAC, TEXEL0, 0, 0, 0, 1, PRIMITIVE, TEXEL0, PRIM_LOD_FRAC,
+ TEXEL0, 0, 0, 0, 1);
+ } else {
+ // Interpolate between envColor (the new black) and primColor (the new white)
+ gDPSetOtherMode(gfx++,
+ G_AD_DISABLE | G_CD_DISABLE | G_CK_NONE | G_TC_FILT | G_TF_POINT | G_TT_NONE | G_TL_TILE |
+ G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE,
+ G_AC_NONE | G_ZS_PIXEL | G_RM_CLD_SURF | G_RM_NOOP2);
+ gDPSetColor(gfx++, G_SETENVCOLOR, this->envColor.rgba);
+ gDPSetCombineLERP(gfx++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, PRIMITIVE, ENVIRONMENT, TEXEL0,
+ ENVIRONMENT, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, PRIMITIVE, ENVIRONMENT, TEXEL0,
+ ENVIRONMENT);
+ }
+
+ // Draw scaled image in centre of `width * height` rectangle in `source`
+ {
+ f32 scale = CLAMP_ALT(this->scale, SCALE_MIN, SCALE_MAX);
+
+ VisFbuf_SetBgGeneral(&gfx, img, source, width, height, width * 0.5f * (1.0f - scale),
+ height * 0.5f * (1.0f - scale), scale, scale, VIS_FBUF_BG_CYC_1CYC);
+ }
+
+ gDPPipeSync(gfx++);
+
+ *gfxP = gfx;
+}
+
+// internal, used in VisFbuf_Draw, VIS_FBUF_MODE_GENERAL
+/**
+ * If scale is within `(SCALE_MIN, SCALE_MAX)`, apply VisFbuf_ApplyEffects().
+ * If it is smaller than `SCALE_MIN`, fill the framebuffer with `this->primColor`
+ *
+ * @param[in] this
+ * @param[in,out] gfxP Pointer to current displaylist
+ * @param[in,out] source Pointer to beginning of source color image
+ * @param[in,out] img Pointer to beginning of destination color image
+ * @param[in] width Output width in pixels
+ * @param[in] height Output height in pixels
+ */
+void VisFbuf_DrawGeneral(VisFbuf* this, Gfx** gfxP, void* source, void* img, s32 width, s32 height) {
+ if (this->scale < SCALE_MAX) {
+ Gfx* gfx = *gfxP;
+ u32 color;
+
+ if (this->scale > SCALE_MIN) {
+ VisFbuf_ApplyEffects(this, &gfx, source, img, width, height);
+ } else {
+ gDPPipeSync(gfx++);
+ // fill the framebuffer with this->primColor
+ gDPSetOtherMode(gfx++,
+ G_AD_PATTERN | G_CD_MAGICSQ | G_CK_NONE | G_TC_CONV | G_TF_POINT | G_TT_NONE | G_TL_TILE |
+ G_TD_CLAMP | G_TP_NONE | G_CYC_FILL | G_PM_NPRIMITIVE,
+ G_AC_NONE | G_ZS_PIXEL | G_RM_NOOP | G_RM_NOOP2);
+ color = GPACK_RGBA5551(this->primColor.r, this->primColor.g, (u32)this->primColor.b, 1);
+ gDPSetFillColor(gfx++, (color << 0x10) | color);
+ //! @bug See corresponding note in VisFbuf_ApplyEffects()
+ gDPFillRectangle(gfx++, 0, 0, width - 1, height - 1);
+
+ gDPPipeSync(gfx++);
+ }
+
+ *gfxP = gfx;
+ }
+}
+
+/**
+ * Redraw `img` in-place, using texel color to interpolate between envColor (the new black) and primColor (the new
+ * white)
+ *
+ * @param[in] this
+ * @param[in,out] gfxP Pointer to current displaylist
+ * @param[in,out] img Pointer to beginning of color image to modify in-place
+ * @param[in] width width of img
+ * @param[in] height height of img
+ */
+void VisFbuf_DrawInterpolate(VisFbuf* this, Gfx** gfxP, void* img, s32 width, s32 height) {
+ Gfx* gfx = *gfxP;
+
+ gDPPipeSync(gfx++);
+
+ gDPSetOtherMode(gfx++,
+ G_AD_DISABLE | G_CD_DISABLE | G_CK_NONE | G_TC_FILT | G_TF_POINT | G_TT_NONE | G_TL_TILE |
+ G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE,
+ G_AC_NONE | G_ZS_PIXEL | G_RM_CLD_SURF | G_RM_NOOP2);
+ gDPSetColor(gfx++, G_SETPRIMCOLOR, this->primColor.rgba);
+ gDPSetColor(gfx++, G_SETENVCOLOR, this->envColor.rgba);
+ gDPSetCombineLERP(gfx++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT,
+ PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT);
+ VisFbuf_SetBgSimple(&gfx, img, img, width, height, VIS_FBUF_BG_CYC_1CYC);
+
+ gDPPipeSync(gfx++);
+
+ *gfxP = gfx;
+}
+
+// used in Play and FbdemoWipe4
+/**
+ * main drawing function in this file, draws depending on settings specified in `this`.
+ *
+ * @param[in] this
+ * @param[in,out] gfxP Pointer to current displaylist
+ * @param[in,out] img Pointer to beginning of destination color image
+ */
+void VisFbuf_Draw(VisFbuf* this, Gfx** gfxP, void* img) {
+ Gfx* gfx = *gfxP;
+
+ gSPLoadUcodeL(gfx++, gspS2DEX2_fifo);
+
+ switch (this->mode) {
+ case VIS_FBUF_MODE_GENERAL:
+ VisFbuf_DrawGeneral(this, &gfx, D_0F000000, img, gScreenWidth, gScreenHeight);
+ break;
+
+ case VIS_FBUF_MODE_INTERPOLATE:
+ VisFbuf_DrawInterpolate(this, &gfx, D_0F000000, gScreenWidth, gScreenHeight);
+ break;
+
+ default:
+ break;
+ }
+
+ gSPLoadUcode(gfx++, SysUcode_GetUCode(), SysUcode_GetUCodeData());
+
+ *gfxP = gfx;
+}