pokeemerald/gflib/bg.c

1250 lines
31 KiB
C
Raw Normal View History

2020-04-28 01:29:15 +02:00
#include <limits.h>
2017-09-05 04:18:52 +02:00
#include "global.h"
#include "bg.h"
2017-09-05 04:18:52 +02:00
#include "dma3.h"
2017-09-19 14:27:46 +02:00
#include "gpu_regs.h"
2017-09-05 04:18:52 +02:00
2017-09-19 14:27:46 +02:00
#define DISPCNT_ALL_BG_AND_MODE_BITS (DISPCNT_BG_ALL_ON | 0x7)
2017-09-05 04:18:52 +02:00
2017-09-19 14:27:46 +02:00
struct BgControl
{
2017-09-10 04:48:33 +02:00
struct BgConfig {
2021-02-28 03:31:19 +01:00
u8 visible:1;
u8 unknown_1:1;
u8 screenSize:2;
u8 priority:2;
u8 mosaic:1;
u8 wraparound:1;
u8 charBaseIndex:2;
u8 mapBaseIndex:5;
u8 paletteMode:1;
u8 unknown_2; // Assigned to but never read
u8 unknown_3; // Assigned to but never read
2021-02-18 16:00:07 +01:00
} configs[NUM_BACKGROUNDS];
2017-09-10 04:48:33 +02:00
u16 bgVisibilityAndMode;
2017-09-10 04:48:33 +02:00
};
2017-09-19 14:27:46 +02:00
struct BgConfig2
{
2017-09-10 04:48:33 +02:00
u32 baseTile:10;
u32 basePalette:4;
u32 unk_3:18;
2022-07-29 16:52:35 +02:00
void *tilemap;
s32 bg_x;
s32 bg_y;
2017-09-10 04:48:33 +02:00
};
static struct BgControl sGpuBgConfigs;
2021-02-18 16:00:07 +01:00
static struct BgConfig2 sGpuBgConfigs2[NUM_BACKGROUNDS];
static u32 sDmaBusyBitfield[NUM_BACKGROUNDS];
2017-09-05 04:18:52 +02:00
2021-09-24 20:30:15 +02:00
u32 gWindowTileAutoAllocEnabled;
2017-09-05 04:18:52 +02:00
2017-09-19 14:27:46 +02:00
static const struct BgConfig sZeroedBgControlStruct = { 0 };
2017-09-10 04:48:33 +02:00
2021-09-24 20:30:15 +02:00
static u32 GetBgType(u8 bg);
2017-09-05 04:18:52 +02:00
void ResetBgs(void)
{
ResetBgControlStructs();
2017-09-19 14:27:46 +02:00
sGpuBgConfigs.bgVisibilityAndMode = 0;
2017-09-05 04:18:52 +02:00
SetTextModeAndHideBgs();
}
2017-09-19 14:27:46 +02:00
static void SetBgModeInternal(u8 bgMode)
2017-09-05 04:18:52 +02:00
{
sGpuBgConfigs.bgVisibilityAndMode &= ~0x7;
2017-09-19 14:27:46 +02:00
sGpuBgConfigs.bgVisibilityAndMode |= bgMode;
2017-09-05 04:18:52 +02:00
}
u8 GetBgMode(void)
{
2017-09-19 14:27:46 +02:00
return sGpuBgConfigs.bgVisibilityAndMode & 0x7;
2017-09-05 04:18:52 +02:00
}
void ResetBgControlStructs(void)
{
int i;
2021-02-18 16:00:07 +01:00
for (i = 0; i < NUM_BACKGROUNDS; i++)
2017-09-05 04:18:52 +02:00
{
sGpuBgConfigs.configs[i] = sZeroedBgControlStruct;
2017-09-05 04:18:52 +02:00
}
}
void Unused_ResetBgControlStruct(u8 bg)
{
2018-12-26 13:05:02 +01:00
if (!IsInvalidBg(bg))
2017-09-05 04:18:52 +02:00
{
2017-09-19 14:27:46 +02:00
sGpuBgConfigs.configs[bg] = sZeroedBgControlStruct;
2017-09-05 04:18:52 +02:00
}
}
2018-12-26 13:05:02 +01:00
enum
2017-09-05 04:18:52 +02:00
{
2018-12-26 13:05:02 +01:00
BG_CTRL_ATTR_VISIBLE = 1,
BG_CTRL_ATTR_CHARBASEINDEX = 2,
BG_CTRL_ATTR_MAPBASEINDEX = 3,
BG_CTRL_ATTR_SCREENSIZE = 4,
BG_CTRL_ATTR_PALETTEMODE = 5,
BG_CTRL_ATTR_PRIORITY = 6,
BG_CTRL_ATTR_MOSAIC = 7,
BG_CTRL_ATTR_WRAPAROUND = 8,
};
static void SetBgControlAttributes(u8 bg, u8 charBaseIndex, u8 mapBaseIndex, u8 screenSize, u8 paletteMode, u8 priority, u8 mosaic, u8 wraparound)
{
if (!IsInvalidBg(bg))
2017-09-05 04:18:52 +02:00
{
2017-09-10 03:52:33 +02:00
if (charBaseIndex != 0xFF)
2017-09-05 04:18:52 +02:00
{
2021-02-28 03:31:19 +01:00
sGpuBgConfigs.configs[bg].charBaseIndex = charBaseIndex;
2017-09-05 04:18:52 +02:00
}
2017-09-10 03:52:33 +02:00
if (mapBaseIndex != 0xFF)
2017-09-05 04:18:52 +02:00
{
2021-02-28 03:31:19 +01:00
sGpuBgConfigs.configs[bg].mapBaseIndex = mapBaseIndex;
2017-09-05 04:18:52 +02:00
}
2017-09-05 04:18:52 +02:00
if (screenSize != 0xFF)
{
2021-02-28 03:31:19 +01:00
sGpuBgConfigs.configs[bg].screenSize = screenSize;
2017-09-05 04:18:52 +02:00
}
2017-09-05 04:18:52 +02:00
if (paletteMode != 0xFF)
{
2017-09-19 14:27:46 +02:00
sGpuBgConfigs.configs[bg].paletteMode = paletteMode;
2017-09-05 04:18:52 +02:00
}
2017-09-05 04:18:52 +02:00
if (priority != 0xFF)
{
2021-02-28 03:31:19 +01:00
sGpuBgConfigs.configs[bg].priority = priority;
2017-09-05 04:18:52 +02:00
}
2017-09-05 04:18:52 +02:00
if (mosaic != 0xFF)
{
2021-02-28 03:31:19 +01:00
sGpuBgConfigs.configs[bg].mosaic = mosaic;
2017-09-05 04:18:52 +02:00
}
2017-09-05 04:18:52 +02:00
if (wraparound != 0xFF)
{
2017-09-19 14:27:46 +02:00
sGpuBgConfigs.configs[bg].wraparound = wraparound;
2017-09-05 04:18:52 +02:00
}
2017-09-19 14:27:46 +02:00
sGpuBgConfigs.configs[bg].unknown_2 = 0;
sGpuBgConfigs.configs[bg].unknown_3 = 0;
2017-09-19 14:27:46 +02:00
sGpuBgConfigs.configs[bg].visible = 1;
2017-09-05 04:18:52 +02:00
}
}
2018-12-26 13:05:02 +01:00
static u16 GetBgControlAttribute(u8 bg, u8 attributeId)
2017-09-05 04:18:52 +02:00
{
2018-12-26 13:05:02 +01:00
if (!IsInvalidBg(bg) && sGpuBgConfigs.configs[bg].visible)
2017-09-05 04:18:52 +02:00
{
switch (attributeId)
{
2018-11-25 20:16:41 +01:00
case BG_CTRL_ATTR_VISIBLE:
return sGpuBgConfigs.configs[bg].visible;
case BG_CTRL_ATTR_CHARBASEINDEX:
return sGpuBgConfigs.configs[bg].charBaseIndex;
case BG_CTRL_ATTR_MAPBASEINDEX:
return sGpuBgConfigs.configs[bg].mapBaseIndex;
case BG_CTRL_ATTR_SCREENSIZE:
return sGpuBgConfigs.configs[bg].screenSize;
case BG_CTRL_ATTR_PALETTEMODE:
return sGpuBgConfigs.configs[bg].paletteMode;
case BG_CTRL_ATTR_PRIORITY:
return sGpuBgConfigs.configs[bg].priority;
case BG_CTRL_ATTR_MOSAIC:
return sGpuBgConfigs.configs[bg].mosaic;
case BG_CTRL_ATTR_WRAPAROUND:
return sGpuBgConfigs.configs[bg].wraparound;
2017-09-05 04:18:52 +02:00
}
}
2017-09-05 04:18:52 +02:00
return 0xFF;
}
u8 LoadBgVram(u8 bg, const void *src, u16 size, u16 destOffset, u8 mode)
2017-09-05 04:18:52 +02:00
{
u16 offset;
s8 cursor;
2021-05-24 04:26:34 +02:00
if (IsInvalidBg(bg) || !sGpuBgConfigs.configs[bg].visible)
return -1;
2021-05-24 04:26:34 +02:00
switch (mode)
{
case 0x1:
offset = sGpuBgConfigs.configs[bg].charBaseIndex * BG_CHAR_SIZE;
2017-09-05 04:18:52 +02:00
offset = destOffset + offset;
2022-07-29 16:52:35 +02:00
cursor = RequestDma3Copy(src, (void *)(offset + BG_VRAM), size, 0);
2017-09-05 04:18:52 +02:00
if (cursor == -1)
return -1;
2021-05-24 04:26:34 +02:00
break;
case 0x2:
offset = sGpuBgConfigs.configs[bg].mapBaseIndex * BG_SCREEN_SIZE;
offset = destOffset + offset;
2022-07-29 16:52:35 +02:00
cursor = RequestDma3Copy(src, (void *)(offset + BG_VRAM), size, 0);
2021-05-24 04:26:34 +02:00
if (cursor == -1)
return -1;
break;
default:
cursor = -1;
break;
2017-09-05 04:18:52 +02:00
}
2017-09-05 04:18:52 +02:00
return cursor;
}
2017-09-19 14:27:46 +02:00
static void ShowBgInternal(u8 bg)
2017-09-05 04:18:52 +02:00
{
u16 value;
2018-12-26 13:05:02 +01:00
if (!IsInvalidBg(bg) && sGpuBgConfigs.configs[bg].visible)
2017-09-05 04:18:52 +02:00
{
2017-09-19 14:27:46 +02:00
value = sGpuBgConfigs.configs[bg].priority |
(sGpuBgConfigs.configs[bg].charBaseIndex << 2) |
(sGpuBgConfigs.configs[bg].mosaic << 6) |
(sGpuBgConfigs.configs[bg].paletteMode << 7) |
(sGpuBgConfigs.configs[bg].mapBaseIndex << 8) |
(sGpuBgConfigs.configs[bg].wraparound << 13) |
(sGpuBgConfigs.configs[bg].screenSize << 14);
2019-07-23 22:17:00 +02:00
SetGpuReg((bg << 1) + REG_OFFSET_BG0CNT, value);
2017-09-19 14:27:46 +02:00
sGpuBgConfigs.bgVisibilityAndMode |= 1 << (bg + 8);
sGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS;
2017-09-05 04:18:52 +02:00
}
}
2017-09-19 14:27:46 +02:00
static void HideBgInternal(u8 bg)
2017-09-05 04:18:52 +02:00
{
2018-12-26 13:05:02 +01:00
if (!IsInvalidBg(bg))
2017-09-05 04:18:52 +02:00
{
2017-09-19 14:27:46 +02:00
sGpuBgConfigs.bgVisibilityAndMode &= ~(1 << (bg + 8));
sGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS;
2017-09-05 04:18:52 +02:00
}
}
2017-09-19 14:27:46 +02:00
static void SyncBgVisibilityAndMode(void)
2017-09-05 04:18:52 +02:00
{
2018-12-26 13:05:02 +01:00
SetGpuReg(REG_OFFSET_DISPCNT, (GetGpuReg(REG_OFFSET_DISPCNT) & ~DISPCNT_ALL_BG_AND_MODE_BITS) | sGpuBgConfigs.bgVisibilityAndMode);
2017-09-05 04:18:52 +02:00
}
2017-09-19 14:27:46 +02:00
void SetTextModeAndHideBgs(void)
2017-09-05 04:18:52 +02:00
{
2018-12-26 13:05:02 +01:00
SetGpuReg(REG_OFFSET_DISPCNT, GetGpuReg(REG_OFFSET_DISPCNT) & ~DISPCNT_ALL_BG_AND_MODE_BITS);
2017-09-05 04:18:52 +02:00
}
2019-01-26 21:06:20 +01:00
static void SetBgAffineInternal(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle)
2017-09-05 04:18:52 +02:00
{
struct BgAffineSrcData src;
struct BgAffineDstData dest;
2017-09-19 14:27:46 +02:00
switch (sGpuBgConfigs.bgVisibilityAndMode & 0x7)
2017-09-05 04:18:52 +02:00
{
default:
case 0:
return;
2018-11-25 20:16:41 +01:00
case 1:
if (bg != 2)
return;
break;
case 2:
if (bg != 2 && bg != 3)
2017-09-05 04:18:52 +02:00
return;
2018-11-25 20:16:41 +01:00
break;
2017-09-05 04:18:52 +02:00
}
2017-09-05 04:18:52 +02:00
src.texX = srcCenterX;
src.texY = srcCenterY;
src.scrX = dispCenterX;
src.scrY = dispCenterY;
src.sx = scaleX;
src.sy = scaleY;
src.alpha = rotationAngle;
2017-09-05 04:18:52 +02:00
BgAffineSet(&src, &dest, 1);
SetGpuReg(REG_OFFSET_BG2PA, dest.pa);
SetGpuReg(REG_OFFSET_BG2PB, dest.pb);
SetGpuReg(REG_OFFSET_BG2PC, dest.pc);
SetGpuReg(REG_OFFSET_BG2PD, dest.pd);
SetGpuReg(REG_OFFSET_BG2PA, dest.pa);
SetGpuReg(REG_OFFSET_BG2X_L, (s16)(dest.dx));
SetGpuReg(REG_OFFSET_BG2X_H, (s16)(dest.dx >> 16));
SetGpuReg(REG_OFFSET_BG2Y_L, (s16)(dest.dy));
SetGpuReg(REG_OFFSET_BG2Y_H, (s16)(dest.dy >> 16));
}
bool8 IsInvalidBg(u8 bg)
{
2021-02-18 16:00:07 +01:00
if (bg >= NUM_BACKGROUNDS)
2017-09-05 04:18:52 +02:00
return TRUE;
2018-11-25 20:16:41 +01:00
else
return FALSE;
2017-09-05 04:18:52 +02:00
}
2021-09-24 20:30:15 +02:00
// From FRLG. Dummied out.
int BgTileAllocOp(int bg, int offset, int count, int mode)
2017-09-05 04:18:52 +02:00
{
return 0;
}
void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable)
{
int i;
ResetBgs();
2021-02-18 16:00:07 +01:00
for (i = 0; i < NUM_BACKGROUNDS; i++)
2017-09-05 04:18:52 +02:00
{
2017-09-19 14:27:46 +02:00
sDmaBusyBitfield[i] = 0;
2017-09-05 04:18:52 +02:00
}
2021-09-24 20:30:15 +02:00
gWindowTileAutoAllocEnabled = leftoverFireRedLeafGreenVariable;
2017-09-05 04:18:52 +02:00
}
void InitBgsFromTemplates(u8 bgMode, const struct BgTemplate *templates, u8 numTemplates)
2017-09-05 04:18:52 +02:00
{
int i;
u8 bg;
2017-09-05 04:18:52 +02:00
SetBgModeInternal(bgMode);
ResetBgControlStructs();
for (i = 0; i < numTemplates; i++)
{
bg = templates[i].bg;
2021-02-18 16:00:07 +01:00
if (bg < NUM_BACKGROUNDS)
2018-12-26 13:05:02 +01:00
{
2017-09-05 04:18:52 +02:00
SetBgControlAttributes(bg,
2017-09-10 03:52:33 +02:00
templates[i].charBaseIndex,
templates[i].mapBaseIndex,
2017-09-05 04:18:52 +02:00
templates[i].screenSize,
templates[i].paletteMode,
templates[i].priority,
0,
0);
2017-09-19 14:27:46 +02:00
sGpuBgConfigs2[bg].baseTile = templates[i].baseTile;
sGpuBgConfigs2[bg].basePalette = 0;
sGpuBgConfigs2[bg].unk_3 = 0;
2017-09-19 14:27:46 +02:00
sGpuBgConfigs2[bg].tilemap = NULL;
sGpuBgConfigs2[bg].bg_x = 0;
sGpuBgConfigs2[bg].bg_y = 0;
2017-09-05 04:18:52 +02:00
}
}
}
2017-09-19 14:27:46 +02:00
void InitBgFromTemplate(const struct BgTemplate *template)
2017-09-05 04:18:52 +02:00
{
u8 bg = template->bg;
2021-02-18 16:00:07 +01:00
if (bg < NUM_BACKGROUNDS)
2017-09-05 04:18:52 +02:00
{
SetBgControlAttributes(bg,
2017-09-10 03:52:33 +02:00
template->charBaseIndex,
template->mapBaseIndex,
2017-09-05 04:18:52 +02:00
template->screenSize,
template->paletteMode,
template->priority,
0,
0);
2017-09-19 14:27:46 +02:00
sGpuBgConfigs2[bg].baseTile = template->baseTile;
sGpuBgConfigs2[bg].basePalette = 0;
sGpuBgConfigs2[bg].unk_3 = 0;
2017-09-19 14:27:46 +02:00
sGpuBgConfigs2[bg].tilemap = NULL;
sGpuBgConfigs2[bg].bg_x = 0;
sGpuBgConfigs2[bg].bg_y = 0;
2017-09-05 04:18:52 +02:00
}
}
void SetBgMode(u8 bgMode)
{
SetBgModeInternal(bgMode);
}
2022-07-29 16:52:35 +02:00
u16 LoadBgTiles(u8 bg, const void *src, u16 size, u16 destOffset)
2017-09-05 04:18:52 +02:00
{
2017-09-10 03:52:33 +02:00
u16 tileOffset;
2017-09-05 04:18:52 +02:00
u8 cursor;
2017-09-10 03:52:33 +02:00
if (GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE) == 0)
2017-09-05 04:18:52 +02:00
{
2017-09-19 14:27:46 +02:00
tileOffset = (sGpuBgConfigs2[bg].baseTile + destOffset) * 0x20;
2017-09-05 04:18:52 +02:00
}
else
{
2017-09-19 14:27:46 +02:00
tileOffset = (sGpuBgConfigs2[bg].baseTile + destOffset) * 0x40;
2017-09-05 04:18:52 +02:00
}
2017-09-10 03:52:33 +02:00
cursor = LoadBgVram(bg, src, size, tileOffset, DISPCNT_MODE_1);
2017-09-05 04:18:52 +02:00
if (cursor == 0xFF)
{
return -1;
}
2017-09-19 14:27:46 +02:00
sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20));
2021-09-24 20:30:15 +02:00
if (gWindowTileAutoAllocEnabled == TRUE)
BgTileAllocOp(bg, tileOffset / 0x20, size / 0x20, 1);
2017-09-05 04:18:52 +02:00
return cursor;
}
2017-09-19 14:27:46 +02:00
u16 LoadBgTilemap(u8 bg, const void *src, u16 size, u16 destOffset)
2017-09-05 04:18:52 +02:00
{
2018-12-26 13:05:02 +01:00
u8 cursor = LoadBgVram(bg, src, size, destOffset * 2, DISPCNT_MODE_2);
2017-09-05 04:18:52 +02:00
if (cursor == 0xFF)
{
return -1;
}
2017-09-19 14:27:46 +02:00
sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20));
2017-09-05 04:18:52 +02:00
return cursor;
}
2017-09-19 14:27:46 +02:00
u16 Unused_LoadBgPalette(u8 bg, const void *src, u16 size, u16 destOffset)
2017-09-05 04:18:52 +02:00
{
s8 cursor;
2018-12-26 13:05:02 +01:00
if (!IsInvalidBg32(bg))
2017-09-05 04:18:52 +02:00
{
2018-12-26 13:05:02 +01:00
u16 paletteOffset = (sGpuBgConfigs2[bg].basePalette * 0x20) + (destOffset * 2);
2022-07-29 16:52:35 +02:00
cursor = RequestDma3Copy(src, (void *)(paletteOffset + BG_PLTT), size, 0);
2017-09-05 08:02:31 +02:00
if (cursor == -1)
{
return -1;
}
2017-09-05 04:18:52 +02:00
}
else
{
return -1;
}
2017-09-19 14:27:46 +02:00
sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20));
2017-09-05 04:18:52 +02:00
return (u8)cursor;
}
2017-09-05 08:02:31 +02:00
bool8 IsDma3ManagerBusyWithBgCopy(void)
2017-09-05 04:18:52 +02:00
{
2017-09-07 04:59:34 +02:00
int i;
2017-09-05 08:02:31 +02:00
for (i = 0; i < 0x80; i++)
{
2018-12-26 13:05:02 +01:00
u8 div = i / 0x20;
u8 mod = i % 0x20;
2018-12-26 13:05:02 +01:00
if ((sDmaBusyBitfield[div] & (1 << mod)))
2017-09-05 08:02:31 +02:00
{
2018-12-26 13:05:02 +01:00
s8 reqSpace = CheckForSpaceForDma3Request(i);
2017-09-07 04:59:34 +02:00
if (reqSpace == -1)
2017-09-05 08:02:31 +02:00
{
return TRUE;
}
2017-09-19 14:27:46 +02:00
sDmaBusyBitfield[div] &= ~(1 << mod);
2017-09-05 08:02:31 +02:00
}
}
return FALSE;
2017-09-05 04:18:52 +02:00
}
2017-09-07 04:59:34 +02:00
void ShowBg(u8 bg)
{
ShowBgInternal(bg);
SyncBgVisibilityAndMode();
}
void HideBg(u8 bg)
{
HideBgInternal(bg);
SyncBgVisibilityAndMode();
}
void SetBgAttribute(u8 bg, u8 attributeId, u8 value)
{
switch (attributeId)
{
2018-12-26 13:05:02 +01:00
case BG_ATTR_CHARBASEINDEX:
2018-11-26 20:19:52 +01:00
SetBgControlAttributes(bg, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
break;
2018-12-26 13:05:02 +01:00
case BG_ATTR_MAPBASEINDEX:
2018-11-26 20:19:52 +01:00
SetBgControlAttributes(bg, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
break;
2018-12-26 13:05:02 +01:00
case BG_ATTR_SCREENSIZE:
2018-11-26 20:19:52 +01:00
SetBgControlAttributes(bg, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF);
break;
2018-12-26 13:05:02 +01:00
case BG_ATTR_PALETTEMODE:
2018-11-26 20:19:52 +01:00
SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF);
break;
2018-12-26 13:05:02 +01:00
case BG_ATTR_PRIORITY:
2018-11-26 20:19:52 +01:00
SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF);
break;
2018-12-26 13:05:02 +01:00
case BG_ATTR_MOSAIC:
2018-11-26 20:19:52 +01:00
SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF);
break;
2018-12-26 13:05:02 +01:00
case BG_ATTR_WRAPAROUND:
2018-11-26 20:19:52 +01:00
SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value);
break;
2017-09-07 04:59:34 +02:00
}
}
u16 GetBgAttribute(u8 bg, u8 attributeId)
{
switch (attributeId)
{
2018-12-26 13:05:02 +01:00
case BG_ATTR_CHARBASEINDEX:
2018-11-26 20:19:52 +01:00
return GetBgControlAttribute(bg, BG_CTRL_ATTR_CHARBASEINDEX);
2018-12-26 13:05:02 +01:00
case BG_ATTR_MAPBASEINDEX:
2018-11-26 20:19:52 +01:00
return GetBgControlAttribute(bg, BG_CTRL_ATTR_MAPBASEINDEX);
2018-12-26 13:05:02 +01:00
case BG_ATTR_SCREENSIZE:
2018-11-26 20:19:52 +01:00
return GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
2018-12-26 13:05:02 +01:00
case BG_ATTR_PALETTEMODE:
2018-11-26 20:19:52 +01:00
return GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE);
2018-12-26 13:05:02 +01:00
case BG_ATTR_PRIORITY:
2018-11-26 20:19:52 +01:00
return GetBgControlAttribute(bg, BG_CTRL_ATTR_PRIORITY);
2018-12-26 13:05:02 +01:00
case BG_ATTR_MOSAIC:
2018-11-26 20:19:52 +01:00
return GetBgControlAttribute(bg, BG_CTRL_ATTR_MOSAIC);
2018-12-26 13:05:02 +01:00
case BG_ATTR_WRAPAROUND:
2018-11-26 20:19:52 +01:00
return GetBgControlAttribute(bg, BG_CTRL_ATTR_WRAPAROUND);
2018-12-26 13:05:02 +01:00
case BG_ATTR_METRIC:
2018-11-26 20:19:52 +01:00
switch (GetBgType(bg))
{
2021-09-24 20:30:15 +02:00
case BG_TYPE_NORMAL:
2018-12-17 23:00:08 +01:00
return GetBgMetricTextMode(bg, 0) * 0x800;
2021-09-24 20:30:15 +02:00
case BG_TYPE_AFFINE:
2018-12-17 23:00:08 +01:00
return GetBgMetricAffineMode(bg, 0) * 0x100;
default:
return 0;
2018-11-26 20:19:52 +01:00
}
2018-12-26 13:05:02 +01:00
case BG_ATTR_TYPE:
2018-11-26 20:19:52 +01:00
return GetBgType(bg);
2018-12-26 13:05:02 +01:00
case BG_ATTR_BASETILE:
2018-11-26 20:19:52 +01:00
return sGpuBgConfigs2[bg].baseTile;
default:
return -1;
2017-09-07 04:59:34 +02:00
}
}
2018-12-17 23:00:08 +01:00
s32 ChangeBgX(u8 bg, s32 value, u8 op)
2017-09-07 04:59:34 +02:00
{
u8 mode;
2017-09-10 08:02:23 +02:00
u16 temp1;
u16 temp2;
2018-12-26 13:05:02 +01:00
if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE))
2017-09-07 04:59:34 +02:00
{
return -1;
}
2017-09-07 04:59:34 +02:00
switch (op)
{
2021-10-14 18:12:16 +02:00
case BG_COORD_SET:
2018-11-26 20:19:52 +01:00
default:
sGpuBgConfigs2[bg].bg_x = value;
break;
2021-10-14 18:12:16 +02:00
case BG_COORD_ADD:
2018-11-26 20:19:52 +01:00
sGpuBgConfigs2[bg].bg_x += value;
break;
2021-10-14 18:12:16 +02:00
case BG_COORD_SUB:
2018-11-26 20:19:52 +01:00
sGpuBgConfigs2[bg].bg_x -= value;
break;
2017-09-07 04:59:34 +02:00
}
2017-09-07 04:59:34 +02:00
mode = GetBgMode();
2017-09-07 04:59:34 +02:00
switch (bg)
{
2018-11-26 20:19:52 +01:00
case 0:
temp1 = sGpuBgConfigs2[0].bg_x >> 0x8;
SetGpuReg(REG_OFFSET_BG0HOFS, temp1);
break;
case 1:
temp1 = sGpuBgConfigs2[1].bg_x >> 0x8;
SetGpuReg(REG_OFFSET_BG1HOFS, temp1);
break;
case 2:
if (mode == 0)
{
temp1 = sGpuBgConfigs2[2].bg_x >> 0x8;
SetGpuReg(REG_OFFSET_BG2HOFS, temp1);
}
else
{
temp1 = sGpuBgConfigs2[2].bg_x >> 0x10;
temp2 = sGpuBgConfigs2[2].bg_x & 0xFFFF;
SetGpuReg(REG_OFFSET_BG2X_H, temp1);
SetGpuReg(REG_OFFSET_BG2X_L, temp2);
}
break;
case 3:
if (mode == 0)
{
temp1 = sGpuBgConfigs2[3].bg_x >> 0x8;
SetGpuReg(REG_OFFSET_BG3HOFS, temp1);
}
else if (mode == 2)
{
temp1 = sGpuBgConfigs2[3].bg_x >> 0x10;
temp2 = sGpuBgConfigs2[3].bg_x & 0xFFFF;
SetGpuReg(REG_OFFSET_BG3X_H, temp1);
SetGpuReg(REG_OFFSET_BG3X_L, temp2);
}
break;
2017-09-07 04:59:34 +02:00
}
2017-09-19 14:27:46 +02:00
return sGpuBgConfigs2[bg].bg_x;
2017-09-07 04:59:34 +02:00
}
2018-12-17 23:00:08 +01:00
s32 GetBgX(u8 bg)
2017-09-07 04:59:34 +02:00
{
2018-12-26 13:05:02 +01:00
if (IsInvalidBg32(bg))
2017-09-07 04:59:34 +02:00
return -1;
else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE))
return -1;
else
return sGpuBgConfigs2[bg].bg_x;
2017-09-07 04:59:34 +02:00
}
2018-12-17 23:00:08 +01:00
s32 ChangeBgY(u8 bg, s32 value, u8 op)
2017-09-07 04:59:34 +02:00
{
u8 mode;
u16 temp1;
u16 temp2;
2018-12-26 13:05:02 +01:00
if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE))
2017-09-07 04:59:34 +02:00
{
return -1;
}
2017-09-07 04:59:34 +02:00
switch (op)
{
2021-10-14 18:12:16 +02:00
case BG_COORD_SET:
2018-11-26 20:19:52 +01:00
default:
sGpuBgConfigs2[bg].bg_y = value;
break;
2021-10-14 18:12:16 +02:00
case BG_COORD_ADD:
2018-11-26 20:19:52 +01:00
sGpuBgConfigs2[bg].bg_y += value;
break;
2021-10-14 18:12:16 +02:00
case BG_COORD_SUB:
2018-11-26 20:19:52 +01:00
sGpuBgConfigs2[bg].bg_y -= value;
break;
2017-09-07 04:59:34 +02:00
}
2017-09-07 04:59:34 +02:00
mode = GetBgMode();
2017-09-07 04:59:34 +02:00
switch (bg)
{
2018-11-26 20:19:52 +01:00
case 0:
temp1 = sGpuBgConfigs2[0].bg_y >> 0x8;
SetGpuReg(REG_OFFSET_BG0VOFS, temp1);
break;
case 1:
temp1 = sGpuBgConfigs2[1].bg_y >> 0x8;
SetGpuReg(REG_OFFSET_BG1VOFS, temp1);
break;
case 2:
if (mode == 0)
{
temp1 = sGpuBgConfigs2[2].bg_y >> 0x8;
SetGpuReg(REG_OFFSET_BG2VOFS, temp1);
}
else
{
temp1 = sGpuBgConfigs2[2].bg_y >> 0x10;
temp2 = sGpuBgConfigs2[2].bg_y & 0xFFFF;
SetGpuReg(REG_OFFSET_BG2Y_H, temp1);
SetGpuReg(REG_OFFSET_BG2Y_L, temp2);
}
break;
case 3:
if (mode == 0)
{
temp1 = sGpuBgConfigs2[3].bg_y >> 0x8;
SetGpuReg(REG_OFFSET_BG3VOFS, temp1);
}
else if (mode == 2)
{
temp1 = sGpuBgConfigs2[3].bg_y >> 0x10;
temp2 = sGpuBgConfigs2[3].bg_y & 0xFFFF;
SetGpuReg(REG_OFFSET_BG3Y_H, temp1);
SetGpuReg(REG_OFFSET_BG3Y_L, temp2);
}
break;
2017-09-07 04:59:34 +02:00
}
2017-09-19 14:27:46 +02:00
return sGpuBgConfigs2[bg].bg_y;
2017-09-07 04:59:34 +02:00
}
s32 ChangeBgY_ScreenOff(u8 bg, s32 value, u8 op)
2017-09-07 04:59:34 +02:00
{
u8 mode;
u16 temp1;
u16 temp2;
2018-12-26 13:05:02 +01:00
if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE))
2017-09-07 04:59:34 +02:00
{
return -1;
}
2017-09-07 04:59:34 +02:00
switch (op)
{
2021-10-14 18:12:16 +02:00
case BG_COORD_SET:
2018-11-26 20:19:52 +01:00
default:
sGpuBgConfigs2[bg].bg_y = value;
break;
2021-10-14 18:12:16 +02:00
case BG_COORD_ADD:
2018-11-26 20:19:52 +01:00
sGpuBgConfigs2[bg].bg_y += value;
break;
2021-10-14 18:12:16 +02:00
case BG_COORD_SUB:
2018-11-26 20:19:52 +01:00
sGpuBgConfigs2[bg].bg_y -= value;
break;
2017-09-07 04:59:34 +02:00
}
2017-09-07 04:59:34 +02:00
mode = GetBgMode();
2017-09-07 04:59:34 +02:00
switch (bg)
{
2018-11-26 20:19:52 +01:00
case 0:
temp1 = sGpuBgConfigs2[0].bg_y >> 0x8;
SetGpuReg_ForcedBlank(REG_OFFSET_BG0VOFS, temp1);
break;
case 1:
temp1 = sGpuBgConfigs2[1].bg_y >> 0x8;
SetGpuReg_ForcedBlank(REG_OFFSET_BG1VOFS, temp1);
break;
case 2:
if (mode == 0)
{
temp1 = sGpuBgConfigs2[2].bg_y >> 0x8;
SetGpuReg_ForcedBlank(REG_OFFSET_BG2VOFS, temp1);
}
else
{
temp1 = sGpuBgConfigs2[2].bg_y >> 0x10;
temp2 = sGpuBgConfigs2[2].bg_y & 0xFFFF;
SetGpuReg_ForcedBlank(REG_OFFSET_BG2Y_H, temp1);
SetGpuReg_ForcedBlank(REG_OFFSET_BG2Y_L, temp2);
}
break;
case 3:
if (mode == 0)
{
temp1 = sGpuBgConfigs2[3].bg_y >> 0x8;
SetGpuReg_ForcedBlank(REG_OFFSET_BG3VOFS, temp1);
}
else if (mode == 2)
{
temp1 = sGpuBgConfigs2[3].bg_y >> 0x10;
temp2 = sGpuBgConfigs2[3].bg_y & 0xFFFF;
SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_H, temp1);
SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_L, temp2);
}
break;
2017-09-07 04:59:34 +02:00
}
2017-09-19 14:27:46 +02:00
return sGpuBgConfigs2[bg].bg_y;
2017-09-07 04:59:34 +02:00
}
2018-12-17 23:00:08 +01:00
s32 GetBgY(u8 bg)
2017-09-07 04:59:34 +02:00
{
2018-12-26 13:05:02 +01:00
if (IsInvalidBg32(bg))
2017-09-07 04:59:34 +02:00
return -1;
else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE))
return -1;
else
return sGpuBgConfigs2[bg].bg_y;
2017-09-07 04:59:34 +02:00
}
2019-01-26 21:06:20 +01:00
void SetBgAffine(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle)
2017-09-07 04:59:34 +02:00
{
SetBgAffineInternal(bg, srcCenterX, srcCenterY, dispCenterX, dispCenterY, scaleX, scaleY, rotationAngle);
}
u8 Unused_AdjustBgMosaic(u8 val, u8 mode)
{
u16 mosaic = GetGpuReg(REG_OFFSET_MOSAIC);
s16 bgH = mosaic & 0xF;
s16 bgV = (mosaic >> 4) & 0xF;
mosaic &= 0xFF00; // clear background mosaic sizes
switch (mode)
2017-09-07 04:59:34 +02:00
{
2022-01-14 11:18:46 +01:00
case BG_MOSAIC_SET_HV:
2018-11-26 20:19:52 +01:00
default:
bgH = val & 0xF;
bgV = val >> 0x4;
2018-11-26 20:19:52 +01:00
break;
2022-01-14 11:18:46 +01:00
case BG_MOSAIC_SET_H:
bgH = val & 0xF;
2018-11-26 20:19:52 +01:00
break;
2022-01-14 11:18:46 +01:00
case BG_MOSAIC_ADD_H:
if ((bgH + val) > 0xF)
2018-11-26 20:19:52 +01:00
{
bgH = 0xF;
2018-11-26 20:19:52 +01:00
}
else
{
bgH += val;
2018-11-26 20:19:52 +01:00
}
break;
2022-01-14 11:18:46 +01:00
case BG_MOSAIC_SUB_H:
if ((bgH - val) < 0)
2018-11-26 20:19:52 +01:00
{
bgH = 0x0;
2018-11-26 20:19:52 +01:00
}
else
{
bgH -= val;
2018-11-26 20:19:52 +01:00
}
break;
2022-01-14 11:18:46 +01:00
case BG_MOSAIC_SET_V:
bgV = val & 0xF;
2018-11-26 20:19:52 +01:00
break;
2022-01-14 11:18:46 +01:00
case BG_MOSAIC_ADD_V:
if ((bgV + val) > 0xF)
2018-11-26 20:19:52 +01:00
{
bgV = 0xF;
2018-11-26 20:19:52 +01:00
}
else
{
bgV += val;
2018-11-26 20:19:52 +01:00
}
break;
2022-01-14 11:18:46 +01:00
case BG_MOSAIC_SUB_V:
if ((bgV - val) < 0)
2018-11-26 20:19:52 +01:00
{
bgV = 0x0;
2018-11-26 20:19:52 +01:00
}
else
{
bgV -= val;
2018-11-26 20:19:52 +01:00
}
break;
2017-09-07 04:59:34 +02:00
}
mosaic |= ((bgV << 0x4) & 0xF0);
mosaic |= (bgH & 0xF);
SetGpuReg(REG_OFFSET_MOSAIC, mosaic);
return mosaic;
2017-09-07 04:59:34 +02:00
}
void SetBgTilemapBuffer(u8 bg, void *tilemap)
{
2018-12-26 13:05:02 +01:00
if (!IsInvalidBg32(bg) && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE))
2017-09-07 04:59:34 +02:00
{
2017-09-19 14:27:46 +02:00
sGpuBgConfigs2[bg].tilemap = tilemap;
2017-09-07 04:59:34 +02:00
}
}
void UnsetBgTilemapBuffer(u8 bg)
{
2018-12-26 13:05:02 +01:00
if (!IsInvalidBg32(bg) && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE))
2017-09-07 04:59:34 +02:00
{
2017-09-19 14:27:46 +02:00
sGpuBgConfigs2[bg].tilemap = NULL;
2017-09-07 04:59:34 +02:00
}
}
2022-07-29 16:52:35 +02:00
void *GetBgTilemapBuffer(u8 bg)
2017-09-07 04:59:34 +02:00
{
2018-12-26 13:05:02 +01:00
if (IsInvalidBg32(bg))
2017-09-07 04:59:34 +02:00
return NULL;
else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE))
return NULL;
else
return sGpuBgConfigs2[bg].tilemap;
2017-09-07 04:59:34 +02:00
}
void CopyToBgTilemapBuffer(u8 bg, const void *src, u16 mode, u16 destOffset)
2017-09-07 04:59:34 +02:00
{
if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg))
{
if (mode != 0)
CpuCopy16(src, (void *)(sGpuBgConfigs2[bg].tilemap + (destOffset * 2)), mode);
else
LZ77UnCompWram(src, (void *)(sGpuBgConfigs2[bg].tilemap + (destOffset * 2)));
}
2017-09-07 04:59:34 +02:00
}
void CopyBgTilemapBufferToVram(u8 bg)
{
u16 sizeToLoad;
if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg))
2017-09-07 04:59:34 +02:00
{
switch (GetBgType(bg))
{
2021-09-24 20:30:15 +02:00
case BG_TYPE_NORMAL:
sizeToLoad = GetBgMetricTextMode(bg, 0) * 0x800;
break;
2021-09-24 20:30:15 +02:00
case BG_TYPE_AFFINE:
sizeToLoad = GetBgMetricAffineMode(bg, 0) * 0x100;
break;
default:
sizeToLoad = 0;
break;
}
LoadBgVram(bg, sGpuBgConfigs2[bg].tilemap, sizeToLoad, 0, 2);
2017-09-07 04:59:34 +02:00
}
}
2022-07-29 16:52:35 +02:00
void CopyToBgTilemapBufferRect(u8 bg, const void *src, u8 destX, u8 destY, u8 width, u8 height)
2017-09-07 04:59:34 +02:00
{
u16 destX16;
u16 destY16;
u16 mode;
if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg))
2020-08-24 21:32:57 +02:00
{
switch (GetBgType(bg))
{
2021-09-24 20:30:15 +02:00
case BG_TYPE_NORMAL:
{
const u16 * srcCopy = src;
for (destY16 = destY; destY16 < (destY + height); destY16++)
2018-11-26 20:19:52 +01:00
{
for (destX16 = destX; destX16 < (destX + width); destX16++)
{
((u16 *)sGpuBgConfigs2[bg].tilemap)[((destY16 * 0x20) + destX16)] = *srcCopy++;
}
2018-11-26 20:19:52 +01:00
}
break;
}
2021-09-24 20:30:15 +02:00
case BG_TYPE_AFFINE:
{
const u8 * srcCopy = src;
mode = GetBgMetricAffineMode(bg, 0x1);
for (destY16 = destY; destY16 < (destY + height); destY16++)
2018-11-26 20:19:52 +01:00
{
for (destX16 = destX; destX16 < (destX + width); destX16++)
{
((u8 *)sGpuBgConfigs2[bg].tilemap)[((destY16 * mode) + destX16)] = *srcCopy++;
}
2018-11-26 20:19:52 +01:00
}
break;
}
}
2017-09-07 04:59:34 +02:00
}
}
2018-08-25 19:59:47 +02:00
void CopyToBgTilemapBufferRect_ChangePalette(u8 bg, const void *src, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette)
{
CopyRectToBgTilemapBufferRect(bg, src, 0, 0, rectWidth, rectHeight, destX, destY, rectWidth, rectHeight, palette, 0, 0);
}
void CopyRectToBgTilemapBufferRect(u8 bg, const void *src, u8 srcX, u8 srcY, u8 srcWidth, u8 srcHeight, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette1, s16 tileOffset, s16 palette2)
2018-11-25 20:16:41 +01:00
{
u16 screenWidth, screenHeight, screenSize;
u16 var;
const void *srcPtr;
u16 i, j;
2018-11-25 20:16:41 +01:00
if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg))
{
2018-11-25 20:16:41 +01:00
screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
screenWidth = GetBgMetricTextMode(bg, 0x1) * 0x20;
screenHeight = GetBgMetricTextMode(bg, 0x2) * 0x20;
switch (GetBgType(bg))
{
2021-09-24 20:30:15 +02:00
case BG_TYPE_NORMAL:
2018-11-25 20:16:41 +01:00
srcPtr = src + ((srcY * srcWidth) + srcX) * 2;
for (i = destY; i < (destY + rectHeight); i++)
2018-11-25 20:16:41 +01:00
{
for (j = destX; j < (destX + rectWidth); j++)
{
2018-11-25 20:16:41 +01:00
u16 index = GetTileMapIndexFromCoords(j, i, screenSize, screenWidth, screenHeight);
CopyTileMapEntry(srcPtr, sGpuBgConfigs2[bg].tilemap + (index * 2), palette1, tileOffset, palette2);
2018-11-25 20:16:41 +01:00
srcPtr += 2;
}
srcPtr += (srcWidth - rectWidth) * 2;
2018-11-25 20:16:41 +01:00
}
break;
2021-09-24 20:30:15 +02:00
case BG_TYPE_AFFINE:
2018-11-25 20:16:41 +01:00
srcPtr = src + ((srcY * srcWidth) + srcX);
var = GetBgMetricAffineMode(bg, 0x1);
for (i = destY; i < (destY + rectHeight); i++)
2018-11-25 20:16:41 +01:00
{
for (j = destX; j < (destX + rectWidth); j++)
{
*(u8 *)(sGpuBgConfigs2[bg].tilemap + ((var * i) + j)) = *(u8 *)(srcPtr) + tileOffset;
2018-11-25 20:16:41 +01:00
srcPtr++;
}
srcPtr += (srcWidth - rectWidth);
2018-11-25 20:16:41 +01:00
}
break;
}
}
2017-09-10 02:46:19 +02:00
}
void FillBgTilemapBufferRect_Palette0(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height)
{
u16 x16;
u16 y16;
u16 mode;
2018-12-26 13:05:02 +01:00
if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg))
2017-09-10 02:46:19 +02:00
{
switch (GetBgType(bg))
{
2021-09-24 20:30:15 +02:00
case BG_TYPE_NORMAL:
2018-12-26 13:05:02 +01:00
for (y16 = y; y16 < (y + height); y16++)
{
for (x16 = x; x16 < (x + width); x16++)
2017-09-10 02:46:19 +02:00
{
((u16 *)sGpuBgConfigs2[bg].tilemap)[((y16 * 0x20) + x16)] = tileNum;
2017-09-10 02:46:19 +02:00
}
2018-12-26 13:05:02 +01:00
}
break;
2021-09-24 20:30:15 +02:00
case BG_TYPE_AFFINE:
2018-12-26 13:05:02 +01:00
mode = GetBgMetricAffineMode(bg, 0x1);
for (y16 = y; y16 < (y + height); y16++)
{
for (x16 = x; x16 < (x + width); x16++)
2017-09-10 02:46:19 +02:00
{
((u8 *)sGpuBgConfigs2[bg].tilemap)[((y16 * mode) + x16)] = tileNum;
2017-09-10 02:46:19 +02:00
}
2018-12-26 13:05:02 +01:00
}
break;
2017-09-10 02:46:19 +02:00
}
}
}
void FillBgTilemapBufferRect(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height, u8 palette)
{
WriteSequenceToBgTilemapBuffer(bg, tileNum, x, y, width, height, palette, 0);
}
void WriteSequenceToBgTilemapBuffer(u8 bg, u16 firstTileNum, u8 x, u8 y, u8 width, u8 height, u8 paletteSlot, s16 tileNumDelta)
{
u16 mode;
u16 mode2;
u16 attribute;
u16 mode3;
2018-12-17 23:00:08 +01:00
u16 x16, y16;
2018-12-17 23:00:08 +01:00
if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg))
2017-09-10 02:46:19 +02:00
{
2017-09-10 03:52:33 +02:00
attribute = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
2017-09-10 02:46:19 +02:00
mode = GetBgMetricTextMode(bg, 0x1) * 0x20;
mode2 = GetBgMetricTextMode(bg, 0x2) * 0x20;
switch (GetBgType(bg))
{
2021-09-24 20:30:15 +02:00
case BG_TYPE_NORMAL:
2018-12-17 23:00:08 +01:00
for (y16 = y; y16 < (y + height); y16++)
{
for (x16 = x; x16 < (x + width); x16++)
2017-09-10 02:46:19 +02:00
{
CopyTileMapEntry(&firstTileNum, &((u16 *)sGpuBgConfigs2[bg].tilemap)[(u16)GetTileMapIndexFromCoords(x16, y16, attribute, mode, mode2)], paletteSlot, 0, 0);
2022-01-19 16:15:32 +01:00
firstTileNum = (firstTileNum & (MAPGRID_COLLISION_MASK | MAPGRID_ELEVATION_MASK)) + ((firstTileNum + tileNumDelta) & MAPGRID_METATILE_ID_MASK);
2017-09-10 02:46:19 +02:00
}
2018-12-17 23:00:08 +01:00
}
break;
2021-09-24 20:30:15 +02:00
case BG_TYPE_AFFINE:
2018-12-17 23:00:08 +01:00
mode3 = GetBgMetricAffineMode(bg, 0x1);
for (y16 = y; y16 < (y + height); y16++)
{
for (x16 = x; x16 < (x + width); x16++)
2017-09-10 02:46:19 +02:00
{
((u8 *)sGpuBgConfigs2[bg].tilemap)[(y16 * mode3) + x16] = firstTileNum;
2022-01-19 16:15:32 +01:00
firstTileNum = (firstTileNum & (MAPGRID_COLLISION_MASK | MAPGRID_ELEVATION_MASK)) + ((firstTileNum + tileNumDelta) & MAPGRID_METATILE_ID_MASK);
2017-09-10 02:46:19 +02:00
}
2018-12-17 23:00:08 +01:00
}
break;
2017-09-10 02:46:19 +02:00
}
}
}
u16 GetBgMetricTextMode(u8 bg, u8 whichMetric)
{
2018-12-26 13:05:02 +01:00
u8 screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
2017-09-10 02:46:19 +02:00
switch (whichMetric)
{
2018-11-25 20:16:41 +01:00
case 0:
2018-12-26 13:05:02 +01:00
switch (screenSize)
2018-11-25 20:16:41 +01:00
{
2017-09-10 02:46:19 +02:00
case 0:
2018-11-25 20:16:41 +01:00
return 1;
2017-09-10 02:46:19 +02:00
case 1:
case 2:
2018-11-25 20:16:41 +01:00
return 2;
case 3:
return 4;
}
break;
case 1:
2018-12-26 13:05:02 +01:00
switch (screenSize)
2018-11-25 20:16:41 +01:00
{
case 0:
return 1;
case 1:
return 2;
case 2:
return 1;
case 3:
return 2;
}
break;
case 2:
2018-12-26 13:05:02 +01:00
switch (screenSize)
2018-11-25 20:16:41 +01:00
{
case 0:
case 1:
return 1;
case 2:
case 3:
return 2;
}
break;
2017-09-10 02:46:19 +02:00
}
return 0;
}
u32 GetBgMetricAffineMode(u8 bg, u8 whichMetric)
{
2018-12-26 13:05:02 +01:00
u8 screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
2017-09-10 02:46:19 +02:00
switch (whichMetric)
{
2018-11-25 20:16:41 +01:00
case 0:
2018-12-26 13:05:02 +01:00
switch (screenSize)
2018-11-25 20:16:41 +01:00
{
2017-09-10 02:46:19 +02:00
case 0:
2018-11-25 20:16:41 +01:00
return 0x1;
2017-09-10 02:46:19 +02:00
case 1:
2018-11-25 20:16:41 +01:00
return 0x4;
2017-09-10 02:46:19 +02:00
case 2:
2018-11-25 20:16:41 +01:00
return 0x10;
case 3:
return 0x40;
}
break;
case 1:
case 2:
2018-12-26 13:05:02 +01:00
return 0x10 << screenSize;
2017-09-10 02:46:19 +02:00
}
return 0;
}
u32 GetTileMapIndexFromCoords(s32 x, s32 y, s32 screenSize, u32 screenWidth, u32 screenHeight)
{
x = x & (screenWidth - 1);
y = y & (screenHeight - 1);
2017-09-10 02:46:19 +02:00
switch (screenSize)
{
2018-11-25 20:16:41 +01:00
case 0:
case 2:
break;
case 3:
if (y >= 0x20)
y += 0x20;
case 1:
if (x >= 0x20)
{
x -= 0x20;
y += 0x20;
}
break;
2017-09-10 02:46:19 +02:00
}
return (y * 0x20) + x;
}
2018-11-25 20:16:41 +01:00
void CopyTileMapEntry(const u16 *src, u16 *dest, s32 palette1, s32 tileOffset, s32 palette2)
2017-09-10 02:46:19 +02:00
{
2018-11-25 20:16:41 +01:00
u16 var;
2019-08-27 23:58:19 +02:00
2017-09-10 02:46:19 +02:00
switch (palette1)
{
2020-04-28 01:29:15 +02:00
case 0 ... 15:
2019-08-27 23:58:19 +02:00
var = ((*src + tileOffset) & 0xFFF) + ((palette1 + palette2) << 12);
break;
2020-04-28 01:29:15 +02:00
case 16:
2019-08-27 23:58:19 +02:00
var = *dest;
var &= 0xFC00;
var += palette2 << 12;
var |= (*src + tileOffset) & 0x3FF;
2018-11-25 20:16:41 +01:00
break;
default:
2020-04-28 01:29:15 +02:00
case 17 ... INT_MAX:
2018-11-25 20:16:41 +01:00
var = *src + tileOffset + (palette2 << 12);
break;
2017-09-10 02:46:19 +02:00
}
2018-11-25 20:16:41 +01:00
*dest = var;
2017-09-10 02:46:19 +02:00
}
2021-09-24 20:30:15 +02:00
static u32 GetBgType(u8 bg)
2017-09-10 02:46:19 +02:00
{
2018-11-25 20:16:41 +01:00
u8 mode = GetBgMode();
2017-09-10 02:46:19 +02:00
switch (bg)
{
2018-11-25 20:16:41 +01:00
case 0:
case 1:
switch (mode)
{
2017-09-10 02:46:19 +02:00
case 0:
case 1:
2021-09-24 20:30:15 +02:00
return BG_TYPE_NORMAL;
2018-11-25 20:16:41 +01:00
}
break;
case 2:
switch (mode)
{
case 0:
2021-09-24 20:30:15 +02:00
return BG_TYPE_NORMAL;
2018-11-25 20:16:41 +01:00
case 1:
2017-09-10 02:46:19 +02:00
case 2:
2021-09-24 20:30:15 +02:00
return BG_TYPE_AFFINE;
2018-11-25 20:16:41 +01:00
}
break;
case 3:
switch (mode)
{
case 0:
2021-09-24 20:30:15 +02:00
return BG_TYPE_NORMAL;
2018-11-25 20:16:41 +01:00
case 2:
2021-09-24 20:30:15 +02:00
return BG_TYPE_AFFINE;
2018-11-25 20:16:41 +01:00
}
break;
2017-09-10 02:46:19 +02:00
}
2021-09-24 20:30:15 +02:00
return BG_TYPE_NONE;
2017-09-10 02:46:19 +02:00
}
bool32 IsInvalidBg32(u8 bg)
{
2021-02-18 16:00:07 +01:00
if (bg >= NUM_BACKGROUNDS)
2017-09-10 02:46:19 +02:00
return TRUE;
2018-11-25 20:16:41 +01:00
else
return FALSE;
2017-09-10 02:46:19 +02:00
}
bool32 IsTileMapOutsideWram(u8 bg)
{
2022-07-29 16:52:35 +02:00
if (sGpuBgConfigs2[bg].tilemap > (void *)IWRAM_END)
2017-09-10 02:46:19 +02:00
return TRUE;
2018-11-25 20:16:41 +01:00
else if (sGpuBgConfigs2[bg].tilemap == NULL)
2017-09-10 02:46:19 +02:00
return TRUE;
2018-11-25 20:16:41 +01:00
else
return FALSE;
2017-09-10 02:46:19 +02:00
}