diff options
author | YamaArashi <shadow962@live.com> | 2016-05-20 11:45:24 -0700 |
---|---|---|
committer | YamaArashi <shadow962@live.com> | 2016-05-21 10:35:53 -0700 |
commit | c0203de808a98d27446e01c6b7e9f9311a5ad3bf (patch) | |
tree | e538179372ce7cddc50b851e4c24a4c7e0a40c81 /src | |
parent | 4af578c1865e4b620f4c64401e0a16ccbd9efc8d (diff) |
sprite.c and updated preproc
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 45 | ||||
-rw-r--r-- | src/sprite.c | 1795 |
2 files changed, 1796 insertions, 44 deletions
diff --git a/src/main.c b/src/main.c index 9e029eeb2..0c5055e60 100644 --- a/src/main.c +++ b/src/main.c @@ -3,50 +3,7 @@ #include "gba/flash_internal.h" #include "siirtc.h" #include "rtc.h" - -typedef void (*MainCallback)(void); -typedef void (*IntrCallback)(void); -typedef void (*IntrFunc)(void); - -struct OamData -{ - u32 a, b; -}; - -struct Main -{ - MainCallback callback1; - MainCallback callback2; - - u32 field_8; - - IntrCallback vblankCallback; - IntrCallback hblankCallback; - IntrCallback vcountCallback; - IntrCallback serialCallback; - - vu16 intrCheck; - - u32 vblankCounter1; - u32 vblankCounter2; - - u16 heldKeysRaw; // held keys without L=A remapping - u16 newKeysRaw; // newly pressed keys without L=A remapping - u16 heldKeys; // held keys with L=A remapping - u16 newKeys; // newly pressed keys with L=A remapping - u16 newAndRepeatedKeys; // newly pressed keys plus key repeat - u16 keyRepeatCounter; // counts down to 0, triggering key repeat - bool16 watchedKeysPressed; // whether one of the watched keys was pressed - u16 watchedKeysMask; // bit mask for watched keys - - u32 field_38; - - struct OamData oamBuffer[128]; - - u8 state; - - bool8 oamLoadDisabled; -}; +#include "main.h" extern struct SoundInfo gSoundInfo; extern u16 gUnknown_3002A20; diff --git a/src/sprite.c b/src/sprite.c new file mode 100644 index 000000000..1a586a63d --- /dev/null +++ b/src/sprite.c @@ -0,0 +1,1795 @@ +#include "global.h" +#include "main.h" +#include "sprite.h" + +#define MAX_SPRITES 64 + +#define MAX_SPRITE_COPY_REQUESTS 64 + +#define OAM_MATRIX_COUNT 32 + +#define SET_SPRITE_TILE_RANGE(index, start, count) \ +{ \ + u16 *rangeStarts; \ + u16 *rangeCounts; \ + rangeStarts = sSpriteTileRanges; \ + rangeStarts[index * 2] = start; \ + rangeCounts = sSpriteTileRanges + 1; \ + rangeCounts[index * 2] = count; \ +} + +struct OamMatrix +{ + s16 a; + s16 b; + s16 c; + s16 d; +}; + +struct SpriteCopyRequest +{ + u8 *src; + u8 *dest; + u16 size; +}; + +struct OamDimensions +{ + s8 width; + s8 height; +}; + +void gpu_pal_apply(u8 *, u16, u32); +void sub_814A590(void); + +static void UpdateOamCoords(void); +static void BuildSpritePriorities(void); +static void SortSprites(void); +static void CopyMatricesToOamBuffer(void); +static void AddSpritesToOamBuffer(void); +static u8 CreateSpriteAt(u8 index, struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); +static void ClearSpriteCopyRequests(void); +static void ResetOamMatrices(void); +static void ResetSprite(struct Sprite *sprite); +static s16 AllocSpriteTiles(u16 tileCount); +static u8 SpriteTileAllocBitmapOp(u16 bit, u8 op); +static void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, struct SpriteFrameImage *images); +static void CopyFromSprites(u8 *dest); +static void CopyToSprites(u8 *src); +static void ResetAllSprites(void); +static void BeginAnim(struct Sprite *sprite); +static void ContinueAnim(struct Sprite *sprite); +static void AnimCmd_frame(struct Sprite *sprite); +static void AnimCmd_end(struct Sprite *sprite); +static void AnimCmd_jump(struct Sprite *sprite); +static void AnimCmd_loop(struct Sprite *sprite); +static void BeginAnimLoop(struct Sprite *sprite); +static void ContinueAnimLoop(struct Sprite *sprite); +static void JumpToTopOfAnimLoop(struct Sprite *sprite); +static void BeginAffineAnim(struct Sprite *sprite); +static void ContinueAffineAnim(struct Sprite *sprite); +static void AffineAnimDelay(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_loop(u8 matrixNum, struct Sprite *sprite); +static void BeginAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); +static void ContinueAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); +static void JumpToTopOfAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_jump(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_end(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_frame(u8 matrixNum, struct Sprite *sprite); +static void CopyOamMatrix(u8 destMatrixIndex, struct OamMatrix *srcMatrix); +static u8 GetSpriteMatrixNum(struct Sprite *sprite); +static void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip); +static void AffineAnimStateRestartAnim(u8 matrixNum); +static void AffineAnimStateStartAnim(u8 matrixNum, u8 animNum); +static void AffineAnimStateReset(u8 matrixNum); +static void ApplyAffineAnimFrameAbsolute(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); +static void DecrementAnimDelayCounter(struct Sprite *sprite); +static bool8 DecrementAffineAnimDelayCounter(struct Sprite *sprite, u8 matrixNum); +static void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); +static s16 ConvertScaleParam(s16 scale); +static void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd); +static void ApplyAffineAnimFrame(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); +static void ResetAffineAnimData(void); +static u8 IndexOfSpriteTileTag(u16 tag); +static void AddSpriteTileRange(u16 tag, u16 start, u16 count); +static void ApplySpritePalette(u8 *src, u16 paletteOffset); + +typedef void (*AnimFunc)(struct Sprite *); +typedef void (*AnimCmdFunc)(struct Sprite *); +typedef void (*AffineAnimCmdFunc)(u8 matrixNum, struct Sprite *); + +#define DUMMY_OAM_DATA \ +{ \ + 160, /* Y (off-screen) */ \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 304, /* X */ \ + 0, \ + 0, \ + 0, \ + 3, /* lowest priority */ \ + 0, \ + 0 \ +} + +#define ANIM_END 0xFFFF +#define AFFINE_ANIM_END 0x7FFF + +// forward declarations +const union AnimCmd * const gDummySpriteAnimTable[]; +const union AffineAnimCmd * const gDummySpriteAffineAnimTable[]; +const struct SpriteTemplate gDummySpriteTemplate; + +// Unreferenced error message. +// It means "The DMA transfer request table has exceeded its limit." +static const u8 sDmaOverErrorMsg[] = + _"DMA OVER\n" + "DMAてんそう\n" + "リクエストテーブルが\n" + "オーバーしました"; + +// Unreferenced data. +static const u8 sUnknownData[24] = +{ + 0x01, 0x04, 0x10, 0x40, + 0x02, 0x04, 0x08, 0x20, + 0x02, 0x04, 0x08, 0x20, + 0x01, 0x04, 0x10, 0x40, + 0x02, 0x04, 0x08, 0x20, + 0x02, 0x04, 0x08, 0x20, +}; + +static const u8 sCenterToCornerVecTable[3][4][2] = +{ + { // square + { -4, -4 }, + { -8, -8 }, + { -16, -16 }, + { -32, -32 }, + }, + { // horizontal rectangle + { -8, -4 }, + { -16, -4 }, + { -16, -8 }, + { -32, -16 }, + }, + { // vertical rectangle + { -4, -8 }, + { -4, -16 }, + { -8, -16 }, + { -16, -32 }, + }, +}; + +static const struct Sprite sDummySprite = +{ + DUMMY_OAM_DATA, + (union AnimCmd **)gDummySpriteAnimTable, + NULL, + (union AffineAnimCmd **)gDummySpriteAffineAnimTable, + (struct SpriteTemplate *)&gDummySpriteTemplate, + NULL, + SpriteCallbackDummy, + { 304, 160 }, + { 0, 0 }, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0xFF +}; + +const struct OamData gDummyOamData = DUMMY_OAM_DATA; + +static const union AnimCmd sDummyAnim = { ANIM_END }; + +const union AnimCmd * const gDummySpriteAnimTable[] = { &sDummyAnim }; + +static const union AffineAnimCmd sDummyAffineAnim = { AFFINE_ANIM_END }; + +const union AffineAnimCmd * const gDummySpriteAffineAnimTable[] = { &sDummyAffineAnim }; + +const struct SpriteTemplate gDummySpriteTemplate = +{ + 0, + 0xFFFF, + (struct OamData *)&gDummyOamData, + (union AnimCmd **)gDummySpriteAnimTable, + NULL, + (union AffineAnimCmd **)gDummySpriteAffineAnimTable, + SpriteCallbackDummy +}; + +// TODO: Find out what these are used for. +static const u16 sOamBitmasks[9] = +{ + 0xFF00, 0x00FF, 0x001F, + 0xFE00, 0x01FF, 0x03E0, + 0xFC00, 0x03FF, 0xFC00, +}; + +static const AnimFunc sAnimFuncs[] = +{ + ContinueAnim, + BeginAnim, +}; + +static const AnimFunc sAffineAnimFuncs[] = +{ + ContinueAffineAnim, + BeginAffineAnim, +}; + +static const AnimCmdFunc sAnimCmdFuncs[] = +{ + AnimCmd_loop, + AnimCmd_jump, + AnimCmd_end, + AnimCmd_frame, +}; + +static const AffineAnimCmdFunc sAffineAnimCmdFuncs[] = +{ + AffineAnimCmd_loop, + AffineAnimCmd_jump, + AffineAnimCmd_end, + AffineAnimCmd_frame, +}; + +static const struct OamDimensions sOamDimensions[3][4] = +{ + { // square + { 8, 8 }, + { 16, 16 }, + { 32, 32 }, + { 64, 64 }, + }, + { // horizontal rectangle + { 16, 8 }, + { 32, 8 }, + { 32, 16 }, + { 64, 32 }, + }, + { // vertical rectangle + { 8, 16 }, + { 8, 32 }, + { 16, 32 }, + { 32, 64 }, + }, +}; + +extern struct Main gMain; + +static u16 sSpriteTileRangeTags[MAX_SPRITES]; +static u16 sSpriteTileRanges[MAX_SPRITES * 2]; +static struct AffineAnimState sAffineAnimStates[OAM_MATRIX_COUNT]; +static u16 sSpritePaletteTags[16]; + +COMM_4(u8 gSpriteOrder[MAX_SPRITES]) +COMM_4(u8 gSpriteTileAllocBitmap[128]) +COMM_2(s16 gSpriteCoordOffsetX) +COMM_2(u8 gOamLimit) +COMM_2(u16 gReservedSpriteTileCount) +COMM_2(u8 gSpriteCopyRequestCount) +COMM_4(struct SpriteCopyRequest gSpriteCopyRequests[MAX_SPRITE_COPY_REQUESTS]) +COMM_2(s16 gSpriteCoordOffsetY) +COMM_4(struct OamMatrix gOamMatrices[OAM_MATRIX_COUNT]) +COMM_2(bool8 gShouldProcessSpriteCopyRequests) +COMM_2(u32 gOamMatrixAllocBitmap) +COMM_2(u8 gReservedSpritePaletteCount) + +EWRAM_DATA struct Sprite gSprites[MAX_SPRITES + 1] = {0}; +EWRAM_DATA u16 gSpritePriorities[MAX_SPRITES] = {0}; +EWRAM_DATA u8 gAffineAnimsDisabled = {0}; + +void ResetSpriteData(void) +{ + ResetOamRange(0, 128); + ResetAllSprites(); + ClearSpriteCopyRequests(); + ResetAffineAnimData(); + FreeAllSpriteTiles(); + gOamLimit = 64; + gReservedSpriteTileCount = 0; + AllocSpriteTiles(0); + gSpriteCoordOffsetX = 0; + gSpriteCoordOffsetY = 0; +} + +void AnimateSprites(void) +{ + u8 i; + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + + if (sprite->inUse) + { + sprite->callback(sprite); + + if (sprite->inUse) + AnimateSprite(sprite); + } + } +} + +void BuildOamBuffer(void) +{ + u8 temp; + UpdateOamCoords(); + BuildSpritePriorities(); + SortSprites(); + temp = gMain.oamLoadDisabled; + gMain.oamLoadDisabled = TRUE; + AddSpritesToOamBuffer(); + CopyMatricesToOamBuffer(); + gMain.oamLoadDisabled = temp; + gShouldProcessSpriteCopyRequests = TRUE; +} + +static void UpdateOamCoords(void) +{ + u8 i; + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + if (sprite->inUse && !sprite->invisible) + { + if (sprite->coordOffsetEnabled) + { + sprite->oam.x = sprite->pos1.x + sprite->pos2.x + sprite->centerToCornerVecX + gSpriteCoordOffsetX; + sprite->oam.y = sprite->pos1.y + sprite->pos2.y + sprite->centerToCornerVecY + gSpriteCoordOffsetY; + } + else + { + sprite->oam.x = sprite->pos1.x + sprite->pos2.x + sprite->centerToCornerVecX; + sprite->oam.y = sprite->pos1.y + sprite->pos2.y + sprite->centerToCornerVecY; + } + } + } +} + +static void BuildSpritePriorities(void) +{ + u16 i; + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + u16 priority = sprite->subpriority | (sprite->oam.priority << 8); + gSpritePriorities[i] = priority; + } +} + +static void SortSprites(void) +{ + u8 i; + for (i = 1; i < MAX_SPRITES; i++) + { + u8 j = i; + struct Sprite *sprite1 = &gSprites[gSpriteOrder[i - 1]]; + struct Sprite *sprite2 = &gSprites[gSpriteOrder[i]]; + u16 sprite1Priority = gSpritePriorities[gSpriteOrder[i - 1]]; + u16 sprite2Priority = gSpritePriorities[gSpriteOrder[i]]; + s16 sprite1Y = sprite1->oam.y; + s16 sprite2Y = sprite2->oam.y; + + if (sprite1Y >= DISPLAY_HEIGHT) + sprite1Y = sprite1Y - 256; + + if (sprite2Y >= DISPLAY_HEIGHT) + sprite2Y = sprite2Y - 256; + + if (sprite1->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite1->oam.size == 3) + { + u32 shape = sprite1->oam.shape; + if (shape == ST_OAM_SQUARE || shape == 2) + { + if (sprite1Y > 128) + sprite1Y = sprite1Y - 256; + } + } + + if (sprite2->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite2->oam.size == 3) + { + u32 shape = sprite2->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite2Y > 128) + sprite2Y = sprite2Y - 256; + } + } + + while (j > 0 + && ((sprite1Priority > sprite2Priority) + || (sprite1Priority == sprite2Priority && sprite1Y < sprite2Y))) + { + u8 temp = gSpriteOrder[j]; + gSpriteOrder[j] = gSpriteOrder[j - 1]; + gSpriteOrder[j - 1] = temp; + + j--; + + sprite1 = &gSprites[gSpriteOrder[j - 1]]; + sprite2 = &gSprites[gSpriteOrder[j]]; + sprite1Priority = gSpritePriorities[gSpriteOrder[j - 1]]; + sprite2Priority = gSpritePriorities[gSpriteOrder[j]]; + sprite1Y = sprite1->oam.y; + sprite2Y = sprite2->oam.y; + + if (sprite1Y >= DISPLAY_HEIGHT) + sprite1Y = sprite1Y - 256; + + if (sprite2Y >= DISPLAY_HEIGHT) + sprite2Y = sprite2Y - 256; + + if (sprite1->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite1->oam.size == 3) + { + u32 shape = sprite1->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite1Y > 128) + sprite1Y = sprite1Y - 256; + } + } + + if (sprite2->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite2->oam.size == 3) + { + u32 shape = sprite2->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite2Y > 128) + sprite2Y = sprite2Y - 256; + } + } + } + } +} + +static void CopyMatricesToOamBuffer(void) +{ + u8 i; + for (i = 0; i < OAM_MATRIX_COUNT; i++) + { + u32 base = 4 * i; + gMain.oamBuffer[base + 0].affineParam = gOamMatrices[i].a; + gMain.oamBuffer[base + 1].affineParam = gOamMatrices[i].b; + gMain.oamBuffer[base + 2].affineParam = gOamMatrices[i].c; + gMain.oamBuffer[base + 3].affineParam = gOamMatrices[i].d; + } +} + +static void AddSpritesToOamBuffer(void) +{ + u8 i = 0; + u8 oamIndex = 0; + + while (i < MAX_SPRITES) + { + struct Sprite *sprite = &gSprites[gSpriteOrder[i]]; + if (sprite->inUse && !sprite->invisible && AddSpriteToOamBuffer(sprite, &oamIndex)) + break; + i++; + } + + gMain.objCount = oamIndex; + + while (oamIndex < gOamLimit) + { + gMain.oamBuffer[oamIndex] = gDummyOamData; + oamIndex++; + } +} + +u8 CreateSprite(struct SpriteTemplate *template, u16 x, u16 y, u8 subpriority) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + if (!gSprites[i].inUse) + return CreateSpriteAt(i, template, x, y, subpriority); + + return MAX_SPRITES; +} + +u8 CreateSpriteAtEnd(struct SpriteTemplate *template, u16 x, u16 y, u8 subpriority) +{ + s16 i; + + for (i = MAX_SPRITES - 1; i > -1; i--) + if (!gSprites[i].inUse) + return CreateSpriteAt(i, template, x, y, subpriority); + + return MAX_SPRITES; +} + +u8 CreateInvisibleSprite(void (*callback)(struct Sprite *)) +{ + u8 index = CreateSprite((struct SpriteTemplate *)&gDummySpriteTemplate, 0, 0, 31); + + if (index == MAX_SPRITES) + { + return MAX_SPRITES; + } + else + { + gSprites[index].invisible = TRUE; + gSprites[index].callback = callback; + return index; + } +} + +static u8 CreateSpriteAt(u8 index, struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + struct Sprite *sprite = &gSprites[index]; + + ResetSprite(sprite); + + sprite->inUse = TRUE; + sprite->animBeginning = TRUE; + sprite->affineAnimBeginning = TRUE; + sprite->usingSheet = TRUE; + + sprite->subpriority = subpriority; + sprite->oam = *template->oam; + sprite->anims = template->anims; + sprite->affineAnims = template->affineAnims; + sprite->template = template; + sprite->callback = template->callback; + sprite->pos1.x = x; + sprite->pos1.y = y; + + CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); + + if (template->tileTag == 0xFFFF) + { + s16 tileNum; + sprite->images = template->images; + tileNum = AllocSpriteTiles((u8)(sprite->images->size / TILE_SIZE_4BPP)); + if (tileNum == -1) + { + ResetSprite(sprite); + return MAX_SPRITES; + } + sprite->oam.tileNum = tileNum; + sprite->usingSheet = FALSE; + sprite->sheetTileStart = 0; + } + else + { + sprite->sheetTileStart = GetSpriteTileStartByTag(template->tileTag); + SetSpriteSheetFrameTileNum(sprite); + } + + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + InitSpriteAffineAnim(sprite); + + if (template->paletteTag != 0xFFFF) + sprite->oam.paletteNum = IndexOfSpritePaletteTag(template->paletteTag); + + return index; +} + +u8 CreateSpriteAndAnimate(struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + + if (!gSprites[i].inUse) + { + u8 index = CreateSpriteAt(i, template, x, y, subpriority); + + if (index == MAX_SPRITES) + return MAX_SPRITES; + + gSprites[i].callback(sprite); + + if (gSprites[i].inUse) + AnimateSprite(sprite); + + return index; + } + } + + return MAX_SPRITES; +} + +void DestroySprite(struct Sprite *sprite) +{ + if (sprite->inUse) + { + if (!sprite->usingSheet) + { + u16 i; + u16 tileEnd = (sprite->images->size / TILE_SIZE_4BPP) + sprite->oam.tileNum; + for (i = sprite->oam.tileNum; i < tileEnd; i++) + gSpriteTileAllocBitmap[i / 8] &= ~(1 << (i % 8)); + } + ResetSprite(sprite); + } +} + +void ResetOamRange(u8 a, u8 b) +{ + u8 i; + + for (i = a; i < b; i++) + { + struct OamData *oamBuffer = gMain.oamBuffer; + oamBuffer[i] = *(struct OamData *)&gDummyOamData; + } +} + +void LoadOam(void) +{ + if (!gMain.oamLoadDisabled) + CpuCopy32(gMain.oamBuffer, (void *)OAM, sizeof(gMain.oamBuffer)); +} + +static void ClearSpriteCopyRequests(void) +{ + u8 i; + + gShouldProcessSpriteCopyRequests = FALSE; + gSpriteCopyRequestCount = 0; + + for (i = 0; i < MAX_SPRITE_COPY_REQUESTS; i++) + { + gSpriteCopyRequests[i].src = 0; + gSpriteCopyRequests[i].dest = 0; + gSpriteCopyRequests[i].size = 0; + } +} + +static void ResetOamMatrices(void) +{ + u8 i; + for (i = 0; i < OAM_MATRIX_COUNT; i++) + { + // set to identity matrix + gOamMatrices[i].a = 0x0100; + gOamMatrices[i].b = 0x0000; + gOamMatrices[i].c = 0x0000; + gOamMatrices[i].d = 0x0100; + } +} + +void SetOamMatrix(u8 matrixNum, u16 a, u16 b, u16 c, u16 d) +{ + gOamMatrices[matrixNum].a = a; + gOamMatrices[matrixNum].b = b; + gOamMatrices[matrixNum].c = c; + gOamMatrices[matrixNum].d = d; +} + +static void ResetSprite(struct Sprite *sprite) +{ + *sprite = sDummySprite; +} + +void CalcCenterToCornerVec(struct Sprite *sprite, u8 shape, u8 size, u8 affineMode) +{ + u8 x = sCenterToCornerVecTable[shape][size][0]; + u8 y = sCenterToCornerVecTable[shape][size][1]; + + if (affineMode & ST_OAM_AFFINE_DOUBLE_MASK) + { + x *= 2; + y *= 2; + } + + sprite->centerToCornerVecX = x; + sprite->centerToCornerVecY = y; +} + +static s16 AllocSpriteTiles(u16 tileCount) +{ + u16 i; + s16 start; + u16 numTilesFound; + + if (tileCount == 0) + { + for (i = gReservedSpriteTileCount; i < TOTAL_OBJ_TILE_COUNT; i++) + gSpriteTileAllocBitmap[i / 8] &= ~(1 << (i % 8)); + + return 0; + } + + i = gReservedSpriteTileCount; + + for (;;) + { + while ((gSpriteTileAllocBitmap[i / 8] >> (i % 8)) & 1) + { + i++; + + if (i == TOTAL_OBJ_TILE_COUNT) + return -1; + } + + start = i; + numTilesFound = 1; + + while (numTilesFound != tileCount) + { + i++; + + if (i == TOTAL_OBJ_TILE_COUNT) + return -1; + + if (!((gSpriteTileAllocBitmap[i / 8] >> (i % 8)) & 1)) + numTilesFound++; + else + break; + } + + if (numTilesFound == tileCount) + break; + } + + for (i = start; i < tileCount + start; i++) + gSpriteTileAllocBitmap[i / 8] |= (1 << (i % 8)); + + return start; +} + +static u8 SpriteTileAllocBitmapOp(u16 bit, u8 op) +{ + u8 index = bit / 8; + u8 shift = bit % 8; + u8 val = bit % 8; + u8 retVal = 0; + + if (op == 0) + { + val = ~(1 << val); + gSpriteTileAllocBitmap[index] &= val; + } + else if (op == 1) + { + val = (1 << val); + gSpriteTileAllocBitmap[index] |= val; + } + else + { + retVal = 1 << shift; + retVal &= gSpriteTileAllocBitmap[index]; + } + + return retVal; +} + +void SpriteCallbackDummy(struct Sprite *sprite) +{ +} + +void ProcessSpriteCopyRequests(void) +{ + if (gShouldProcessSpriteCopyRequests) + { + u8 i = 0; + + while (gSpriteCopyRequestCount > 0) + { + CpuCopy16(gSpriteCopyRequests[i].src, gSpriteCopyRequests[i].dest, gSpriteCopyRequests[i].size); + gSpriteCopyRequestCount--; + i++; + } + + gShouldProcessSpriteCopyRequests = FALSE; + } +} + +static void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, struct SpriteFrameImage *images) +{ + if (gSpriteCopyRequestCount < MAX_SPRITE_COPY_REQUESTS) + { + gSpriteCopyRequests[gSpriteCopyRequestCount].src = images[index].data; + gSpriteCopyRequests[gSpriteCopyRequestCount].dest = (u8 *)OBJ_VRAM0 + TILE_SIZE_4BPP * tileNum; + gSpriteCopyRequests[gSpriteCopyRequestCount].size = images[index].size; + gSpriteCopyRequestCount++; + } +} + +void RequestSpriteCopy(u8 *src, u8 *dest, u16 size) +{ + if (gSpriteCopyRequestCount < MAX_SPRITE_COPY_REQUESTS) + { + gSpriteCopyRequests[gSpriteCopyRequestCount].src = src; + gSpriteCopyRequests[gSpriteCopyRequestCount].dest = dest; + gSpriteCopyRequests[gSpriteCopyRequestCount].size = size; + gSpriteCopyRequestCount++; + } +} + +static void CopyFromSprites(u8 *dest) +{ + u32 i; + u8 *src = (u8 *)gSprites; + for (i = 0; i < sizeof(struct Sprite) * MAX_SPRITES; i++) + { + *dest = *src; + dest++; + src++; + } +} + +static void CopyToSprites(u8 *src) +{ + u32 i; + u8 *dest = (u8 *)gSprites; + for (i = 0; i < sizeof(struct Sprite) * MAX_SPRITES; i++) + { + *dest = *src; + src++; + dest++; + } +} + +static void ResetAllSprites(void) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + ResetSprite(&gSprites[i]); + gSpriteOrder[i] = i; + } + + ResetSprite(&gSprites[i]); + sub_814A590(); +} + +void FreeSpriteTiles(struct Sprite *sprite) +{ + if (sprite->template->tileTag != 0xFFFF) + FreeSpriteTilesByTag(sprite->template->tileTag); +} + +void FreeSpritePalette(struct Sprite *sprite) +{ + FreeSpritePaletteByTag(sprite->template->paletteTag); +} + +void FreeSpriteOamMatrix(struct Sprite *sprite) +{ + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + { + FreeOamMatrix(sprite->oam.matrixNum); + sprite->oam.affineMode = ST_OAM_AFFINE_OFF; + } +} + +void DestroySpriteAndFreeResources(struct Sprite *sprite) +{ + FreeSpriteTiles(sprite); + FreeSpritePalette(sprite); + FreeSpriteOamMatrix(sprite); + DestroySprite(sprite); +} + +void sub_800142C(u32 a1, u32 a2, u16 *a3, u16 a4, u32 a5) +{ + u16 *d = a3; + struct OamData *oam = &gMain.oamBuffer[gMain.objCount]; + while (!(gMain.objCount & 0x80) && (s16)(d[0] + 1) != 0) + { + u16 *x = (u16 *)oam; + x[0] = (d[0] & sOamBitmasks[0]) | ((d[0] + a2) & sOamBitmasks[1]) | ((a4 & sOamBitmasks[2]) << 8); + x[1] = (d[1] & sOamBitmasks[3]) | ((d[1] + a1) & sOamBitmasks[4]) | ((a4 & sOamBitmasks[5]) << 4); + x[2] = (d[2] & sOamBitmasks[6]) | ((d[2] + a5) & sOamBitmasks[7]) | (a4 & sOamBitmasks[8]); + oam++; + gMain.objCount++; + d += 3; + } +} + +void AnimateSprite(struct Sprite *sprite) +{ + sAnimFuncs[sprite->animBeginning](sprite); + + if (!gAffineAnimsDisabled) + sAffineAnimFuncs[sprite->affineAnimBeginning](sprite); +} + +static void BeginAnim(struct Sprite *sprite) +{ + s16 imageValue; + u8 duration; + u8 hFlip; + u8 vFlip; + + sprite->animCmdIndex = 0; + sprite->animEnded = FALSE; + sprite->animLoopCounter = 0; + imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + + if (imageValue != -1) + { + sprite->animBeginning = FALSE; + duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + + if (duration) + duration--; + + sprite->animDelayCounter = duration; + + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + + if (sprite->usingSheet) + sprite->oam.tileNum = sprite->sheetTileStart + imageValue; + else + RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); + } +} + +static void ContinueAnim(struct Sprite *sprite) +{ + if (sprite->animDelayCounter) + { + u8 hFlip; + u8 vFlip; + DecrementAnimDelayCounter(sprite); + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + } + else if (!sprite->animPaused) + { + s16 type; + s16 funcIndex; + sprite->animCmdIndex++; + type = sprite->anims[sprite->animNum][sprite->animCmdIndex].type; + funcIndex = 3; + if (type < 0) + funcIndex = type + 3; + sAnimCmdFuncs[funcIndex](sprite); + } +} + +static void AnimCmd_frame(struct Sprite *sprite) +{ + s16 imageValue; + u8 duration; + u8 hFlip; + u8 vFlip; + + imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + + if (duration) + duration--; + + sprite->animDelayCounter = duration; + + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + + if (sprite->usingSheet) + sprite->oam.tileNum = sprite->sheetTileStart + imageValue; + else + RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); +} + +static void AnimCmd_end(struct Sprite *sprite) +{ + sprite->animCmdIndex--; + sprite->animEnded = TRUE; +} + +static void AnimCmd_jump(struct Sprite *sprite) +{ + s16 imageValue; + u8 duration; + u8 hFlip; + u8 vFlip; + + sprite->animCmdIndex = sprite->anims[sprite->animNum][sprite->animCmdIndex].jump.target; + + imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + + if (duration) + duration--; + + sprite->animDelayCounter = duration; + + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + + if (sprite->usingSheet) + sprite->oam.tileNum = sprite->sheetTileStart + imageValue; + else + RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); +} + +static void AnimCmd_loop(struct Sprite *sprite) +{ + if (sprite->animLoopCounter) + ContinueAnimLoop(sprite); + else + BeginAnimLoop(sprite); +} + +static void BeginAnimLoop(struct Sprite *sprite) +{ + sprite->animLoopCounter = sprite->anims[sprite->animNum][sprite->animCmdIndex].loop.count; + JumpToTopOfAnimLoop(sprite); + ContinueAnim(sprite); +} + +static void ContinueAnimLoop(struct Sprite *sprite) +{ + sprite->animLoopCounter--; + JumpToTopOfAnimLoop(sprite); + ContinueAnim(sprite); +} + +static void JumpToTopOfAnimLoop(struct Sprite *sprite) +{ + if (sprite->animLoopCounter) + { + sprite->animCmdIndex--; + + while (sprite->anims[sprite->animNum][sprite->animCmdIndex - 1].type != -3) + { + if (sprite->animCmdIndex == 0) + break; + sprite->animCmdIndex--; + } + + sprite->animCmdIndex--; + } +} + +static void BeginAffineAnim(struct Sprite *sprite) +{ + if ((sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) && sprite->affineAnims[0][0].type != 32767) + { + struct AffineAnimFrameCmd frameCmd; + u8 matrixNum = GetSpriteMatrixNum(sprite); + AffineAnimStateRestartAnim(matrixNum); + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + sprite->affineAnimBeginning = FALSE; + sprite->affineAnimEnded = FALSE; + ApplyAffineAnimFrame(matrixNum, &frameCmd); + sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; + } +} + +static void ContinueAffineAnim(struct Sprite *sprite) +{ + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + { + u8 matrixNum = GetSpriteMatrixNum(sprite); + + if (sAffineAnimStates[matrixNum].delayCounter) + { + AffineAnimDelay(matrixNum, sprite); + } + else if (!sprite->affineAnimPaused) + { + s16 type; + s16 funcIndex; + sAffineAnimStates[matrixNum].animCmdIndex++; + type = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].type; + funcIndex = 3; + if (type >= 32765) + funcIndex = type - 32765; + sAffineAnimCmdFuncs[funcIndex](matrixNum, sprite); + } + } +} + +static void AffineAnimDelay(u8 matrixNum, struct Sprite *sprite) +{ + if (!DecrementAffineAnimDelayCounter(sprite, matrixNum)) + { + struct AffineAnimFrameCmd frameCmd; + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &frameCmd); + } +} + +static void AffineAnimCmd_loop(u8 matrixNum, struct Sprite *sprite) +{ + if (sAffineAnimStates[matrixNum].loopCounter) + ContinueAffineAnimLoop(matrixNum, sprite); + else + BeginAffineAnimLoop(matrixNum, sprite); +} + +static void BeginAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) +{ + sAffineAnimStates[matrixNum].loopCounter = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].loop.count; + JumpToTopOfAffineAnimLoop(matrixNum, sprite); + ContinueAffineAnim(sprite); +} + +static void ContinueAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) +{ + sAffineAnimStates[matrixNum].loopCounter--; + JumpToTopOfAffineAnimLoop(matrixNum, sprite); + ContinueAffineAnim(sprite); +} + +static void JumpToTopOfAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) +{ + if (sAffineAnimStates[matrixNum].loopCounter) + { + sAffineAnimStates[matrixNum].animCmdIndex--; + + while (sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex - 1].type != 32765) + { + if (sAffineAnimStates[matrixNum].animCmdIndex == 0) + break; + sAffineAnimStates[matrixNum].animCmdIndex--; + } + + sAffineAnimStates[matrixNum].animCmdIndex--; + } +} + +static void AffineAnimCmd_jump(u8 matrixNum, struct Sprite *sprite) +{ + struct AffineAnimFrameCmd frameCmd; + sAffineAnimStates[matrixNum].animCmdIndex = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].jump.target; + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + ApplyAffineAnimFrame(matrixNum, &frameCmd); + sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; +} + +static void AffineAnimCmd_end(u8 matrixNum, struct Sprite *sprite) +{ + struct AffineAnimFrameCmd dummyFrameCmd = {0}; + sprite->affineAnimEnded = TRUE; + sAffineAnimStates[matrixNum].animCmdIndex--; + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &dummyFrameCmd); +} + +static void AffineAnimCmd_frame(u8 matrixNum, struct Sprite *sprite) +{ + struct AffineAnimFrameCmd frameCmd; + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + ApplyAffineAnimFrame(matrixNum, &frameCmd); + sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; +} + +static void CopyOamMatrix(u8 destMatrixIndex, struct OamMatrix *srcMatrix) +{ + gOamMatrices[destMatrixIndex].a = srcMatrix->a; + gOamMatrices[destMatrixIndex].b = srcMatrix->b; + gOamMatrices[destMatrixIndex].c = srcMatrix->c; + gOamMatrices[destMatrixIndex].d = srcMatrix->d; +} + +static u8 GetSpriteMatrixNum(struct Sprite *sprite) +{ + u8 matrixNum = 0; + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + matrixNum = sprite->oam.matrixNum; + return matrixNum; +} + +static void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip) +{ + sprite->oam.matrixNum &= 0x7; + sprite->oam.matrixNum |= (((hFlip ^ sprite->hFlip) & 1) << 3); + sprite->oam.matrixNum |= (((vFlip ^ sprite->vFlip) & 1) << 4); +} + +static void AffineAnimStateRestartAnim(u8 matrixNum) +{ + sAffineAnimStates[matrixNum].animCmdIndex = 0; + sAffineAnimStates[matrixNum].delayCounter = 0; + sAffineAnimStates[matrixNum].loopCounter = 0; +} + +static void AffineAnimStateStartAnim(u8 matrixNum, u8 animNum) +{ + sAffineAnimStates[matrixNum].animNum = animNum; + sAffineAnimStates[matrixNum].animCmdIndex = 0; + sAffineAnimStates[matrixNum].delayCounter = 0; + sAffineAnimStates[matrixNum].loopCounter = 0; + sAffineAnimStates[matrixNum].xScale = 0x0100; + sAffineAnimStates[matrixNum].yScale = 0x0100; + sAffineAnimStates[matrixNum].rotation = 0; +} + +static void AffineAnimStateReset(u8 matrixNum) +{ + sAffineAnimStates[matrixNum].animNum = 0; + sAffineAnimStates[matrixNum].animCmdIndex = 0; + sAffineAnimStates[matrixNum].delayCounter = 0; + sAffineAnimStates[matrixNum].loopCounter = 0; + sAffineAnimStates[matrixNum].xScale = 0x0100; + sAffineAnimStates[matrixNum].yScale = 0x0100; + sAffineAnimStates[matrixNum].rotation = 0; +} + +static void ApplyAffineAnimFrameAbsolute(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) +{ + sAffineAnimStates[matrixNum].xScale = frameCmd->xScale; + sAffineAnimStates[matrixNum].yScale = frameCmd->yScale; + sAffineAnimStates[matrixNum].rotation = frameCmd->rotation << 8; +} + +static void DecrementAnimDelayCounter(struct Sprite *sprite) +{ + if (!sprite->animPaused) + sprite->animDelayCounter--; +} + +static bool8 DecrementAffineAnimDelayCounter(struct Sprite *sprite, u8 matrixNum) +{ + if (!sprite->affineAnimPaused) + --sAffineAnimStates[matrixNum].delayCounter; + return sprite->affineAnimPaused; +} + +static void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) +{ + struct ObjAffineSrcData srcData; + struct OamMatrix matrix; + sAffineAnimStates[matrixNum].xScale += frameCmd->xScale; + sAffineAnimStates[matrixNum].yScale += frameCmd->yScale; + sAffineAnimStates[matrixNum].rotation = (sAffineAnimStates[matrixNum].rotation + (frameCmd->rotation << 8)) & ~0xFF; + srcData.xScale = ConvertScaleParam(sAffineAnimStates[matrixNum].xScale); + srcData.yScale = ConvertScaleParam(sAffineAnimStates[matrixNum].yScale); + srcData.rotation = sAffineAnimStates[matrixNum].rotation; + ObjAffineSet(&srcData, &matrix, 1, 2); + CopyOamMatrix(matrixNum, &matrix); +} + +static s16 ConvertScaleParam(s16 scale) +{ + s32 val = 0x10000; + return val / scale; +} + +static void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd) +{ + frameCmd->xScale = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.xScale; + frameCmd->yScale = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.yScale; + frameCmd->rotation = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.rotation; + frameCmd->duration = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.duration; +} + +static void ApplyAffineAnimFrame(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) +{ + struct AffineAnimFrameCmd dummyFrameCmd = {0}; + + if (frameCmd->duration) + { + frameCmd->duration--; + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, frameCmd); + } + else + { + ApplyAffineAnimFrameAbsolute(matrixNum, frameCmd); + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &dummyFrameCmd); + } +} + +void StartSpriteAnim(struct Sprite *sprite, u8 animNum) +{ + sprite->animNum = animNum; + sprite->animBeginning = TRUE; + sprite->animEnded = FALSE; +} + +void StartSpriteAnimIfDifferent(struct Sprite *sprite, u8 animNum) +{ + if (sprite->animNum != animNum) + StartSpriteAnim(sprite, animNum); +} + +void SeekSpriteAnim(struct Sprite *sprite, u8 animCmdIndex) +{ + u8 temp = sprite->animPaused; + sprite->animCmdIndex = animCmdIndex - 1; + sprite->animDelayCounter = 0; + sprite->animBeginning = FALSE; + sprite->animEnded = FALSE; + sprite->animPaused = FALSE; + ContinueAnim(sprite); + if (sprite->animDelayCounter) + sprite->animDelayCounter++; + sprite->animPaused = temp; +} + +void StartSpriteAffineAnim(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + AffineAnimStateStartAnim(matrixNum, animNum); + sprite->affineAnimBeginning = TRUE; + sprite->affineAnimEnded = FALSE; +} + +void StartSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + if (sAffineAnimStates[matrixNum].animNum != animNum) + StartSpriteAffineAnim(sprite, animNum); +} + +void ChangeSpriteAffineAnim(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + sAffineAnimStates[matrixNum].animNum = animNum; + sprite->affineAnimBeginning = TRUE; + sprite->affineAnimEnded = FALSE; +} + +void ChangeSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + if (sAffineAnimStates[matrixNum].animNum != animNum) + ChangeSpriteAffineAnim(sprite, animNum); +} + +void SetSpriteSheetFrameTileNum(struct Sprite *sprite) +{ + if (sprite->usingSheet) + { + s16 tileOffset = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + if (tileOffset < 0) + tileOffset = 0; + sprite->oam.tileNum = sprite->sheetTileStart + tileOffset; + } +} + +static void ResetAffineAnimData(void) +{ + u8 i; + + gAffineAnimsDisabled = 0; + gOamMatrixAllocBitmap = 0; + + ResetOamMatrices(); + + for (i = 0; i < OAM_MATRIX_COUNT; i++) + AffineAnimStateReset(i); +} + +u8 AllocOamMatrix(void) +{ + u8 i = 0; + u32 bit = 1; + u32 bitmap = gOamMatrixAllocBitmap; + + while (i < OAM_MATRIX_COUNT) + { + if (!(bitmap & bit)) + { + gOamMatrixAllocBitmap |= bit; + return i; + } + + i++; + bit <<= 1; + } + + return 0xFF; +} + +void FreeOamMatrix(u8 matrixNum) +{ + u8 i = 0; + u32 bit = 1; + + while (i < matrixNum) + { + i++; + bit <<= 1; + } + + gOamMatrixAllocBitmap &= ~bit; + SetOamMatrix(matrixNum, 0x100, 0, 0, 0x100); +} + +void InitSpriteAffineAnim(struct Sprite *sprite) +{ + u8 matrixNum = AllocOamMatrix(); + if (matrixNum != 0xFF) + { + CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); + sprite->oam.matrixNum = matrixNum; + sprite->affineAnimBeginning = TRUE; + AffineAnimStateReset(matrixNum); + } +} + +void SetOamMatrixRotationScaling(u8 matrixNum, s16 xScale, s16 yScale, u16 rotation) +{ + struct ObjAffineSrcData srcData; + struct OamMatrix matrix; + srcData.xScale = ConvertScaleParam(xScale); + srcData.yScale = ConvertScaleParam(yScale); + srcData.rotation = rotation; + ObjAffineSet(&srcData, &matrix, 1, 2); + CopyOamMatrix(matrixNum, &matrix); +} + +u16 LoadSpriteSheet(struct SpriteSheet *sheet) +{ + s16 tileStart = AllocSpriteTiles(sheet->size / TILE_SIZE_4BPP); + + if (tileStart < 0) + { + return 0; + } + else + { + AddSpriteTileRange(sheet->tag, (u16)tileStart, sheet->size / TILE_SIZE_4BPP); + CpuCopy16(sheet->data, (u8 *)OBJ_VRAM0 + TILE_SIZE_4BPP * tileStart, sheet->size); + return (u16)tileStart; + } +} + +void LoadSpriteSheets(struct SpriteSheet *sheets) +{ + u8 i; + for (i = 0; sheets[i].data != NULL; i++) + LoadSpriteSheet(&sheets[i]); +} + +u16 AllocTilesForSpriteSheet(struct SpriteSheet *sheet) +{ + s16 tileStart = AllocSpriteTiles(sheet->size / TILE_SIZE_4BPP); + + if (tileStart < 0) + { + return 0; + } + else + { + AddSpriteTileRange(sheet->tag, (u16)tileStart, sheet->size / TILE_SIZE_4BPP); + return (u16)tileStart; + } +} + +void AllocTilesForSpriteSheets(struct SpriteSheet *sheets) +{ + u8 i; + for (i = 0; sheets[i].data != NULL; i++) + AllocTilesForSpriteSheet(&sheets[i]); +} + +void LoadTilesForSpriteSheet(struct SpriteSheet *sheet) +{ + u8 *data = sheet->data; + u16 tileStart = GetSpriteTileStartByTag(sheet->tag); + CpuCopy16(data, (u8 *)OBJ_VRAM0 + TILE_SIZE_4BPP * tileStart, sheet->size); +} + +void LoadTilesForSpriteSheets(struct SpriteSheet *sheets) +{ + u8 i; + for (i = 0; sheets[i].data != NULL; i++) + LoadTilesForSpriteSheet(&sheets[i]); +} + +void FreeSpriteTilesByTag(u16 tag) +{ + u8 index = IndexOfSpriteTileTag(tag); + if (index != 0xFF) + { + u16 i; + u16 *rangeStarts; + u16 *rangeCounts; + u16 start; + u16 count; + rangeStarts = sSpriteTileRanges; + start = rangeStarts[index * 2]; + rangeCounts = sSpriteTileRanges + 1; + count = rangeCounts[index * 2]; + + for (i = start; i < start + count; i++) + gSpriteTileAllocBitmap[i / 8] &= ~(1 << (i % 8)); + + sSpriteTileRangeTags[index] = 0xFFFF; + } +} + +void FreeAllSpriteTiles(void) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + sSpriteTileRangeTags[i] = 0xFFFF; + SET_SPRITE_TILE_RANGE(i, 0, 0); + } +} + +u16 GetSpriteTileStartByTag(u16 tag) +{ + u8 index = IndexOfSpriteTileTag(tag); + if (index == 0xFF) + return 0xFFFF; + return sSpriteTileRanges[index * 2]; +} + +static u8 IndexOfSpriteTileTag(u16 tag) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + if (sSpriteTileRangeTags[i] == tag) + return i; + + return 0xFF; +} + +u16 GetSpriteTileTagByTileStart(u16 start) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + if (sSpriteTileRangeTags[i] != 0xFFFF && sSpriteTileRanges[i * 2] == start) + return sSpriteTileRangeTags[i]; + } + + return 0xFFFF; +} + +static void AddSpriteTileRange(u16 tag, u16 start, u16 count) +{ + u8 freeIndex = IndexOfSpriteTileTag(0xFFFF); + sSpriteTileRangeTags[freeIndex] = tag; + SET_SPRITE_TILE_RANGE(freeIndex, start, count); +} + +void RequestSpriteSheetCopy(struct SpriteSheet *sheet) +{ + u8 *data = sheet->data; + u16 tileStart = GetSpriteTileStartByTag(sheet->tag); + RequestSpriteCopy(data, (u8 *)OBJ_VRAM0 + tileStart * TILE_SIZE_4BPP, sheet->size); +} + +u16 LoadSpriteSheetDeferred(struct SpriteSheet *sheet) +{ + s16 tileStart = AllocSpriteTiles(sheet->size / TILE_SIZE_4BPP); + + if (tileStart < 0) + { + return 0; + } + else + { + AddSpriteTileRange(sheet->tag, (u16)tileStart, sheet->size / TILE_SIZE_4BPP); + RequestSpriteSheetCopy(sheet); + return (u16)tileStart; + } +} + +void FreeAllSpritePalettes(void) +{ + u8 i; + gReservedSpritePaletteCount = 0; + for (i = 0; i < 16; i++) + sSpritePaletteTags[i] = 0xFFFF; +} + +u8 LoadSpritePalette(struct SpritePalette *palette) +{ + u8 index = IndexOfSpritePaletteTag(palette->tag); + + if (index != 0xFF) + return index; + + index = IndexOfSpritePaletteTag(0xFFFF); + + if (index == 0xFF) + { + return 0xFF; + } + else + { + sSpritePaletteTags[index] = palette->tag; + ApplySpritePalette(palette->data, index * 16); + return index; + } +} + +void LoadSpritePalettes(struct SpritePalette *palettes) +{ + u8 i; + for (i = 0; palettes[i].data != NULL; i++) + if (LoadSpritePalette(&palettes[i]) == 0xFF) + break; +} + +static void ApplySpritePalette(u8 *src, u16 paletteOffset) +{ + gpu_pal_apply(src, paletteOffset + 0x100, 32); +} + +u8 AllocSpritePalette(u16 tag) +{ + u8 index = IndexOfSpritePaletteTag(0xFFFF); + if (index == 0xFF) + { + return 0xFF; + } + else + { + sSpritePaletteTags[index] = tag; + return index; + } +} + +u8 IndexOfSpritePaletteTag(u16 tag) +{ + u8 i; + for (i = gReservedSpritePaletteCount; i < 16; i++) + if (sSpritePaletteTags[i] == tag) + return i; + + return 0xFF; +} + +u16 GetSpritePaletteTagByPaletteNum(u8 paletteNum) +{ + return sSpritePaletteTags[paletteNum]; +} + +void FreeSpritePaletteByTag(u16 tag) +{ + u8 index = IndexOfSpritePaletteTag(tag); + if (index != 0xFF) + sSpritePaletteTags[index] = 0xFFFF; +} + +void SetSubspriteTables(struct Sprite *sprite, struct SubspriteTable *subspriteTables) +{ + sprite->subspriteTables = subspriteTables; + sprite->subspriteTableNum = 0; + sprite->subspriteMode = SUBSPRITES_ON; +} + +bool8 AddSpriteToOamBuffer(struct Sprite *sprite, u8 *oamIndex) +{ + if (*oamIndex >= gOamLimit) + return 1; + + if (!sprite->subspriteTables || sprite->subspriteMode == SUBSPRITES_OFF) + { + gMain.oamBuffer[*oamIndex] = sprite->oam; + (*oamIndex)++; + return 0; + } + else + { + return AddSubspritesToOamBuffer(sprite, &gMain.oamBuffer[*oamIndex], oamIndex); + } +} + +bool8 AddSubspritesToOamBuffer(struct Sprite *sprite, struct OamData *destOam, u8 *oamIndex) +{ + struct SubspriteTable *subspriteTable; + struct OamData *oam; + + if (*oamIndex >= gOamLimit) + return 1; + + subspriteTable = &sprite->subspriteTables[sprite->subspriteTableNum]; + oam = &sprite->oam; + + if (!subspriteTable || !subspriteTable->subsprites) + { + *destOam = *oam; + (*oamIndex)++; + return 0; + } + else + { + u16 tileNum; + u16 baseX; + u16 baseY; + u8 subspriteCount; + u8 hFlip; + u8 vFlip; + u8 i; + + tileNum = oam->tileNum; + subspriteCount = subspriteTable->subspriteCount; + hFlip = ((s32)oam->matrixNum >> 3) & 1; + vFlip = ((s32)oam->matrixNum >> 4) & 1; + baseX = oam->x - sprite->centerToCornerVecX; + baseY = oam->y - sprite->centerToCornerVecY; + + for (i = 0; i < subspriteCount; i++, (*oamIndex)++) + { + u16 x; + u16 y; + + if (*oamIndex >= gOamLimit) + return 1; + + x = subspriteTable->subsprites[i].x; + y = subspriteTable->subsprites[i].y; + + if (hFlip) + { + s8 width = sOamDimensions[subspriteTable->subsprites[i].shape][subspriteTable->subsprites[i].size].width; + s16 right = x; + right += width; + x = right; + x = ~x + 1; + } + + if (vFlip) + { + s8 height = sOamDimensions[subspriteTable->subsprites[i].shape][subspriteTable->subsprites[i].size].height; + s16 bottom = y; + bottom += height; + y = bottom; + y = ~y + 1; + } + + destOam[i] = *oam; + destOam[i].shape = subspriteTable->subsprites[i].shape; + destOam[i].size = subspriteTable->subsprites[i].size; + destOam[i].x = (s16)baseX + (s16)x; + destOam[i].y = baseY + y; + destOam[i].tileNum = tileNum + subspriteTable->subsprites[i].tileOffset; + + if (sprite->subspriteMode != SUBSPRITES_IGNORE_PRIORITY) + destOam[i].priority = subspriteTable->subsprites[i].priority; + } + } + + return 0; +} |