mirror of
https://github.com/SAT-R/sa2.git
synced 2026-10-28 09:43:38 +00:00
731 lines
21 KiB
C
731 lines
21 KiB
C
#ifndef GUARD_MAIN_H
|
|
#define GUARD_MAIN_H
|
|
|
|
#if !GEN_CTX
|
|
#include <string.h> // memcpy
|
|
#endif
|
|
|
|
#include "global.h"
|
|
#include "rect.h"
|
|
#include "task.h"
|
|
#include "flags.h"
|
|
#include "tilemap.h"
|
|
#include "input_recorder.h"
|
|
|
|
#define VRAM_HEAP_TILE_SIZE TILE_SIZE_4BPP
|
|
#define VRAM_HEAP_SEGMENT_SIZE (4 * VRAM_HEAP_TILE_SIZE)
|
|
#define VRAM_TILE_SLOTS_PER_SEGMENT (VRAM_HEAP_SEGMENT_SIZE / VRAM_HEAP_TILE_SIZE)
|
|
|
|
// TODO: Find out where these numbers come from
|
|
#if (ENGINE == ENGINE_1)
|
|
#define VRAM_TILE_SEGMENTS 156
|
|
#define VRAM_HEAP_TILE_COUNT 112
|
|
#elif (ENGINE == ENGINE_2)
|
|
#if COLLECT_RINGS_ROM
|
|
#define VRAM_TILE_SEGMENTS 128
|
|
#define VRAM_HEAP_TILE_COUNT 0
|
|
#else
|
|
#define VRAM_TILE_SEGMENTS 140
|
|
#define VRAM_HEAP_TILE_COUNT 48
|
|
#endif
|
|
#endif
|
|
|
|
struct MultiSioData_0_0 {
|
|
// id
|
|
u16 unk0;
|
|
// value
|
|
u8 unk2;
|
|
|
|
u8 unk3;
|
|
u32 unk4;
|
|
u16 unk8[3];
|
|
|
|
// TODO: all values from unkE onwards appear to be 'RoomEvent' types?
|
|
// This seems to apply to all 'MultiSioData_X_X' types?
|
|
u8 unkE;
|
|
u8 unkF;
|
|
u32 unk10;
|
|
};
|
|
|
|
struct MultiSioData_0_1 {
|
|
// id
|
|
u16 unk0;
|
|
// value
|
|
u8 unk2;
|
|
|
|
u8 unk3;
|
|
|
|
u16 unk4;
|
|
u16 unk6;
|
|
|
|
u16 unk8[3];
|
|
|
|
// TODO: all values from unkE onwards appear to be 'RoomEvent' types?
|
|
// This seems to apply to all 'MultiSioData_X_X' types?
|
|
u8 unkE;
|
|
u8 unkF;
|
|
u32 unk10;
|
|
};
|
|
struct MultiSioData_0_2 {
|
|
// id
|
|
u8 unk0;
|
|
u8 filler1;
|
|
// value
|
|
u8 unk2;
|
|
|
|
u8 unk3;
|
|
|
|
u16 unk4;
|
|
u16 unk6;
|
|
|
|
u16 unk8[3];
|
|
|
|
// TODO: all values from unkE onwards appear to be 'RoomEvent' types?
|
|
// This seems to apply to all 'MultiSioData_X_X' types?
|
|
u8 unkE;
|
|
u8 unkF;
|
|
u32 unk10;
|
|
};
|
|
|
|
struct MultiSioData_0_3 {
|
|
// id
|
|
u16 unk0;
|
|
// value
|
|
u8 unk2;
|
|
|
|
u8 unk3;
|
|
|
|
u16 unk4;
|
|
u16 unk6;
|
|
|
|
u32 unk8;
|
|
u16 unkC;
|
|
|
|
// TODO: all values from unkE onwards appear to be 'RoomEvent' types?
|
|
// This seems to apply to all 'MultiSioData_X_X' types?
|
|
u8 unkE;
|
|
u8 unkF;
|
|
u32 unk10;
|
|
};
|
|
|
|
struct MultiSioData_0_4 {
|
|
// id
|
|
u16 unk0;
|
|
// value
|
|
s16 x;
|
|
s16 y;
|
|
u16 unk6;
|
|
u16 unk8;
|
|
u8 unkA;
|
|
u8 unkB;
|
|
u8 unkC;
|
|
u8 unkD;
|
|
|
|
// TODO: all values from unkE onwards appear to be 'RoomEvent' types?
|
|
// This seems to apply to all 'MultiSioData_X_X' types?
|
|
u8 unkE;
|
|
u8 numRings;
|
|
u8 unk10;
|
|
u8 unk11;
|
|
u8 unk12;
|
|
u8 unk13;
|
|
};
|
|
|
|
struct MultiSioData_0_5 {
|
|
// id
|
|
u16 unk0;
|
|
// value
|
|
s16 x;
|
|
s16 y;
|
|
|
|
u8 filler3[0x9];
|
|
u8 sioId;
|
|
u8 unk10;
|
|
u8 unk11;
|
|
u8 unk12;
|
|
u8 unk13;
|
|
};
|
|
|
|
union MultiSioData {
|
|
struct MultiSioData_0_0 pat0;
|
|
struct MultiSioData_0_1 pat1;
|
|
struct MultiSioData_0_2 pat2;
|
|
struct MultiSioData_0_3 pat3;
|
|
struct MultiSioData_0_4 pat4;
|
|
struct MultiSioData_0_5 pat5;
|
|
}; /* size = MULTI_SIO_BLOCK_SIZE */
|
|
|
|
// TODO: Have we defined this somewhere else already?
|
|
#define MAP_LAYER_COUNT 2
|
|
|
|
#if (GAME == GAME_SA1)
|
|
typedef u16 collPxDim_t;
|
|
#else
|
|
typedef u32 collPxDim_t;
|
|
#endif
|
|
|
|
typedef struct {
|
|
u16 bldCnt;
|
|
u16 bldAlpha;
|
|
u16 bldY;
|
|
} BlendRegs;
|
|
|
|
// Values to be passed top the affine registers
|
|
// (used by BG2/BG3 in affine screen modes)
|
|
typedef struct {
|
|
/* 0x00 */ u16 pa, pb, pc, pd;
|
|
/* 0x08 */ u32 x, y;
|
|
} BgAffineReg;
|
|
|
|
// Thanks @MainMemory_ for figuring out how collision is stored!
|
|
typedef struct {
|
|
/* 0x00 */ const s8 *height_map;
|
|
/* 0x04 */ const u8 *tile_rotation;
|
|
/* 0x08 */ const u16 *metatiles;
|
|
/* 0x0C */ const MetatileIndexType *map[MAP_LAYER_COUNT];
|
|
/* 0x14 */ const u16 *flags;
|
|
/* 0x18 */ u16 levelX, levelY;
|
|
/* 0x1C */ collPxDim_t pxWidth, pxHeight;
|
|
|
|
// unk20/unk22 are not in SA1
|
|
} Collision;
|
|
|
|
struct Unk_03003674_1_Sub {
|
|
u16 unk0, unk2, unk4, unk6;
|
|
s16 unk8, unkA;
|
|
}; /* size = 0xC */
|
|
|
|
struct Unk_03003674_1_Full {
|
|
struct Unk_03003674_1_Sub sub;
|
|
u32 unkC;
|
|
}; /* size = 0x10 */
|
|
|
|
union Unk_03003674_1 {
|
|
const struct Unk_03003674_1_Sub *sub;
|
|
const struct Unk_03003674_1_Full *full;
|
|
};
|
|
|
|
struct Unk_03003674 {
|
|
const union Unk_03003674_0 *const *unk0;
|
|
const union Unk_03003674_1 *unk4;
|
|
const u16 *const *unk8;
|
|
const void *unkC;
|
|
const void *unk10;
|
|
const void *unk14;
|
|
const s32 *unk18;
|
|
}; /* size = 0x1C */
|
|
|
|
typedef u16 AnimId;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ const void *src;
|
|
/* 0x04 */ void *dest;
|
|
/* 0x08 */ u16 size;
|
|
/* 0x0A */ AnimId anim;
|
|
} GraphicsData;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ GraphicsData graphics;
|
|
|
|
// 'tilesVram' points to tile-index array in VRAM, telling the GBA which tiles to
|
|
// draw on this BG
|
|
//
|
|
// (!!! Data likely different depending on type of Background (Affine vs. Text). !!!)
|
|
//
|
|
// Data-Structure (16 bits): MSB > PPPPYXTTTTTTTTTT < LSB
|
|
// P = Palette Index
|
|
// Y = Y-Flip
|
|
// X = X-Flip
|
|
// T = Tile-Index
|
|
//
|
|
// NOTE: It does NOT point to the tileset!
|
|
/* 0x0C */ u16 *layoutVram;
|
|
|
|
// Stage-Map: Metatiles
|
|
// Common Tilemaps: Tilemap-Tiles
|
|
/* 0x10 */ const u16 *layout;
|
|
|
|
// Tile-count on each axis
|
|
// - Stage maps: should be 12 (# per metatile)
|
|
// - Common Tilemaps: should be .targetTilesX/Y
|
|
/* 0x14 */ u16 xTiles;
|
|
/* 0x16 */ u16 yTiles;
|
|
|
|
/* 0x18 */ u16 unk18;
|
|
/* 0x1A */ u16 unk1A;
|
|
/* 0x1C */ u16 tilemapId;
|
|
/* 0x1E */ u16 unk1E;
|
|
|
|
/* 0x20 */ u16 unk20;
|
|
/* 0x22 */ u16 unk22;
|
|
/* 0x24 */ u16 unk24;
|
|
|
|
/* Tile-Dimensions for the rendering target */
|
|
/* - Stage maps: DISPLAY_WIDTH/_HEIGHT + 1*TILE_WIDTH */
|
|
/* - Common Tilemaps: full image dimensions */
|
|
/* 0x26 */ u16 targetTilesX;
|
|
/* 0x28 */ u16 targetTilesY;
|
|
|
|
/* 0x2A */ u8 paletteOffset;
|
|
/* 0x2B */ u8 animFrameCounter;
|
|
/* 0x2C */ u8 animDelayCounter;
|
|
|
|
/* 0x2E */ u16 flags;
|
|
|
|
// apparently NOT signed?
|
|
/* 0x30 */ u16 scrollX;
|
|
/* 0x32 */ u16 scrollY;
|
|
/* 0x34 */ u16 prevScrollX;
|
|
/* 0x36 */ u16 prevScrollY;
|
|
|
|
/* Only used by stage maps (they are encoded as Tilemaps) */
|
|
/* 0x38 */ const MetatileIndexType *metatileMap;
|
|
/* 0x3C */ u16 mapWidth;
|
|
/* 0x3E */ u16 mapHeight;
|
|
} Background; /* size = 0x40 */
|
|
|
|
typedef struct {
|
|
#if (ENGINE >= ENGINE_3)
|
|
// In SA3 flip-bits are integrated into the oamIndex.
|
|
// X-Flip: Bit 14
|
|
// Y-Flip: Bit 15
|
|
/* 0x00 */ u16 oamIndex;
|
|
#else
|
|
/* 0x00 */ u8 flip;
|
|
|
|
// every animation has an associated oamData pointer, oamIndex starts at
|
|
// 0 for every new animation and ends at variantCount-1
|
|
/* 0x01 */ u8 oamIndex;
|
|
#endif
|
|
|
|
// some sprite frames consist of multiple images (of the same size
|
|
// as GBA's Object Attribute Memory, e.g. 8x8, 8x32, 32x64, ...)
|
|
/* 0x02 */ u16 numSubframes;
|
|
|
|
// In pixels
|
|
/* 0x04 */ u16 width;
|
|
// In pixels
|
|
/* 0x06 */ u16 height;
|
|
|
|
/* 0x08 */ s16 offsetX;
|
|
/* 0x0A */ s16 offsetY;
|
|
} SpriteOffset;
|
|
|
|
typedef struct {
|
|
// index: -1 on init; lower 4 bits = index (in anim-cmds)
|
|
/* 0x00 */ s32 index;
|
|
/* 0x04 */ Rect8 b;
|
|
} Hitbox;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ GraphicsData graphics;
|
|
/* 0x0C */ const SpriteOffset *dimensions;
|
|
|
|
// Bitfield description from KATAM decomp
|
|
/* 0x10 */ u32 frameFlags; // bit 0-4: affine-index / rotscale param selection
|
|
// bit 5: rotscale enable
|
|
// bit 6: rotscale double-size
|
|
// bit 7-8: obj mode
|
|
// bit 9
|
|
// bit 10 X-Flip
|
|
// bit 11 Y-Flip
|
|
// bit 12-13: priority
|
|
// bit 14
|
|
// bit 15-16: Background ID
|
|
// bit 17
|
|
// bit 18
|
|
// bit 19-25(?)
|
|
// bit 26
|
|
// bit 27-29(?)
|
|
// bit 30
|
|
// bit 31
|
|
|
|
/* 0x14 */ u16 animCursor;
|
|
|
|
/* 0x16 */ s16 x;
|
|
/* 0x18 */ s16 y;
|
|
|
|
/* 0x1A */ u16 oamFlags; // bit 6-10: OAM order index
|
|
|
|
/* 0x1C */ s16 qAnimDelay; // Q_8_8, in frames
|
|
/* 0x1E */ u16 prevAnim;
|
|
/* 0x20 */ u8 variant;
|
|
/* 0x21 */ u8 prevVariant;
|
|
|
|
// 0x08 = 0.5x, 0x10 = 1.0x, 0x20 = 2.0x ...
|
|
/* 0x22 */ u8 animSpeed;
|
|
|
|
/* 0x23 */ u8 oamBaseIndex;
|
|
/* 0x24 */ u8 numSubFrames;
|
|
/* 0x25 */ u8 palId;
|
|
/* 0x28 */ Hitbox hitboxes[1];
|
|
} Sprite /* size = 0x30 */;
|
|
|
|
// TODO: Unify Sprite with variable hitbox count through a macro
|
|
typedef struct {
|
|
Sprite s;
|
|
Hitbox hb1;
|
|
} Sprite2;
|
|
|
|
// TODO: Unify Sprite with variable hitbox count through a macro
|
|
typedef struct {
|
|
Sprite s;
|
|
Hitbox hb1;
|
|
Hitbox hb2;
|
|
} Sprite3;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ u16 rotation;
|
|
/* 0x02 */ s16 qScaleX;
|
|
/* 0x04 */ s16 qScaleY;
|
|
/* 0x06 */ s16 x;
|
|
/* 0x08 */ s16 y;
|
|
} SpriteTransform; /* size 0xA */
|
|
|
|
#define AnimCommandSizeInWords(_structType) ((sizeof(_structType)) / sizeof(s32))
|
|
|
|
typedef struct {
|
|
/* 0x00 */ s32 cmdId; // -2
|
|
|
|
// Note(Jace): This needs to be signed, since a
|
|
// negative value infers that it's using 8bit-colors
|
|
/* 0x04 */ s32 tileIndex;
|
|
|
|
/* 0x08 */ u32 numTilesToCopy;
|
|
} ACmd_GetTiles;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ s32 cmdId; // -2
|
|
|
|
/* 0x04 */ s32 palId;
|
|
/* 0x06 */ u16 numColors;
|
|
/* 0x08 */ u16 insertOffset;
|
|
} ACmd_GetPalette;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ s32 cmdId; // -3
|
|
|
|
/* 0x04 */ s32 offset;
|
|
} ACmd_JumpBack;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ s32 cmdId; // -4
|
|
} ACmd_4;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ s32 cmdId; // -5
|
|
|
|
/* 0x04 */ u16 songId;
|
|
} ACmd_PlaySoundEffect;
|
|
|
|
// TODO: param types unknown
|
|
typedef struct {
|
|
/* 0x00 */ s32 cmdId; // -6
|
|
|
|
/* 0x04 */ Hitbox hitbox;
|
|
} ACmd_Hitbox;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ s32 cmdId; // -7
|
|
|
|
/* 0x04 */ u16 x;
|
|
/* 0x06 */ u16 y;
|
|
} ACmd_TranslateSprite;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ s32 cmdId; // -8
|
|
|
|
/* 0x04 */ s32 unk4;
|
|
/* 0x08 */ s32 unk8;
|
|
} ACmd_8;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ s32 cmdId; // -9
|
|
|
|
/* 0x04 */ AnimId animId;
|
|
/* 0x06 */ u16 variant;
|
|
} ACmd_SetIdAndVariant;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ s32 cmdId; // -10
|
|
|
|
/* 0x04 */ s32 unk4;
|
|
/* 0x08 */ s32 unk8;
|
|
/* 0x0C */ s32 unkC;
|
|
} ACmd_10;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ s32 cmdId; // -11
|
|
|
|
/* 0x04 */ s32 priority;
|
|
} ACmd_SetSpritePriority;
|
|
|
|
typedef struct {
|
|
/* 0x00 */ s32 cmdId; // -12
|
|
|
|
/* 0x04 */ s32 orderIndex;
|
|
} ACmd_SetOamOrder;
|
|
|
|
typedef struct {
|
|
// number of frames this will be displayed
|
|
s32 delay;
|
|
|
|
// frameId of this animation that should be displayed
|
|
s32 index;
|
|
} ACmd_ShowFrame;
|
|
|
|
typedef union {
|
|
s32 id;
|
|
|
|
ACmd_GetTiles tiles;
|
|
ACmd_GetPalette pal;
|
|
ACmd_JumpBack jump;
|
|
ACmd_4 end;
|
|
ACmd_PlaySoundEffect sfx;
|
|
ACmd_Hitbox _6;
|
|
ACmd_TranslateSprite translate;
|
|
ACmd_8 _8;
|
|
ACmd_SetIdAndVariant setAnimId;
|
|
ACmd_10 _10;
|
|
ACmd_SetSpritePriority _11;
|
|
ACmd_SetOamOrder setOamOrder;
|
|
|
|
ACmd_ShowFrame show;
|
|
} ACmd;
|
|
|
|
typedef enum {
|
|
ACMD_RESULT__ANIM_CHANGED = -1,
|
|
ACMD_RESULT__ENDED = 0,
|
|
ACMD_RESULT__RUNNING = +1,
|
|
} AnimCmdResult;
|
|
|
|
typedef AnimCmdResult (*AnimationCommandFunc)(void *cursor, Sprite *sprite);
|
|
|
|
typedef struct {
|
|
/* 0x00 */ const ACmd **const *animations;
|
|
/* 0x04 */ const SpriteOffset *const *dimensions;
|
|
/* 0x08 */ const u16 **const oamData;
|
|
/* 0x0C */ const ColorRaw *const palettes;
|
|
/* 0x10 */ const u8 *const tiles_4bpp;
|
|
/* 0x14 */ const u8 *const tiles_8bpp;
|
|
} SpriteTables;
|
|
|
|
// No idea why this exists when there is a
|
|
// better random number generator in the math
|
|
// module
|
|
#define PSEUDO_RANDOM_32() \
|
|
({ \
|
|
gPseudoRandom = (gPseudoRandom * 0x196225) + 0x3C6EF35F; \
|
|
gPseudoRandom; \
|
|
})
|
|
|
|
#define MP_PSEUDO_RANDOM_32() \
|
|
({ \
|
|
gMultiplayerPseudoRandom = (gMultiplayerPseudoRandom * 0x196225) + 0x3C6EF35F; \
|
|
gMultiplayerPseudoRandom; \
|
|
})
|
|
|
|
// TODO: align the usage of this between both games
|
|
#if (GAME == GAME_SA1)
|
|
#define PseudoRandBetween(min, max) ((PSEUDO_RANDOM_32() & ((-min) + (max))) + (min))
|
|
#else
|
|
#define PseudoRandBetween(min, max) ((PSEUDO_RANDOM_32() & ((-min) + (max - 1))) + (min))
|
|
#endif
|
|
|
|
extern u32 gFlags;
|
|
extern u32 gFlagsPreVBlank;
|
|
|
|
extern u32 gFrameCount;
|
|
|
|
#define INTR_INDEX_SIO 0
|
|
#define INTR_INDEX_VBLANK 1
|
|
#define INTR_INDEX_HBLANK 2
|
|
#define INTR_INDEX_VCOUNT 3
|
|
#define INTR_INDEX_TIMER0 4
|
|
#define INTR_INDEX_TIMER1 5
|
|
#define INTR_INDEX_TIMER2 6
|
|
#define INTR_INDEX_DMA0 7
|
|
#define INTR_INDEX_DMA1 8
|
|
#define INTR_INDEX_DMA2 9
|
|
#define INTR_INDEX_DMA3 10
|
|
#define INTR_INDEX_KEYPAD 11
|
|
#define INTR_INDEX_GAMEPAK 12
|
|
extern IntrFunc gIntrTable[16];
|
|
extern IntrFunc const gIntrTableTemplate[14];
|
|
extern u32 gIntrMainBuf[0x80];
|
|
|
|
extern Task *gCurTask;
|
|
extern Task gTasks[MAX_TASK_NUM];
|
|
extern Task *gTaskPtrs[MAX_TASK_NUM];
|
|
extern Task *gNextTask;
|
|
extern Task gEmptyTask;
|
|
extern s32 gNumTasks;
|
|
|
|
extern u16 gInput;
|
|
extern u16 gPrevInput;
|
|
extern u16 gPhysicalInput;
|
|
extern u16 gReleasedKeys;
|
|
extern u16 gRepeatedKeys;
|
|
extern u16 gPressedKeys;
|
|
extern u8 gKeysFirstRepeatIntervals[10];
|
|
extern u8 gRepeatedKeysTestCounter[10];
|
|
extern u8 gKeysContinuedRepeatIntervals[10];
|
|
|
|
extern const u8 *gInputPlaybackData;
|
|
extern struct InputRecorder gInputRecorder;
|
|
extern u16 *gInputRecorderTapeBuffer;
|
|
|
|
extern union MultiSioData gMultiSioSend;
|
|
extern union MultiSioData gMultiSioRecv[4];
|
|
extern u32 gMultiSioStatusFlags;
|
|
extern bool8 gMultiSioEnabled;
|
|
|
|
extern HBlankIntrFunc gHBlankIntrs[4];
|
|
extern HBlankIntrFunc gHBlankCallbacks[4];
|
|
extern u8 gNumHBlankCallbacks;
|
|
extern u8 gNumHBlankIntrs;
|
|
|
|
extern u8 gIwramHeap[TASK_HEAP_SIZE];
|
|
|
|
extern void *gVramHeapStartAddr;
|
|
extern u16 gVramHeapMaxTileSlots;
|
|
extern u16 gVramHeapState[OBJ_VRAM_TOTAL_SIZE / VRAM_HEAP_SEGMENT_SIZE];
|
|
|
|
extern bool8 gExecSoundMain;
|
|
|
|
extern u16 gDispCnt;
|
|
|
|
#define WINREG_WIN0H 0
|
|
#define WINREG_WIN1H 1
|
|
#define WINREG_WIN0V 2
|
|
#define WINREG_WIN1V 3
|
|
#define WINREG_WININ 4
|
|
#define WINREG_WINOUT 5
|
|
|
|
// TODO: Use these everywhere in SA1!
|
|
#define PALETTE_LEN_4BPP 16u
|
|
#define GET_PALETTE_COLOR_OBJ(_paletteId, _colorId) gObjPalette[(_paletteId)*PALETTE_LEN_4BPP + (_colorId)]
|
|
#define GET_PALETTE_COLOR_BG(_paletteId, _colorId) gBgPalette[(_paletteId)*PALETTE_LEN_4BPP + (_colorId)]
|
|
#define SET_PALETTE_COLOR_OBJ(_paletteId, _colorId, _color) GET_PALETTE_COLOR_OBJ(_paletteId, _colorId) = (_color);
|
|
#define SET_PALETTE_COLOR_BG(_paletteId, _colorId, _color) GET_PALETTE_COLOR_BG(_paletteId, _colorId) = (_color);
|
|
|
|
extern winreg_t gWinRegs[6];
|
|
extern BlendRegs gBldRegs;
|
|
extern BgAffineReg gBgAffineRegs[NUM_AFFINE_BACKGROUNDS];
|
|
extern ColorRaw gObjPalette[16 * PALETTE_LEN_4BPP];
|
|
extern ColorRaw gBgPalette[16 * PALETTE_LEN_4BPP];
|
|
extern u16 gBgCntRegs[4];
|
|
|
|
// TODO: Turn this into a struct-array?
|
|
// [4]{s16 x, s16 y}
|
|
extern s16 gBgScrollRegs[NUM_BACKGROUNDS][2];
|
|
|
|
extern OamData gOamMallocBuffer[OAM_ENTRY_COUNT];
|
|
extern OamData gOamBuffer[OAM_ENTRY_COUNT];
|
|
|
|
// NOTE(Jace): This could be u16[2][DISPLAY_HEIGHT][2] (or unsigned Vec2_16?)
|
|
extern int_vcount gBgOffsetsBuffer[2][DISPLAY_HEIGHT][4];
|
|
extern Background *gBackgroundsCopyQueue[16];
|
|
|
|
// This is used to buffer the xy-shift for each background scanline
|
|
extern void *gBgOffsetsHBlankPrimary;
|
|
|
|
extern u16 gSpriteTransformScaleX;
|
|
extern Vec2_16 gSpriteOffset;
|
|
extern u8 gOamMallocOrders_StartIndex[32];
|
|
extern IntrFunc gVBlankCallbacks[4];
|
|
|
|
extern u8 gOamFreeIndex;
|
|
extern u16 gSpriteTransformRotation;
|
|
extern u8 gNumVBlankIntrs;
|
|
extern s16 gSpriteTransformX;
|
|
|
|
extern Tilemap **gTilemapsRef;
|
|
extern u8 gBgSprites_Unknown2[4][4];
|
|
extern u8 gBgSprites_Unknown1[4];
|
|
|
|
#define LOG_GRAPHICS_QUEUE !TRUE
|
|
#if (!PLATFORM_GBA && LOG_GRAPHICS_QUEUE)
|
|
#define GFX_QUEUE_LOG_ADD(gfx) \
|
|
printf("GFX %d: src 0x%p, dst 0x%p, size 0x%04X\n", gVramGraphicsCopyQueueIndex, (gfx)->src, \
|
|
(void *)((intptr_t)(gfx)->dest - (intptr_t)VRAM), (gfx)->size);
|
|
#else
|
|
#define GFX_QUEUE_LOG_ADD(gfx)
|
|
#endif
|
|
extern GraphicsData *gVramGraphicsCopyQueue[32];
|
|
extern u8 gVramGraphicsCopyQueueIndex;
|
|
// Because the graphics in the queue only get copied if
|
|
// (gVramGraphicsCopyCursor != gVramGraphicsCopyQueueIndex),
|
|
// just making them equal will pause the queue.
|
|
#define PAUSE_GRAPHICS_QUEUE() gVramGraphicsCopyCursor = gVramGraphicsCopyQueueIndex;
|
|
|
|
#define INC_GRAPHICS_QUEUE_CURSOR(cursor) cursor = (cursor + 1) % ARRAY_COUNT(gVramGraphicsCopyQueue);
|
|
|
|
#if PORTABLE
|
|
// On the GBA we use a fixed heap to allocate memory
|
|
// but on other OS's we malloc and free memory which
|
|
// the graphics queue may be referring to. Instead we
|
|
// make a separate copy of the graphics queue with the
|
|
// pointers we need to copy so that a race condition
|
|
// happens where sprite has been freed but the copy
|
|
// has not happened we don't get invalid memory access
|
|
extern GraphicsData gVramGraphicsCopyQueueBuffer[32];
|
|
#define ADD_TO_GRAPHICS_QUEUE(gfx) \
|
|
memcpy(&gVramGraphicsCopyQueueBuffer[gVramGraphicsCopyQueueIndex], gfx, sizeof(GraphicsData)); \
|
|
gVramGraphicsCopyQueue[gVramGraphicsCopyQueueIndex] = &gVramGraphicsCopyQueueBuffer[gVramGraphicsCopyQueueIndex]; \
|
|
/* Log has to happen before gVramGraphicsCopyQueueIndex increment */ \
|
|
GFX_QUEUE_LOG_ADD(gfx) \
|
|
INC_GRAPHICS_QUEUE_CURSOR(gVramGraphicsCopyQueueIndex);
|
|
#else
|
|
#define ADD_TO_GRAPHICS_QUEUE(gfx) \
|
|
gVramGraphicsCopyQueue[gVramGraphicsCopyQueueIndex] = gfx; \
|
|
/* Log has to happen before gVramGraphicsCopyQueueIndex increment */ \
|
|
GFX_QUEUE_LOG_ADD(gfx) \
|
|
INC_GRAPHICS_QUEUE_CURSOR(gVramGraphicsCopyQueueIndex);
|
|
#endif
|
|
|
|
#define PAUSE_BACKGROUNDS_QUEUE() gBackgroundsCopyQueueCursor = gBackgroundsCopyQueueIndex;
|
|
|
|
#define INC_BACKGROUNDS_QUEUE_CURSOR(cursor) cursor = (cursor + 1) % ARRAY_COUNT(gBackgroundsCopyQueue);
|
|
|
|
#define ADD_TO_BACKGROUNDS_QUEUE(_bg) \
|
|
gBackgroundsCopyQueue[gBackgroundsCopyQueueIndex] = _bg; \
|
|
INC_BACKGROUNDS_QUEUE_CURSOR(gBackgroundsCopyQueueIndex);
|
|
|
|
extern void *gBgOffsetsHBlankSecondary;
|
|
extern void *gBgOffsetsSecondary;
|
|
#if (GAME == GAME_SA2)
|
|
extern s16 gMosaicReg;
|
|
extern u8 gUnknown_030026F4;
|
|
#endif
|
|
extern s16 gSpriteTransformY;
|
|
extern u8 gVCountSetting;
|
|
extern void *gHBlankCopyTarget;
|
|
extern u8 gBackgroundsCopyQueueIndex;
|
|
extern u8 gHBlankCopySize;
|
|
extern u16 SA2_LABEL(gUnknown_03002A8C);
|
|
//// When paused, the previously-active OAM elements get moved to the end
|
|
//// of the OAM. This is the index of the first currently-inactive element
|
|
extern u8 gOamFirstPausedIndex;
|
|
extern u8 gBackgroundsCopyQueueCursor;
|
|
extern Sprite *gBgSprites[16];
|
|
extern u8 gNumVBlankCallbacks;
|
|
extern void *gBgOffsetsPrimary;
|
|
extern u16 SA2_LABEL(gUnknown_03004D58);
|
|
extern u8 gVramGraphicsCopyCursor;
|
|
extern u8 gOamMallocOrders_EndIndex[0x20];
|
|
extern u8 gBgSpritesCount;
|
|
extern u16 gSpriteTransformScaleY;
|
|
extern u16 gSpriteTransformScaleUnknown;
|
|
extern IntrFunc gVBlankIntrs[4];
|
|
extern s32 gPseudoRandom;
|
|
extern u8 gOamMallocCopiedOrder[128];
|
|
extern struct MultiBootParam gMultiBootParam;
|
|
|
|
extern const SpriteTables *gRefSpriteTables;
|
|
|
|
void EngineInit(void);
|
|
void EngineMainLoop(void);
|
|
|
|
#endif
|