1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
|
#ifndef GUARD_SPRITE_H
#define GUARD_SPRITE_H
#define MAX_SPRITES 64
#define SPRITE_NONE 0xFF
#define TAG_NONE 0xFFFF
// Given to SetSpriteMatrixAnchor to skip anchoring one of the coords.
#define NO_ANCHOR 0x800
struct SpriteSheet
{
const void *data; // Raw uncompressed pixel data
u16 size;
u16 tag;
};
struct CompressedSpriteSheet
{
const u32 *data; // LZ77 compressed pixel data
u16 size; // Uncompressed size of pixel data
u16 tag;
};
struct SpriteFrameImage
{
const void *data;
u16 size;
};
#define obj_frame_tiles(ptr) {.data = (u8 *)ptr, .size = sizeof ptr}
#define overworld_frame(ptr, width, height, frame) {.data = (u8 *)ptr + (width * height * frame * 64)/2, .size = (width * height * 64)/2}
struct SpritePalette
{
const u16 *data; // Raw uncompressed palette data
u16 tag;
};
struct CompressedSpritePalette
{
const u32 *data; // LZ77 compressed palette data
u16 tag;
};
struct AnimFrameCmd
{
// If the sprite has an array of images, this is the array index.
// If the sprite has a sheet, this is the tile offset.
u32 imageValue:16;
u32 duration:6;
u32 hFlip:1;
u32 vFlip:1;
};
struct AnimLoopCmd
{
u32 type:16;
u32 count:6;
};
struct AnimJumpCmd
{
u32 type:16;
u32 target:6;
};
// The first halfword of this union specifies the type of command.
// If it -2, then it is a jump command. If it is -1, then it is the end of the script.
// Otherwise, it is the imageValue for a frame command.
union AnimCmd
{
s16 type;
struct AnimFrameCmd frame;
struct AnimLoopCmd loop;
struct AnimJumpCmd jump;
};
#define ANIMCMD_FRAME(...) \
{.frame = {__VA_ARGS__}}
#define ANIMCMD_LOOP(_count) \
{.loop = {.type = -3, .count = _count}}
#define ANIMCMD_JUMP(_target) \
{.jump = {.type = -2, .target = _target}}
#define ANIMCMD_END \
{.type = -1}
struct AffineAnimFrameCmd
{
s16 xScale;
s16 yScale;
u8 rotation;
u8 duration;
};
struct AffineAnimLoopCmd
{
s16 type;
s16 count;
};
struct AffineAnimJumpCmd
{
s16 type;
u16 target;
};
struct AffineAnimEndCmdAlt
{
s16 type;
u16 val;
};
union AffineAnimCmd
{
s16 type;
struct AffineAnimFrameCmd frame;
struct AffineAnimLoopCmd loop;
struct AffineAnimJumpCmd jump;
struct AffineAnimEndCmdAlt end; // unused in code
};
#define AFFINEANIMCMDTYPE_LOOP 0x7FFD
#define AFFINEANIMCMDTYPE_JUMP 0x7FFE
#define AFFINEANIMCMDTYPE_END 0x7FFF
#define AFFINEANIMCMD_FRAME(_xScale, _yScale, _rotation, _duration) \
{.frame = {.xScale = _xScale, .yScale = _yScale, .rotation = _rotation, .duration = _duration}}
#define AFFINEANIMCMD_LOOP(_count) \
{.loop = {.type = AFFINEANIMCMDTYPE_LOOP, .count = _count}}
#define AFFINEANIMCMD_JUMP(_target) \
{.jump = {.type = AFFINEANIMCMDTYPE_JUMP, .target = _target}}
#define AFFINEANIMCMD_END \
{.type = AFFINEANIMCMDTYPE_END}
#define AFFINEANIMCMD_END_ALT(_val) \
{.end = {.type = AFFINEANIMCMDTYPE_END, .val = _val}}
struct AffineAnimState
{
u8 animNum;
u8 animCmdIndex;
u8 delayCounter;
u8 loopCounter;
s16 xScale;
s16 yScale;
u16 rotation;
};
enum
{
SUBSPRITES_OFF,
SUBSPRITES_ON,
SUBSPRITES_IGNORE_PRIORITY, // on but priority is ignored
};
struct Subsprite
{
s8 x; // was u16 in R/S
s8 y; // was u16 in R/S
u16 shape:2;
u16 size:2;
u16 tileOffset:10;
u16 priority:2;
};
struct SubspriteTable
{
u8 subspriteCount;
const struct Subsprite *subsprites;
};
struct Sprite;
typedef void (*SpriteCallback)(struct Sprite *);
struct SpriteTemplate
{
u16 tileTag;
u16 paletteTag;
const struct OamData *oam;
const union AnimCmd *const *anims;
const struct SpriteFrameImage *images;
const union AffineAnimCmd *const *affineAnims;
SpriteCallback callback;
};
// UB: template pointer is often used to point to temporary storage,
// then later dereferenced after being freed. Usually this won't
// be visible in-game, but this is (part of) what causes the item
// icon palette to flicker when changing items in the bag.
struct Sprite
{
/*0x00*/ struct OamData oam;
/*0x08*/ const union AnimCmd *const *anims;
/*0x0C*/ const struct SpriteFrameImage *images;
/*0x10*/ const union AffineAnimCmd *const *affineAnims;
/*0x14*/ const struct SpriteTemplate *template;
/*0x18*/ const struct SubspriteTable *subspriteTables;
/*0x1C*/ SpriteCallback callback;
/*0x20*/ s16 x, y;
/*0x24*/ s16 x2, y2;
/*0x28*/ s8 centerToCornerVecX;
/*0x29*/ s8 centerToCornerVecY;
/*0x2A*/ u8 animNum;
/*0x2B*/ u8 animCmdIndex;
/*0x2C*/ u8 animDelayCounter:6;
bool8 animPaused:1;
bool8 affineAnimPaused:1;
/*0x2D*/ u8 animLoopCounter;
// general purpose data fields
/*0x2E*/ s16 data[8];
/*0x3E*/ bool16 inUse:1; //1
bool16 coordOffsetEnabled:1; //2
bool16 invisible:1; //4
bool16 flags_3:1; //8
bool16 flags_4:1; //0x10
bool16 flags_5:1; //0x20
bool16 flags_6:1; //0x40
bool16 flags_7:1; //0x80
/*0x3F*/ bool16 hFlip:1; //1
bool16 vFlip:1; //2
bool16 animBeginning:1; //4
bool16 affineAnimBeginning:1; //8
bool16 animEnded:1; //0x10
bool16 affineAnimEnded:1; //0x20
bool16 usingSheet:1; //0x40
bool16 anchored:1; //0x80
/*0x40*/ u16 sheetTileStart;
/*0x42*/ u8 subspriteTableNum:6;
u8 subspriteMode:2;
/*0x43*/ u8 subpriority;
};
struct OamMatrix
{
s16 a;
s16 b;
s16 c;
s16 d;
};
extern const struct OamData gDummyOamData;
extern const union AnimCmd *const gDummySpriteAnimTable[];
extern const union AffineAnimCmd *const gDummySpriteAffineAnimTable[];
extern const struct SpriteTemplate gDummySpriteTemplate;
extern u8 gReservedSpritePaletteCount;
extern struct Sprite gSprites[];
extern u8 gOamLimit;
extern u16 gReservedSpriteTileCount;
extern s16 gSpriteCoordOffsetX;
extern s16 gSpriteCoordOffsetY;
extern struct OamMatrix gOamMatrices[];
extern bool8 gAffineAnimsDisabled;
void ResetSpriteData(void);
void AnimateSprites(void);
void BuildOamBuffer(void);
u8 CreateSprite(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority);
u8 CreateSpriteAtEnd(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority);
u8 CreateInvisibleSprite(void (*callback)(struct Sprite *));
u8 CreateSpriteAndAnimate(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority);
void DestroySprite(struct Sprite *sprite);
void ResetOamRange(u8 a, u8 b);
void LoadOam(void);
void SetOamMatrix(u8 matrixNum, u16 a, u16 b, u16 c, u16 d);
void CalcCenterToCornerVec(struct Sprite *sprite, u8 shape, u8 size, u8 affineMode);
void SpriteCallbackDummy(struct Sprite *sprite);
void ProcessSpriteCopyRequests(void);
void RequestSpriteCopy(const u8 *src, u8 *dest, u16 size);
void FreeSpriteTiles(struct Sprite *sprite);
void FreeSpritePalette(struct Sprite *sprite);
void FreeSpriteOamMatrix(struct Sprite *sprite);
void DestroySpriteAndFreeResources(struct Sprite *sprite);
void AnimateSprite(struct Sprite *sprite);
void SetSpriteMatrixAnchor(struct Sprite* sprite, s16 x, s16 y);
void StartSpriteAnim(struct Sprite *sprite, u8 animNum);
void StartSpriteAnimIfDifferent(struct Sprite *sprite, u8 animNum);
void SeekSpriteAnim(struct Sprite *sprite, u8 animCmdIndex);
void StartSpriteAffineAnim(struct Sprite *sprite, u8 animNum);
void StartSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum);
void ChangeSpriteAffineAnim(struct Sprite *sprite, u8 animNum);
void ChangeSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum);
void SetSpriteSheetFrameTileNum(struct Sprite *sprite);
u8 AllocOamMatrix(void);
void FreeOamMatrix(u8 matrixNum);
void InitSpriteAffineAnim(struct Sprite *sprite);
void SetOamMatrixRotationScaling(u8 matrixNum, s16 xScale, s16 yScale, u16 rotation);
u16 LoadSpriteSheet(const struct SpriteSheet *sheet);
void LoadSpriteSheets(const struct SpriteSheet *sheets);
u16 AllocTilesForSpriteSheet(struct SpriteSheet *sheet);
void AllocTilesForSpriteSheets(struct SpriteSheet *sheets);
void LoadTilesForSpriteSheet(const struct SpriteSheet *sheet);
void LoadTilesForSpriteSheets(struct SpriteSheet *sheets);
void FreeSpriteTilesByTag(u16 tag);
void FreeSpriteTileRanges(void);
u16 GetSpriteTileStartByTag(u16 tag);
u16 GetSpriteTileTagByTileStart(u16 start);
void RequestSpriteSheetCopy(const struct SpriteSheet *sheet);
u16 LoadSpriteSheetDeferred(const struct SpriteSheet *sheet);
void FreeAllSpritePalettes(void);
u8 LoadSpritePalette(const struct SpritePalette *palette);
void LoadSpritePalettes(const struct SpritePalette *palettes);
u8 AllocSpritePalette(u16 tag);
u8 IndexOfSpritePaletteTag(u16 tag);
u16 GetSpritePaletteTagByPaletteNum(u8 paletteNum);
void FreeSpritePaletteByTag(u16 tag);
void SetSubspriteTables(struct Sprite *sprite, const struct SubspriteTable *subspriteTables);
bool8 AddSpriteToOamBuffer(struct Sprite *object, u8 *oamIndex);
bool8 AddSubspritesToOamBuffer(struct Sprite *sprite, struct OamData *destOam, u8 *oamIndex);
void CopyToSprites(u8 *src);
void CopyFromSprites(u8 *dest);
u8 SpriteTileAllocBitmapOp(u16 bit, u8 op);
void ClearSpriteCopyRequests(void);
void ResetAffineAnimData(void);
#endif //GUARD_SPRITE_H
|