summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCameron Hall <camthesaxman@users.noreply.github.com>2017-09-10 16:13:17 -0500
committerGitHub <noreply@github.com>2017-09-10 16:13:17 -0500
commit6292b82503bf2eb611e5fea6f1710b25578d4fc8 (patch)
tree9a74dd3c29a244bfc06ce5377069eb6bf104b6ee /src
parent7e9948ba2b43d9773cd46959f1f32f029d18c20c (diff)
parent1b220ed2ed367011aa3437b384b2159c0a0130c9 (diff)
Merge pull request #26 from Diegoisawesome/master
Decompile bg.s
Diffstat (limited to 'src')
-rw-r--r--src/bg.c1642
1 files changed, 1642 insertions, 0 deletions
diff --git a/src/bg.c b/src/bg.c
new file mode 100644
index 000000000..8979eaecd
--- /dev/null
+++ b/src/bg.c
@@ -0,0 +1,1642 @@
+#include "global.h"
+#include "dma3.h"
+
+#define DISPCNT_ALL_BG_AND_MODE_BITS 0x0F07
+
+enum {
+ 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,
+};
+
+struct BgControl {
+ struct BgConfig {
+ u16 visible:1;
+ u16 unknown_1:1;
+ u16 screenSize:2;
+ u16 priority:2;
+ u16 mosaic:1;
+ u16 wraparound:1;
+
+ u16 charBaseIndex:2;
+ u16 mapBaseIndex:5;
+ u16 paletteMode:1;
+
+ u8 unknown_2;
+ u8 unknown_3;
+ } configs[4];
+
+ u16 bgVisibilityAndMode;
+};
+
+struct BgTemplate {
+ u32 bg:2;
+ u32 charBaseIndex:2;
+ u32 mapBaseIndex:5;
+ u32 screenSize:2;
+ u32 paletteMode:1;
+ u32 priority:2;
+ u32 baseTile:10;
+};
+
+struct BgConfig2 {
+ u32 baseTile:10;
+ u32 basePalette:4;
+ u32 unk_3:18;
+
+ void* tilemap;
+ u32 bg_x;
+ u32 bg_y;
+};
+
+static struct BgControl gGpuBgConfigs;
+static struct BgConfig2 gGpuBgConfigs2[4];
+static u32 gDmaBusyBitfield[4];
+
+u32 gUnneededFireRedVariable;
+
+static const struct BgConfig gZeroedBgControlStruct = { 0 };
+
+extern void SetGpuReg(u8 regOffset, u16 value);
+extern void SetGpuReg_ForcedBlank(u8 regOffset, u16 value);
+extern u16 GetGpuReg(u8 regOffset);
+extern int CheckForSpaceForDma3Request(s16 index);
+
+bool32 IsInvalidBg32(u8);
+void ResetBgControlStructs();
+u16 GetBgMetricTextMode(u8, u8);
+u32 GetBgMetricAffineMode(u8, u8);
+u32 GetBgType(u8);
+void SetTextModeAndHideBgs();
+bool8 IsInvalidBg(u8);
+bool32 IsTileMapOutsideWram(u8);
+void CopyRectToBgTilemapBufferRect(u8, void*, u8, u8, u8, u8, u8, u8, u8, u8, u8, u16, u16);
+void CopyTileMapEntry(u16*, u16*, s32, u32, u32);
+u32 GetTileMapIndexFromCoords(s32, s32, s32, u32, u32);
+void WriteSequenceToBgTilemapBuffer(u8, u16, u8, u8, u8, u8, u8, s16);
+
+void ResetBgs(void)
+{
+ ResetBgControlStructs();
+ gGpuBgConfigs.bgVisibilityAndMode = 0;
+ SetTextModeAndHideBgs();
+}
+
+void SetBgModeInternal(u8 bgMode)
+{
+ gGpuBgConfigs.bgVisibilityAndMode &= 0xFFF8;
+ gGpuBgConfigs.bgVisibilityAndMode |= bgMode;
+}
+
+u8 GetBgMode(void)
+{
+ return gGpuBgConfigs.bgVisibilityAndMode & 0x7;
+}
+
+void ResetBgControlStructs(void)
+{
+ struct BgConfig* bgConfigs = &gGpuBgConfigs.configs[0];
+ struct BgConfig zeroedConfig = gZeroedBgControlStruct;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ bgConfigs[i] = zeroedConfig;
+ }
+}
+
+void Unused_ResetBgControlStruct(u8 bg)
+{
+ if (IsInvalidBg(bg) == FALSE)
+ {
+ gGpuBgConfigs.configs[bg] = gZeroedBgControlStruct;
+ }
+}
+
+void SetBgControlAttributes(u8 bg, u8 charBaseIndex, u8 mapBaseIndex, u8 screenSize, u8 paletteMode, u8 priority, u8 mosaic, u8 wraparound)
+{
+ if (IsInvalidBg(bg) == FALSE)
+ {
+ if (charBaseIndex != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].charBaseIndex = charBaseIndex & 0x3;
+ }
+
+ if (mapBaseIndex != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].mapBaseIndex = mapBaseIndex & 0x1F;
+ }
+
+ if (screenSize != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].screenSize = screenSize & 0x3;
+ }
+
+ if (paletteMode != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].paletteMode = paletteMode;
+ }
+
+ if (priority != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].priority = priority & 0x3;
+ }
+
+ if (mosaic != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].mosaic = mosaic & 0x1;
+ }
+
+ if (wraparound != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].wraparound = wraparound;
+ }
+
+ gGpuBgConfigs.configs[bg].unknown_2 = 0;
+ gGpuBgConfigs.configs[bg].unknown_3 = 0;
+
+ gGpuBgConfigs.configs[bg].visible = 1;
+ }
+}
+
+u16 GetBgControlAttribute(u8 bg, u8 attributeId)
+{
+ if (IsInvalidBg(bg) == FALSE && gGpuBgConfigs.configs[bg].visible != FALSE)
+ {
+ switch (attributeId)
+ {
+ case BG_CTRL_ATTR_VISIBLE:
+ return gGpuBgConfigs.configs[bg].visible;
+ case BG_CTRL_ATTR_CHARBASEINDEX:
+ return gGpuBgConfigs.configs[bg].charBaseIndex;
+ case BG_CTRL_ATTR_MAPBASEINDEX:
+ return gGpuBgConfigs.configs[bg].mapBaseIndex;
+ case BG_CTRL_ATTR_SCREENSIZE:
+ return gGpuBgConfigs.configs[bg].screenSize;
+ case BG_CTRL_ATTR_PALETTEMODE:
+ return gGpuBgConfigs.configs[bg].paletteMode;
+ case BG_CTRL_ATTR_PRIORITY:
+ return gGpuBgConfigs.configs[bg].priority;
+ case BG_CTRL_ATTR_MOSAIC:
+ return gGpuBgConfigs.configs[bg].mosaic;
+ case BG_CTRL_ATTR_WRAPAROUND:
+ return gGpuBgConfigs.configs[bg].wraparound;
+ }
+ }
+
+ return 0xFF;
+}
+
+u8 LoadBgVram(u8 bg, void *src, u16 size, u16 destOffset, u8 mode)
+{
+ u16 offset;
+ s8 cursor;
+
+ if (IsInvalidBg(bg) == FALSE && gGpuBgConfigs.configs[bg].visible != FALSE)
+ {
+ switch (mode)
+ {
+ case 0x1:
+ offset = gGpuBgConfigs.configs[bg].charBaseIndex * BG_CHAR_SIZE;
+ break;
+ case 0x2:
+ offset = gGpuBgConfigs.configs[bg].mapBaseIndex * BG_SCREEN_SIZE;
+ break;
+ default:
+ cursor = -1;
+ goto end;
+ }
+
+ offset = destOffset + offset;
+
+ cursor = RequestDma3Copy(src, (void*)(offset + BG_VRAM), size, 0);
+
+ if (cursor == -1)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+
+end:
+ return cursor;
+}
+
+void ShowBgInternal(u8 bg)
+{
+ u16 value;
+ if (IsInvalidBg(bg) == FALSE && gGpuBgConfigs.configs[bg].visible != FALSE)
+ {
+ value = gGpuBgConfigs.configs[bg].priority |
+ (gGpuBgConfigs.configs[bg].charBaseIndex << 2) |
+ (gGpuBgConfigs.configs[bg].mosaic << 6) |
+ (gGpuBgConfigs.configs[bg].paletteMode << 7) |
+ (gGpuBgConfigs.configs[bg].mapBaseIndex << 8) |
+ (gGpuBgConfigs.configs[bg].wraparound << 13) |
+ (gGpuBgConfigs.configs[bg].screenSize << 14);
+
+ SetGpuReg((bg << 1) + 0x8, value);
+
+ gGpuBgConfigs.bgVisibilityAndMode |= 1 << (bg + 8);
+ gGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS;
+ }
+}
+
+void HideBgInternal(u8 bg)
+{
+ if (IsInvalidBg(bg) == FALSE)
+ {
+ gGpuBgConfigs.bgVisibilityAndMode &= ~(1 << (bg + 8));
+ gGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS;
+ }
+}
+
+void SyncBgVisibilityAndMode()
+{
+ SetGpuReg(0, (GetGpuReg(0) & ~DISPCNT_ALL_BG_AND_MODE_BITS) | gGpuBgConfigs.bgVisibilityAndMode);
+}
+
+void SetTextModeAndHideBgs()
+{
+ SetGpuReg(0, GetGpuReg(0) & ~DISPCNT_ALL_BG_AND_MODE_BITS);
+}
+
+void SetBgAffineInternal(u8 bg, u32 srcCenterX, u32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle)
+{
+ struct BgAffineSrcData src;
+ struct BgAffineDstData dest;
+
+ switch (gGpuBgConfigs.bgVisibilityAndMode & 0x7)
+ {
+ case 1:
+ if (bg != 2)
+ return;
+ break;
+ case 2:
+ if (bg < 2 || bg > 3)
+ return;
+ break;
+ case 0:
+ default:
+ return;
+ }
+
+ src.texX = srcCenterX;
+ src.texY = srcCenterY;
+ src.scrX = dispCenterX;
+ src.scrY = dispCenterY;
+ src.sx = scaleX;
+ src.sy = scaleY;
+ src.alpha = rotationAngle;
+
+ 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)
+{
+ if (bg > 3)
+ return TRUE;
+ return FALSE;
+}
+
+int DummiedOutFireRedLeafGreenTileAllocFunc(int a1, int a2, int a3, int a4)
+{
+ return 0;
+}
+
+void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable)
+{
+ int i;
+ ResetBgs();
+
+ for (i = 0; i < 4; i++)
+ {
+ gDmaBusyBitfield[i] = 0;
+ }
+
+ gUnneededFireRedVariable = leftoverFireRedLeafGreenVariable;
+}
+
+void InitBgsFromTemplates(u8 bgMode, struct BgTemplate *templates, u8 numTemplates)
+{
+ int i;
+ u8 bg;
+
+ SetBgModeInternal(bgMode);
+ ResetBgControlStructs();
+
+ for (i = 0; i < numTemplates; i++)
+ {
+ bg = templates[i].bg;
+ if (bg < 4) {
+ SetBgControlAttributes(bg,
+ templates[i].charBaseIndex,
+ templates[i].mapBaseIndex,
+ templates[i].screenSize,
+ templates[i].paletteMode,
+ templates[i].priority,
+ 0,
+ 0);
+
+ gGpuBgConfigs2[bg].baseTile = templates[i].baseTile;
+ gGpuBgConfigs2[bg].basePalette = 0;
+ gGpuBgConfigs2[bg].unk_3 = 0;
+
+ gGpuBgConfigs2[bg].tilemap = NULL;
+ gGpuBgConfigs2[bg].bg_x = 0;
+ gGpuBgConfigs2[bg].bg_y = 0;
+ }
+ }
+}
+
+void InitBgFromTemplate(struct BgTemplate *template)
+{
+ u8 bg = template->bg;
+
+ if (bg < 4)
+ {
+ SetBgControlAttributes(bg,
+ template->charBaseIndex,
+ template->mapBaseIndex,
+ template->screenSize,
+ template->paletteMode,
+ template->priority,
+ 0,
+ 0);
+
+ gGpuBgConfigs2[bg].baseTile = template->baseTile;
+ gGpuBgConfigs2[bg].basePalette = 0;
+ gGpuBgConfigs2[bg].unk_3 = 0;
+
+ gGpuBgConfigs2[bg].tilemap = NULL;
+ gGpuBgConfigs2[bg].bg_x = 0;
+ gGpuBgConfigs2[bg].bg_y = 0;
+ }
+}
+
+void SetBgMode(u8 bgMode)
+{
+ SetBgModeInternal(bgMode);
+}
+
+u16 LoadBgTiles(u8 bg, void* src, u16 size, u16 destOffset)
+{
+ u16 tileOffset;
+ u8 cursor;
+
+ if (GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE) == 0)
+ {
+ tileOffset = (gGpuBgConfigs2[bg].baseTile + destOffset) * 0x20;
+ }
+ else
+ {
+ tileOffset = (gGpuBgConfigs2[bg].baseTile + destOffset) * 0x40;
+ }
+
+ cursor = LoadBgVram(bg, src, size, tileOffset, DISPCNT_MODE_1);
+
+ if (cursor == 0xFF)
+ {
+ return -1;
+ }
+
+ gDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20));
+
+ if (gUnneededFireRedVariable == 1)
+ {
+ DummiedOutFireRedLeafGreenTileAllocFunc(bg, tileOffset / 0x20, size / 0x20, 1);
+ }
+
+ return cursor;
+}
+
+u16 LoadBgTilemap(u8 bg, void *src, u16 size, u16 destOffset)
+{
+ u8 cursor;
+
+ cursor = LoadBgVram(bg, src, size, destOffset * 2, DISPCNT_MODE_2);
+
+ if (cursor == 0xFF)
+ {
+ return -1;
+ }
+
+ gDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20));
+
+ return cursor;
+}
+
+u16 Unused_LoadBgPalette(u8 bg, void *src, u16 size, u16 destOffset)
+{
+ u16 paletteOffset;
+ s8 cursor;
+
+ if (IsInvalidBg32(bg) == FALSE)
+ {
+ paletteOffset = (gGpuBgConfigs2[bg].basePalette * 0x20) + (destOffset * 2);
+ cursor = RequestDma3Copy(src, (void*)(paletteOffset + BG_PLTT), size, 0);
+
+ if (cursor == -1)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+
+ gDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20));
+
+ return (u8)cursor;
+}
+
+#ifdef NONMATCHING // Matches everything but r5 and r6 are flipped, rrr
+bool8 IsDma3ManagerBusyWithBgCopy(void)
+{
+ u8 mod;
+ u8 div;
+ s8 reqSpace;
+
+ int i;
+
+ for (i = 0; i < 0x80; i++)
+ {
+ div = i / 0x20;
+ mod = i % 0x20;
+
+ if ((gDmaBusyBitfield[div] & (1 << mod)) != FALSE)
+ {
+ reqSpace = CheckForSpaceForDma3Request(i);
+ if (reqSpace == -1)
+ {
+ return TRUE;
+ }
+
+ gDmaBusyBitfield[div] &= ~(1 << mod);
+ }
+ }
+
+ return FALSE;
+}
+#else
+__attribute__((naked))
+bool8 IsDma3ManagerBusyWithBgCopy(void)
+{
+ asm("push {r4-r7,lr}\n\
+ mov r5, #0\n\
+ mov r7, #0x1\n\
+ neg r7, r7\n\
+_08001ADC:\n\
+ add r0, r5, #0\n\
+ cmp r5, #0\n\
+ bge _08001AE4\n\
+ add r0, #0x1F\n\
+_08001AE4:\n\
+ asr r0, #5\n\
+ lsl r2, r0, #24\n\
+ lsl r0, #5\n\
+ sub r0, r5, r0\n\
+ lsl r0, #24\n\
+ lsr r0, #24\n\
+ ldr r1, =gDmaBusyBitfield\n\
+ lsr r2, #22\n\
+ add r4, r2, r1\n\
+ mov r6, #0x1\n\
+ lsl r6, r0\n\
+ ldr r0, [r4]\n\
+ and r0, r6\n\
+ cmp r0, #0\n\
+ beq _08001B22\n\
+ lsl r0, r5, #16\n\
+ asr r0, #16\n\
+ bl CheckForSpaceForDma3Request\n\
+ lsl r0, #24\n\
+ asr r0, #24\n\
+ cmp r0, r7\n\
+ bne _08001B1C\n\
+ mov r0, #0x1\n\
+ b _08001B2A\n\
+ .pool\n\
+_08001B1C:\n\
+ ldr r0, [r4]\n\
+ bic r0, r6\n\
+ str r0, [r4]\n\
+_08001B22:\n\
+ add r5, #0x1\n\
+ cmp r5, #0x7F\n\
+ ble _08001ADC\n\
+ mov r0, #0\n\
+_08001B2A:\n\
+ pop {r4-r7}\n\
+ pop {r1}\n\
+ bx r1\n");
+}
+#endif // NONMATCHING
+
+void ShowBg(u8 bg)
+{
+ ShowBgInternal(bg);
+ SyncBgVisibilityAndMode();
+}
+
+void HideBg(u8 bg)
+{
+ HideBgInternal(bg);
+ SyncBgVisibilityAndMode();
+}
+
+void SetBgAttribute(u8 bg, u8 attributeId, u8 value)
+{
+ switch (attributeId)
+ {
+ case 1:
+ SetBgControlAttributes(bg, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
+ break;
+ case 2:
+ SetBgControlAttributes(bg, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
+ break;
+ case 3:
+ SetBgControlAttributes(bg, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF);
+ break;
+ case 4:
+ SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF);
+ break;
+ case 7:
+ SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF);
+ break;
+ case 5:
+ SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF);
+ break;
+ case 6:
+ SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value);
+ break;
+ }
+}
+
+u16 GetBgAttribute(u8 bg, u8 attributeId)
+{
+ switch (attributeId)
+ {
+ case 1:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_CHARBASEINDEX);
+ case 2:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_MAPBASEINDEX);
+ case 3:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
+ case 4:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE);
+ case 7:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_PRIORITY);
+ case 5:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_MOSAIC);
+ case 6:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_WRAPAROUND);
+ case 8:
+ switch (GetBgType(bg))
+ {
+ case 0:
+ return GetBgMetricTextMode(bg, 0) * 0x800;
+ case 1:
+ return GetBgMetricAffineMode(bg, 0) * 0x100;
+ default:
+ return 0;
+ }
+ case 9:
+ return GetBgType(bg);
+ case 10:
+ return gGpuBgConfigs2[bg].baseTile;
+ default:
+ return -1;
+ }
+}
+
+u32 ChangeBgX(u8 bg, u32 value, u8 op)
+{
+ u8 mode;
+ u16 temp1;
+ u16 temp2;
+
+ if (IsInvalidBg32(bg) != FALSE || GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) == 0)
+ {
+ return -1;
+ }
+
+ switch (op)
+ {
+ case 0:
+ default:
+ gGpuBgConfigs2[bg].bg_x = value;
+ break;
+ case 1:
+ gGpuBgConfigs2[bg].bg_x += value;
+ break;
+ case 2:
+ gGpuBgConfigs2[bg].bg_x -= value;
+ break;
+ }
+
+ mode = GetBgMode();
+
+ switch (bg)
+ {
+ case 0:
+ temp1 = gGpuBgConfigs2[0].bg_x >> 0x8;
+ SetGpuReg(REG_OFFSET_BG0HOFS, temp1);
+ break;
+ case 1:
+ temp1 = gGpuBgConfigs2[1].bg_x >> 0x8;
+ SetGpuReg(REG_OFFSET_BG1HOFS, temp1);
+ break;
+ case 2:
+ if (mode == 0)
+ {
+ temp1 = gGpuBgConfigs2[2].bg_x >> 0x8;
+ SetGpuReg(REG_OFFSET_BG2HOFS, temp1);
+ }
+ else
+ {
+ temp1 = gGpuBgConfigs2[2].bg_x >> 0x10;
+ temp2 = gGpuBgConfigs2[2].bg_x & 0xFFFF;
+ SetGpuReg(REG_OFFSET_BG2X_H, temp1);
+ SetGpuReg(REG_OFFSET_BG2X_L, temp2);
+ }
+ break;
+ case 3:
+ if (mode == 0)
+ {
+ temp1 = gGpuBgConfigs2[3].bg_x >> 0x8;
+ SetGpuReg(REG_OFFSET_BG3HOFS, temp1);
+ }
+ else if (mode == 2)
+ {
+ temp1 = gGpuBgConfigs2[3].bg_x >> 0x10;
+ temp2 = gGpuBgConfigs2[3].bg_x & 0xFFFF;
+ SetGpuReg(REG_OFFSET_BG3X_H, temp1);
+ SetGpuReg(REG_OFFSET_BG3X_L, temp2);
+ }
+ break;
+ }
+
+ return gGpuBgConfigs2[bg].bg_x;
+}
+
+u32 GetBgX(u8 bg)
+{
+ if (IsInvalidBg32(bg) != FALSE)
+ return -1;
+ if (GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) == 0)
+ return -1;
+ return gGpuBgConfigs2[bg].bg_x;
+}
+
+u32 ChangeBgY(u8 bg, u32 value, u8 op)
+{
+ u8 mode;
+ u16 temp1;
+ u16 temp2;
+
+ if (IsInvalidBg32(bg) != FALSE || GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) == 0)
+ {
+ return -1;
+ }
+
+ switch (op)
+ {
+ case 0:
+ default:
+ gGpuBgConfigs2[bg].bg_y = value;
+ break;
+ case 1:
+ gGpuBgConfigs2[bg].bg_y += value;
+ break;
+ case 2:
+ gGpuBgConfigs2[bg].bg_y -= value;
+ break;
+ }
+
+ mode = GetBgMode();
+
+ switch (bg)
+ {
+ case 0:
+ temp1 = gGpuBgConfigs2[0].bg_y >> 0x8;
+ SetGpuReg(REG_OFFSET_BG0VOFS, temp1);
+ break;
+ case 1:
+ temp1 = gGpuBgConfigs2[1].bg_y >> 0x8;
+ SetGpuReg(REG_OFFSET_BG1VOFS, temp1);
+ break;
+ case 2:
+ if (mode == 0)
+ {
+ temp1 = gGpuBgConfigs2[2].bg_y >> 0x8;
+ SetGpuReg(REG_OFFSET_BG2VOFS, temp1);
+ }
+ else
+ {
+ temp1 = gGpuBgConfigs2[2].bg_y >> 0x10;
+ temp2 = gGpuBgConfigs2[2].bg_y & 0xFFFF;
+ SetGpuReg(REG_OFFSET_BG2Y_H, temp1);
+ SetGpuReg(REG_OFFSET_BG2Y_L, temp2);
+ }
+ break;
+ case 3:
+ if (mode == 0)
+ {
+ temp1 = gGpuBgConfigs2[3].bg_y >> 0x8;
+ SetGpuReg(REG_OFFSET_BG3VOFS, temp1);
+ }
+ else if (mode == 2)
+ {
+ temp1 = gGpuBgConfigs2[3].bg_y >> 0x10;
+ temp2 = gGpuBgConfigs2[3].bg_y & 0xFFFF;
+ SetGpuReg(REG_OFFSET_BG3Y_H, temp1);
+ SetGpuReg(REG_OFFSET_BG3Y_L, temp2);
+ }
+ break;
+ }
+
+ return gGpuBgConfigs2[bg].bg_y;
+}
+
+u32 ChangeBgY_ScreenOff(u8 bg, u32 value, u8 op)
+{
+ u8 mode;
+ u16 temp1;
+ u16 temp2;
+
+ if (IsInvalidBg32(bg) != FALSE || GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) == 0)
+ {
+ return -1;
+ }
+
+ switch (op)
+ {
+ case 0:
+ default:
+ gGpuBgConfigs2[bg].bg_y = value;
+ break;
+ case 1:
+ gGpuBgConfigs2[bg].bg_y += value;
+ break;
+ case 2:
+ gGpuBgConfigs2[bg].bg_y -= value;
+ break;
+ }
+
+ mode = GetBgMode();
+
+ switch (bg)
+ {
+ case 0:
+ temp1 = gGpuBgConfigs2[0].bg_y >> 0x8;
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG0VOFS, temp1);
+ break;
+ case 1:
+ temp1 = gGpuBgConfigs2[1].bg_y >> 0x8;
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG1VOFS, temp1);
+ break;
+ case 2:
+ if (mode == 0)
+ {
+ temp1 = gGpuBgConfigs2[2].bg_y >> 0x8;
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG2VOFS, temp1);
+
+ }
+ else
+ {
+ temp1 = gGpuBgConfigs2[2].bg_y >> 0x10;
+ temp2 = gGpuBgConfigs2[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 = gGpuBgConfigs2[3].bg_y >> 0x8;
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG3VOFS, temp1);
+ }
+ else if (mode == 2)
+ {
+ temp1 = gGpuBgConfigs2[3].bg_y >> 0x10;
+ temp2 = gGpuBgConfigs2[3].bg_y & 0xFFFF;
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_H, temp1);
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_L, temp2);
+ }
+ break;
+ }
+
+ return gGpuBgConfigs2[bg].bg_y;
+}
+
+u32 GetBgY(u8 bg)
+{
+ if (IsInvalidBg32(bg) != FALSE)
+ return -1;
+ if (GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) == 0)
+ return -1;
+ return gGpuBgConfigs2[bg].bg_y;
+}
+
+void SetBgAffine(u8 bg, u32 srcCenterX, u32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle)
+{
+ SetBgAffineInternal(bg, srcCenterX, srcCenterY, dispCenterX, dispCenterY, scaleX, scaleY, rotationAngle);
+}
+
+u8 Unused_AdjustBgMosaic(u8 a1, u8 a2)
+{
+ u16 result;
+ s16 test1;
+ s16 test2;
+
+ result = GetGpuReg(REG_OFFSET_MOSAIC);
+
+ test1 = result & 0xF;
+ test2 = (result >> 4) & 0xF;
+ result &= 0xFF00;
+
+ switch (a2)
+ {
+ case 0:
+ default:
+ test1 = a1 & 0xF;
+ test2 = a1 >> 0x4;
+ break;
+ case 1:
+ test1 = a1 & 0xF;
+ break;
+ case 2:
+ if ((test1 + a1) > 0xF)
+ {
+ test1 = 0xF;
+ }
+ else
+ {
+ test1 += a1;
+ }
+ break;
+ case 3:
+ if ((test1 - a1) < 0)
+ {
+ test1 = 0x0;
+ }
+ else
+ {
+ test1 -= a1;
+ }
+ break;
+ case 4:
+ test2 = a1 & 0xF;
+ break;
+ case 5:
+ if ((test2 + a1) > 0xF)
+ {
+ test2 = 0xF;
+ }
+ else
+ {
+ test2 += a1;
+ }
+ break;
+ case 6:
+ if ((test2 - a1) < 0)
+ {
+ test2 = 0x0;
+ }
+ else
+ {
+ test2 -= a1;
+ }
+ break;
+ }
+
+ result |= ((test2 << 0x4) & 0xF0);
+ result |= (test1 & 0xF);
+
+ SetGpuReg(REG_OFFSET_MOSAIC, result);
+
+ return result;
+}
+
+void SetBgTilemapBuffer(u8 bg, void *tilemap)
+{
+ if (IsInvalidBg32(bg) == FALSE && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) != 0x0)
+ {
+ gGpuBgConfigs2[bg].tilemap = tilemap;
+ }
+}
+
+void UnsetBgTilemapBuffer(u8 bg)
+{
+ if (IsInvalidBg32(bg) == FALSE && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) != 0x0)
+ {
+ gGpuBgConfigs2[bg].tilemap = NULL;
+ }
+}
+
+void* GetBgTilemapBuffer(u8 bg)
+{
+ if (IsInvalidBg32(bg) != FALSE)
+ return NULL;
+ if (GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) == 0)
+ return NULL;
+ return gGpuBgConfigs2[bg].tilemap;
+}
+
+void CopyToBgTilemapBuffer(u8 bg, void *src, u16 mode, u16 destOffset)
+{
+ if (IsInvalidBg32(bg) == FALSE && IsTileMapOutsideWram(bg) == FALSE)
+ {
+ if (mode != 0)
+ {
+ CpuCopy16(src, (void *)(gGpuBgConfigs2[bg].tilemap + (destOffset * 2)), mode);
+ }
+ else
+ {
+ LZ77UnCompWram(src, (void *)(gGpuBgConfigs2[bg].tilemap + (destOffset * 2)));
+ }
+ }
+}
+
+void CopyBgTilemapBufferToVram(u8 bg)
+{
+ u16 sizeToLoad;
+
+ if (IsInvalidBg32(bg) == FALSE && IsTileMapOutsideWram(bg) == FALSE)
+ {
+ switch (GetBgType(bg))
+ {
+ case 0:
+ sizeToLoad = GetBgMetricTextMode(bg, 0) * 0x800;
+ break;
+ case 1:
+ sizeToLoad = GetBgMetricAffineMode(bg, 0) * 0x100;
+ break;
+ default:
+ sizeToLoad = 0;
+ break;
+ }
+ LoadBgVram(bg, gGpuBgConfigs2[bg].tilemap, sizeToLoad, 0, 2);
+ }
+}
+
+void CopyToBgTilemapBufferRect(u8 bg, void* src, u8 destX, u8 destY, u8 width, u8 height)
+{
+ void* srcCopy;
+ u16 destX16;
+ u16 destY16;
+ u16 mode;
+
+ if (IsInvalidBg32(bg) == FALSE && IsTileMapOutsideWram(bg) == FALSE)
+ {
+ switch (GetBgType(bg))
+ {
+ case 0:
+ srcCopy = src;
+ for (destY16 = destY; destY16 < (destY + height); destY16++)
+ {
+ for (destX16 = destX; destX16 < (destX + width); destX16++)
+ {
+ ((u16*)gGpuBgConfigs2[bg].tilemap)[((destY16 * 0x20) + destX16)] = *((u16*)srcCopy)++;
+ }
+ }
+ break;
+ case 1:
+ srcCopy = src;
+ mode = GetBgMetricAffineMode(bg, 0x1);
+ for (destY16 = destY; destY16 < (destY + height); destY16++)
+ {
+ for (destX16 = destX; destX16 < (destX + width); destX16++)
+ {
+ ((u8*)gGpuBgConfigs2[bg].tilemap)[((destY16 * mode) + destX16)] = *((u8*)srcCopy)++;
+ }
+ }
+ break;
+ }
+ }
+}
+
+void CopyToBgTilemapBufferRect_ChangePalette(u8 bg, 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);
+}
+// Skipping for now, it probably uses structs passed by value
+/*
+void CopyRectToBgTilemapBufferRect(u8 bg, void* src, u8 srcX, u8 srcY, u8 srcWidth, u8 srcHeight, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette1, u16 tileOffset, u16 palette2)
+{
+ u16 attribute;
+ u16 mode;
+ u16 mode2;
+
+ void* srcCopy;
+ u16 destX16;
+ u16 destY16;
+
+ if (IsInvalidBg32(bg) == FALSE && IsTileMapOutsideWram(bg) == FALSE)
+ {
+ attribute = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
+ mode = GetBgMetricTextMode(bg, 0x1) * 0x20;
+ mode2 = GetBgMetricTextMode(bg, 0x2) * 0x20;
+ switch (GetBgType(bg))
+ {
+ case 0:
+ srcCopy = src;
+ for (destY16 = destY; destY16 < (destY + rectHeight); destY16++)
+ {
+ for (destX16 = destX; destX16 < (destX + rectWidth); destX16++)
+ {
+ CopyTileMapEntry(&((u16*)srcCopy)[(srcY * rectWidth) + srcX], &((u16*)gGpuBgConfigs2[bg].tilemap)[GetTileMapIndexFromCoords(destX16, destY16, attribute, mode, mode2)], palette1, tileOffset, palette2);
+ }
+ }
+ break;
+ case 1:
+ srcCopy = src;
+ mode = GetBgMetricAffineMode(bg, 0x1);
+ for (destY16 = destY; destY16 < (destY + rectHeight); destY16++)
+ {
+ for (destX16 = destX; destX16 < (destX + rectWidth); destX16++)
+ {
+ CopyTileMapEntry(&((u16*)srcCopy)[(srcY * rectWidth) + srcX], &((u16*)gGpuBgConfigs2[bg].tilemap)[GetTileMapIndexFromCoords(destX16, destY16, attribute, mode, mode2)], palette1, tileOffset, palette2);
+ }
+ }
+ break;
+ }
+ }
+}*/
+__attribute__((naked))
+void CopyRectToBgTilemapBufferRect(u8 bg, void* src, u8 srcX, u8 srcY, u8 srcWidth, u8 srcHeight, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette1, u16 tileOffset, u16 palette2)
+{
+ asm("push {r4-r7,lr}\n\
+ mov r7, r10\n\
+ mov r6, r9\n\
+ mov r5, r8\n\
+ push {r5-r7}\n\
+ sub sp, #0x40\n\
+ str r1, [sp, #0x8]\n\
+ ldr r1, [sp, #0x60]\n\
+ ldr r4, [sp, #0x68]\n\
+ ldr r5, [sp, #0x6C]\n\
+ ldr r6, [sp, #0x70]\n\
+ ldr r7, [sp, #0x74]\n\
+ mov r8, r7\n\
+ ldr r7, [sp, #0x78]\n\
+ mov r9, r7\n\
+ ldr r7, [sp, #0x7C]\n\
+ mov r10, r7\n\
+ ldr r7, [sp, #0x80]\n\
+ mov r12, r7\n\
+ lsl r0, #24\n\
+ lsr r0, #24\n\
+ str r0, [sp, #0x4]\n\
+ lsl r2, #24\n\
+ lsr r2, #24\n\
+ str r2, [sp, #0xC]\n\
+ lsl r3, #24\n\
+ lsr r3, #24\n\
+ str r3, [sp, #0x10]\n\
+ lsl r1, #24\n\
+ lsr r7, r1, #24\n\
+ lsl r4, #24\n\
+ lsr r4, #24\n\
+ str r4, [sp, #0x14]\n\
+ lsl r5, #24\n\
+ lsr r5, #24\n\
+ lsl r6, #24\n\
+ lsr r6, #24\n\
+ str r6, [sp, #0x18]\n\
+ mov r0, r8\n\
+ lsl r0, #24\n\
+ lsr r4, r0, #24\n\
+ mov r1, r9\n\
+ lsl r1, #24\n\
+ lsr r1, #24\n\
+ str r1, [sp, #0x1C]\n\
+ mov r2, r10\n\
+ lsl r2, #16\n\
+ lsr r2, #16\n\
+ str r2, [sp, #0x20]\n\
+ mov r0, r12\n\
+ lsl r0, #16\n\
+ lsr r0, #16\n\
+ str r0, [sp, #0x24]\n\
+ ldr r0, [sp, #0x4]\n\
+ bl IsInvalidBg32\n\
+ cmp r0, #0\n\
+ beq _08002592\n\
+ b _080026EE\n\
+_08002592:\n\
+ ldr r0, [sp, #0x4]\n\
+ bl IsTileMapOutsideWram\n\
+ cmp r0, #0\n\
+ beq _0800259E\n\
+ b _080026EE\n\
+_0800259E:\n\
+ ldr r0, [sp, #0x4]\n\
+ mov r1, #0x4\n\
+ bl GetBgControlAttribute\n\
+ lsl r0, #16\n\
+ lsr r0, #16\n\
+ str r0, [sp, #0x30]\n\
+ ldr r0, [sp, #0x4]\n\
+ mov r1, #0x1\n\
+ bl GetBgMetricTextMode\n\
+ lsl r0, #21\n\
+ lsr r0, #16\n\
+ str r0, [sp, #0x28]\n\
+ ldr r0, [sp, #0x4]\n\
+ mov r1, #0x2\n\
+ bl GetBgMetricTextMode\n\
+ lsl r0, #21\n\
+ lsr r0, #16\n\
+ str r0, [sp, #0x2C]\n\
+ ldr r0, [sp, #0x4]\n\
+ bl GetBgType\n\
+ cmp r0, #0\n\
+ beq _080025D8\n\
+ cmp r0, #0x1\n\
+ beq _08002674\n\
+ b _080026EE\n\
+_080025D8:\n\
+ ldr r1, [sp, #0x10]\n\
+ add r0, r1, #0\n\
+ mul r0, r7\n\
+ ldr r2, [sp, #0xC]\n\
+ add r0, r2\n\
+ lsl r0, #1\n\
+ ldr r1, [sp, #0x8]\n\
+ add r6, r1, r0\n\
+ add r0, r5, r4\n\
+ cmp r5, r0\n\
+ blt _080025F0\n\
+ b _080026EE\n\
+_080025F0:\n\
+ ldr r2, [sp, #0x18]\n\
+ sub r2, r7, r2\n\
+ str r2, [sp, #0x34]\n\
+ str r0, [sp, #0x38]\n\
+_080025F8:\n\
+ ldr r4, [sp, #0x14]\n\
+ ldr r7, [sp, #0x18]\n\
+ add r0, r4, r7\n\
+ add r1, r5, #0x1\n\
+ str r1, [sp, #0x3C]\n\
+ cmp r4, r0\n\
+ bge _0800265A\n\
+ ldr r2, [sp, #0x4]\n\
+ lsl r0, r2, #4\n\
+ ldr r1, =gGpuBgConfigs2+4\n\
+ add r0, r1\n\
+ mov r10, r0\n\
+ ldr r7, [sp, #0x20]\n\
+ lsl r7, #16\n\
+ mov r9, r7\n\
+ ldr r1, [sp, #0x24]\n\
+ lsl r0, r1, #16\n\
+ asr r0, #16\n\
+ mov r8, r0\n\
+_0800261E:\n\
+ ldr r2, [sp, #0x2C]\n\
+ str r2, [sp]\n\
+ add r0, r4, #0\n\
+ add r1, r5, #0\n\
+ ldr r2, [sp, #0x30]\n\
+ ldr r3, [sp, #0x28]\n\
+ bl GetTileMapIndexFromCoords\n\
+ lsl r0, #16\n\
+ lsr r0, #15\n\
+ mov r7, r10\n\
+ ldr r1, [r7]\n\
+ add r1, r0\n\
+ mov r0, r8\n\
+ str r0, [sp]\n\
+ add r0, r6, #0\n\
+ ldr r2, [sp, #0x1C]\n\
+ mov r7, r9\n\
+ asr r3, r7, #16\n\
+ bl CopyTileMapEntry\n\
+ add r6, #0x2\n\
+ add r0, r4, #0x1\n\
+ lsl r0, #16\n\
+ lsr r4, r0, #16\n\
+ ldr r1, [sp, #0x14]\n\
+ ldr r2, [sp, #0x18]\n\
+ add r0, r1, r2\n\
+ cmp r4, r0\n\
+ blt _0800261E\n\
+_0800265A:\n\
+ ldr r5, [sp, #0x34]\n\
+ lsl r0, r5, #1\n\
+ add r6, r0\n\
+ ldr r7, [sp, #0x3C]\n\
+ lsl r0, r7, #16\n\
+ lsr r5, r0, #16\n\
+ ldr r0, [sp, #0x38]\n\
+ cmp r5, r0\n\
+ blt _080025F8\n\
+ b _080026EE\n\
+ .pool\n\
+_08002674:\n\
+ ldr r1, [sp, #0x10]\n\
+ add r0, r1, #0\n\
+ mul r0, r7\n\
+ ldr r2, [sp, #0xC]\n\
+ add r0, r2\n\
+ ldr r1, [sp, #0x8]\n\
+ add r6, r1, r0\n\
+ ldr r0, [sp, #0x4]\n\
+ mov r1, #0x1\n\
+ bl GetBgMetricAffineMode\n\
+ lsl r0, #16\n\
+ lsr r0, #16\n\
+ mov r9, r0\n\
+ add r0, r5, r4\n\
+ cmp r5, r0\n\
+ bge _080026EE\n\
+ ldr r2, [sp, #0x18]\n\
+ sub r2, r7, r2\n\
+ str r2, [sp, #0x34]\n\
+ str r0, [sp, #0x38]\n\
+ ldr r7, =gGpuBgConfigs2+4\n\
+ mov r10, r7\n\
+ ldr r0, [sp, #0x4]\n\
+ lsl r0, #4\n\
+ mov r8, r0\n\
+_080026A8:\n\
+ ldr r4, [sp, #0x14]\n\
+ ldr r1, [sp, #0x18]\n\
+ add r0, r4, r1\n\
+ add r2, r5, #0x1\n\
+ str r2, [sp, #0x3C]\n\
+ cmp r4, r0\n\
+ bge _080026DE\n\
+ mov r3, r8\n\
+ add r3, r10\n\
+ mov r7, r9\n\
+ mul r7, r5\n\
+ mov r12, r7\n\
+ add r2, r0, #0\n\
+_080026C2:\n\
+ ldr r1, [r3]\n\
+ mov r5, r12\n\
+ add r0, r5, r4\n\
+ add r1, r0\n\
+ ldrb r0, [r6]\n\
+ ldr r7, [sp, #0x20]\n\
+ add r0, r7\n\
+ strb r0, [r1]\n\
+ add r6, #0x1\n\
+ add r0, r4, #0x1\n\
+ lsl r0, #16\n\
+ lsr r4, r0, #16\n\
+ cmp r4, r2\n\
+ blt _080026C2\n\
+_080026DE:\n\
+ ldr r0, [sp, #0x34]\n\
+ add r6, r0\n\
+ ldr r1, [sp, #0x3C]\n\
+ lsl r0, r1, #16\n\
+ lsr r5, r0, #16\n\
+ ldr r2, [sp, #0x38]\n\
+ cmp r5, r2\n\
+ blt _080026A8\n\
+_080026EE:\n\
+ add sp, #0x40\n\
+ pop {r3-r5}\n\
+ mov r8, r3\n\
+ mov r9, r4\n\
+ mov r10, r5\n\
+ pop {r4-r7}\n\
+ pop {r0}\n\
+ bx r0\n\
+ .pool\n");
+}
+
+void FillBgTilemapBufferRect_Palette0(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height)
+{
+ u16 x16;
+ u16 y16;
+ u16 mode;
+
+ if (IsInvalidBg32(bg) == FALSE && IsTileMapOutsideWram(bg) == FALSE)
+ {
+ switch (GetBgType(bg))
+ {
+ case 0:
+ for (y16 = y; y16 < (y + height); y16++)
+ {
+ for (x16 = x; x16 < (x + width); x16++)
+ {
+ ((u16*)gGpuBgConfigs2[bg].tilemap)[((y16 * 0x20) + x16)] = tileNum;
+ }
+ }
+ break;
+ case 1:
+ mode = GetBgMetricAffineMode(bg, 0x1);
+ for (y16 = y; y16 < (y + height); y16++)
+ {
+ for (x16 = x; x16 < (x + width); x16++)
+ {
+ ((u8*)gGpuBgConfigs2[bg].tilemap)[((y16 * mode) + x16)] = tileNum;
+ }
+ }
+ break;
+ }
+ }
+}
+
+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;
+
+ u16 x16;
+ u16 y16;
+
+ if (IsInvalidBg32(bg) == FALSE && IsTileMapOutsideWram(bg) == FALSE)
+ {
+ attribute = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
+ mode = GetBgMetricTextMode(bg, 0x1) * 0x20;
+ mode2 = GetBgMetricTextMode(bg, 0x2) * 0x20;
+ switch (GetBgType(bg))
+ {
+ case 0:
+ for (y16 = y; y16 < (y + height); y16++)
+ {
+ for (x16 = x; x16 < (x + width); x16++)
+ {
+ CopyTileMapEntry(&firstTileNum, &((u16*)gGpuBgConfigs2[bg].tilemap)[(u16)GetTileMapIndexFromCoords(x16, y16, attribute, mode, mode2)], paletteSlot, 0, 0);
+ firstTileNum = (firstTileNum & 0xFC00) + ((firstTileNum + tileNumDelta) & 0x3FF);
+ }
+ }
+ break;
+ case 1:
+ mode3 = GetBgMetricAffineMode(bg, 0x1);
+ for (y16 = y; y16 < (y + height); y16++)
+ {
+ for (x16 = x; x16 < (x + width); x16++)
+ {
+ ((u8*)gGpuBgConfigs2[bg].tilemap)[(y16 * mode3) + x16] = firstTileNum;
+ firstTileNum = (firstTileNum & 0xFC00) + ((firstTileNum + tileNumDelta) & 0x3FF);
+ }
+ }
+ break;
+ }
+ }
+}
+
+u16 GetBgMetricTextMode(u8 bg, u8 whichMetric)
+{
+ u8 attribute;
+
+ attribute = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
+
+ switch (whichMetric)
+ {
+ case 0:
+ switch (attribute)
+ {
+ case 0:
+ return 1;
+ case 1:
+ case 2:
+ return 2;
+ case 3:
+ return 4;
+ }
+ break;
+ case 1:
+ switch (attribute)
+ {
+ case 0:
+ return 1;
+ case 1:
+ return 2;
+ case 2:
+ return 1;
+ case 3:
+ return 2;
+ }
+ break;
+ case 2:
+ switch (attribute)
+ {
+ case 0:
+ case 1:
+ return 1;
+ case 2:
+ case 3:
+ return 2;
+ }
+ break;
+ }
+ return 0;
+}
+
+u32 GetBgMetricAffineMode(u8 bg, u8 whichMetric)
+{
+ u8 attribute;
+
+ attribute = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
+
+ switch (whichMetric)
+ {
+ case 0:
+ switch (attribute)
+ {
+ case 0:
+ return 0x1;
+ case 1:
+ return 0x4;
+ case 2:
+ return 0x10;
+ case 3:
+ return 0x40;
+ }
+ break;
+ case 1:
+ case 2:
+ return 0x10 << attribute;
+ }
+ return 0;
+}
+
+u32 GetTileMapIndexFromCoords(s32 x, s32 y, s32 screenSize, u32 screenWidth, u32 screenHeight)
+{
+ x = x & (screenWidth - 1);
+ y = y & (screenHeight - 1);
+
+ switch (screenSize)
+ {
+ case 0:
+ case 2:
+ break;
+ case 3:
+ if (y >= 0x20)
+ y += 0x20;
+ case 1:
+ if (x >= 0x20)
+ {
+ x -= 0x20;
+ y += 0x20;
+ }
+ }
+ return (y * 0x20) + x;
+}
+
+#ifdef NONMATCHING // This one has some weird switch statement cases that refuse to cooperate
+void CopyTileMapEntry(u16 *src, u16 *dest, s32 palette1, u32 tileOffset, u32 palette2)
+{
+ u16 test;
+ switch (palette1)
+ {
+ default:
+ if (palette1 > 0x10 || palette1 < 0)
+ test = *src + tileOffset + (palette2 << 12);
+ else
+ test = ((*src + tileOffset) & 0xFFF) + ((palette1 + palette2) << 12);
+ break;
+ case 0x10:
+ test = ((*dest & 0xFC00) + (palette2 << 12)) | ((*src + tileOffset) & 0x3FF);
+ break;
+ }
+
+ *dest = test;
+}
+#else
+__attribute__((naked))
+void CopyTileMapEntry(u16 *src, u16 *dest, s32 palette1, u32 tileOffset, u32 palette2)
+{
+ asm("push {r4-r6,lr}\n\
+ add r4, r0, #0\n\
+ add r6, r1, #0\n\
+ ldr r5, [sp, #0x10]\n\
+ cmp r2, #0x10\n\
+ beq _08002B14\n\
+ cmp r2, #0x10\n\
+ bgt _08002B34\n\
+ cmp r2, #0\n\
+ blt _08002B34\n\
+ ldrh r0, [r4]\n\
+ add r0, r3\n\
+ ldr r3, =0x00000fff\n\
+ add r1, r3, #0\n\
+ and r0, r1\n\
+ add r1, r2, r5\n\
+ lsl r1, #12\n\
+ b _08002B3A\n\
+ .pool\n\
+_08002B14:\n\
+ ldrh r1, [r6]\n\
+ mov r0, #0xFC\n\
+ lsl r0, #8\n\
+ and r1, r0\n\
+ lsl r2, r5, #12\n\
+ add r2, r1, r2\n\
+ ldrh r0, [r4]\n\
+ add r0, r3\n\
+ ldr r3, =0x000003ff\n\
+ add r1, r3, #0\n\
+ and r0, r1\n\
+ orr r0, r2\n\
+ b _08002B3C\n\
+ .pool\n\
+_08002B34:\n\
+ ldrh r0, [r4]\n\
+ add r0, r3\n\
+ lsl r1, r5, #12\n\
+_08002B3A:\n\
+ add r0, r1\n\
+_08002B3C:\n\
+ lsl r0, #16\n\
+ lsr r1, r0, #16\n\
+ strh r1, [r6]\n\
+ pop {r4-r6}\n\
+ pop {r0}\n\
+ bx r0\n");
+}
+#endif // NONMATCHING
+
+u32 GetBgType(u8 bg)
+{
+ u8 mode;
+
+ mode = GetBgMode();
+
+
+ switch (bg)
+ {
+ case 0:
+ case 1:
+ switch (mode)
+ {
+ case 0:
+ case 1:
+ return 0;
+ }
+ break;
+ case 2:
+ switch (mode)
+ {
+ case 0:
+ return 0;
+ case 1:
+ case 2:
+ return 1;
+ }
+ break;
+ case 3:
+ switch (mode)
+ {
+ case 0:
+ return 0;
+ case 2:
+ return 1;
+ }
+ break;
+ }
+
+ return 0xFFFF;
+}
+
+bool32 IsInvalidBg32(u8 bg)
+{
+ if (bg > 3)
+ return TRUE;
+ return FALSE;
+}
+
+bool32 IsTileMapOutsideWram(u8 bg)
+{
+ if (gGpuBgConfigs2[bg].tilemap > (void*)IWRAM_END)
+ return TRUE;
+ if (gGpuBgConfigs2[bg].tilemap == 0x0)
+ return TRUE;
+ return FALSE;
+}