1 #include <bz/gfx/aseprite_internal.h>
3 #include <bz/math/math.h>
4 #include <bz/memory/allocator.h>
5 #include <bz/renderer/palette_internal.h>
6 #include <bz/resources/resource.h>
7 #include <bz/types/identifier_internal.h>
8 #include <stdio.h> // Apparently stb_image.h need this??
11 #include <assert.h> // Static assertions
13 #define PACKED_STRUCT __attribute__((__packed__))
15 typedef uint8_t ASE_BYTE
;
16 typedef uint16_t ASE_WORD
;
17 typedef int16_t ASE_SHORT
;
18 typedef uint32_t ASE_DWORD
;
19 typedef uint32_t ASE_LONG
;
20 typedef uint32_t ASE_FIXED
;
21 typedef float ASE_FLOAT
;
22 typedef double ASE_DOUBLE
;
23 typedef uint64_t ASE_QWORD
;
24 typedef int64_t ASE_LONG64
;
28 struct PACKED_STRUCT ASE_STRING
{
30 //ASE_BYTE characters[];
32 typedef struct ASE_STRING ASE_STRING
;
33 static_assert(sizeof(ASE_STRING
) == 2, "ASE_STRING is wrong size");
35 struct PACKED_STRUCT ASE_POINT
{
39 typedef struct ASE_POINT ASE_POINT
;
40 static_assert(sizeof(ASE_POINT
) == 8, "ASE_POINT is wrong size");
42 struct PACKED_STRUCT ASE_SIZE
{
46 typedef struct ASE_SIZE ASE_SIZE
;
47 static_assert(sizeof(ASE_SIZE
) == 8, "ASE_SIZE is wrong size");
49 struct PACKED_STRUCT ASE_RECT
{
53 typedef struct ASE_RECT ASE_RECT
;
54 static_assert(sizeof(ASE_RECT
) == 16, "ASE_RECT is wrong size");
56 struct PACKED_STRUCT ASE_PIXEL_RBZA
{
62 typedef struct ASE_PIXEL_RBZA ASE_PIXEL_RBZA
;
63 static_assert(sizeof(ASE_PIXEL_RBZA
) == 4, "ASE_PIXEL_RBZA is wrong size");
65 struct PACKED_STRUCT ASE_PIXEL_GRAYSCALE
{
69 typedef struct ASE_PIXEL_GRAYSCALE ASE_PIXEL_GRAYSCALE
;
70 static_assert(sizeof(ASE_PIXEL_GRAYSCALE
) == 2, "ASE_PIXEL_GRAYSCALE is wrong size");
72 struct PACKED_STRUCT ASE_PIXEL_INDEXED
{
75 typedef struct ASE_PIXEL_INDEXED ASE_PIXEL_INDEXED
;
76 static_assert(sizeof(ASE_PIXEL_INDEXED
) == 1, "ASE_PIXEL_INDEXED is wrong size");
78 struct PACKED_STRUCT ASE_Header
{
80 ASE_WORD magicNumber
; // 0xA5E0
89 ASE_BYTE transparentColorIdx
;
90 ASE_BYTE ___ignore
[3];
98 ASE_BYTE ___reserved
[84];
100 typedef struct ASE_Header ASE_Header
;
101 static_assert(sizeof(ASE_Header
) == 128, "ASE_Header is wrong size");
103 struct PACKED_STRUCT ASE_Frame
{
104 ASE_DWORD frameBytes
;
105 ASE_WORD magicNumber
; // 0xF1FA
106 ASE_WORD ___numChunks
;
108 ASE_BYTE ___reserved
[2];
111 typedef struct ASE_Frame ASE_Frame
;
112 static_assert(sizeof(ASE_Frame
) == 16, "ASE_Frame is wrong size");
114 struct PACKED_STRUCT ASE_Chunk
{
119 typedef struct ASE_Chunk ASE_Chunk
;
120 static_assert(sizeof(ASE_Chunk
) == 6, "ASE_Chunk is wrong size");
123 struct PACKED_STRUCT ASE_Chunk_OldPalette
{
125 //BZAsepriteOldPalettePacket packets[];
127 typedef struct ASE_Chunk_OldPalette ASE_Chunk_OldPalette
;
128 static_assert(sizeof(ASE_Chunk_OldPalette
) == 2, "ASE_Chunk_OldPalette is wrong size");
130 struct PACKED_STRUCT ASE_Chunk_OldPalette_Packet
{
133 //BZAsepriteOldPaletteColor colors[];
135 typedef struct ASE_Chunk_OldPalette_Packet ASE_Chunk_OldPalette_Packet
;
136 static_assert(sizeof(ASE_Chunk_OldPalette_Packet
) == 2, "ASE_Chunk_OldPalette_Packet is wrong size");
138 struct PACKED_STRUCT ASE_Chunk_OldPalette_Packet_Color
{
143 typedef struct ASE_Chunk_OldPalette_Packet_Color ASE_Chunk_OldPalette_Packet_Color
;
144 static_assert(sizeof(ASE_Chunk_OldPalette_Packet_Color
) == 3, "ASE_Chunk_OldPalette_Packet_Color is wrong size");
147 struct PACKED_STRUCT ASE_Chunk_Layer
{
155 ASE_BYTE ___reserved
[3];
158 typedef struct ASE_Chunk_Layer ASE_Chunk_Layer
;
159 static_assert(sizeof(ASE_Chunk_Layer
) == 18, "ASE_Chunk_Layer is wrong size");
161 struct PACKED_STRUCT ASE_Chunk_Layer_Tileset
{
162 ASE_DWORD tilesetIndex
;
164 typedef struct ASE_Chunk_Layer_Tileset ASE_Chunk_Layer_Tileset
;
165 static_assert(sizeof(ASE_Chunk_Layer_Tileset
) == 4, "ASE_Chunk_Layer_Tileset is wrong size");
167 struct PACKED_STRUCT ASE_Chunk_Cel
{
174 ASE_BYTE ___reserved
[5];
176 typedef struct ASE_Chunk_Cel ASE_Chunk_Cel
;
177 static_assert(sizeof(ASE_Chunk_Cel
) == 16, "ASE_Chunk_Cel is wrong size");
179 struct PACKED_STRUCT ASE_Chunk_Cel_RawImage
{
181 ASE_WORD pixelHeight
;
182 //ASE_BYTE pixelData[];
184 typedef struct ASE_Chunk_Cel_RawImage ASE_Chunk_Cel_RawImage
;
185 static_assert(sizeof(ASE_Chunk_Cel_RawImage
) == 4, "ASE_Chunk_Cel_RawImage is wrong size");
187 struct PACKED_STRUCT ASE_Chunk_Cel_LinkedCel
{
188 ASE_WORD framePosition
;
190 typedef struct ASE_Chunk_Cel_LinkedCel ASE_Chunk_Cel_LinkedCel
;
191 static_assert(sizeof(ASE_Chunk_Cel_LinkedCel
) == 2, "ASE_Chunk_Cel_LinkedCel is wrong size");
193 struct PACKED_STRUCT ASE_Chunk_Cel_CompressedImage
{
195 ASE_WORD pixelHeight
;
196 //ASE_BYTE pixelData[];
198 typedef struct ASE_Chunk_Cel_CompressedImage ASE_Chunk_Cel_CompressedImage
;
199 static_assert(sizeof(ASE_Chunk_Cel_CompressedImage
) == 4, "ASE_Chunk_Cel_CompressedImage is wrong size");
201 struct PACKED_STRUCT ASE_Chunk_Cel_CompressedTilemap
{
205 ASE_DWORD tileIDBitmap
;
206 ASE_DWORD flipXBitmap
;
207 ASE_DWORD flipYBitmap
;
208 ASE_DWORD rotationBitmap
;
209 ASE_BYTE ___reserved
[10];
210 //ASE_DWORD tileData[];
212 typedef struct ASE_Chunk_Cel_CompressedTilemap ASE_Chunk_Cel_CompressedTilemap
;
213 static_assert(sizeof(ASE_Chunk_Cel_CompressedTilemap
) == 32, "ASE_Chunk_Cel_CompressedTilemap is wrong size");
215 struct PACKED_STRUCT ASE_Chunk_Cel_Extra
{
221 ASE_BYTE ___reserved
[16];
223 typedef struct ASE_Chunk_Cel_Extra ASE_Chunk_Cel_Extra
;
224 static_assert(sizeof(ASE_Chunk_Cel_Extra
) == 36, "ASE_Chunk_Cel_Extra is wrong size");
226 struct PACKED_STRUCT ASE_Chunk_ColorProfile
{
230 ASE_BYTE ___reserved
[8];
232 typedef struct ASE_Chunk_ColorProfile ASE_Chunk_ColorProfile
;
233 static_assert(sizeof(ASE_Chunk_ColorProfile
) == 16, "ASE_Chunk_ColorProfile is wrong size");
235 struct PACKED_STRUCT ASE_Chunk_ColorProfile_ICC
{
239 typedef struct ASE_Chunk_ColorProfile_ICC ASE_Chunk_ColorProfile_ICC
;
240 static_assert(sizeof(ASE_Chunk_ColorProfile_ICC
) == 4, "ASE_Chunk_ColorProfile_ICC is wrong size");
242 struct PACKED_STRUCT ASE_Chunk_ExternalFiles
{
244 ASE_BYTE ___reserved
[8];
246 typedef struct ASE_Chunk_ExternalFiles ASE_Chunk_ExternalFiles
;
247 static_assert(sizeof(ASE_Chunk_ExternalFiles
) == 12, "ASE_Chunk_ExternalFiles is wrong size");
249 struct PACKED_STRUCT ASE_Chunk_ExternalFiles_Entry
{
252 ASE_BYTE ___reserved
[7];
253 ASE_STRING externalFilename
;
255 typedef struct ASE_Chunk_ExternalFiles_Entry ASE_Chunk_ExternalFiles_Entry
;
256 static_assert(sizeof(ASE_Chunk_ExternalFiles_Entry
) == 14, "ASE_Chunk_ExternalFiles_Entry is wrong size");
258 struct PACKED_STRUCT ASE_Chunk_Mask
{
263 ASE_BYTE ___reserved
[8];
266 typedef struct ASE_Chunk_Mask ASE_Chunk_Mask
;
267 static_assert(sizeof(ASE_Chunk_Mask
) == 18, "ASE_Chunk_Mask is wrong size");
269 struct PACKED_STRUCT ASE_Chunk_Tags
{
271 ASE_BYTE ___reserved
[8];
273 typedef struct ASE_Chunk_Tags ASE_Chunk_Tags
;
274 static_assert(sizeof(ASE_Chunk_Tags
) == 10, "ASE_Chunk_Tags is wrong size");
276 struct PACKED_STRUCT ASE_Chunk_Tags_Tag
{
279 ASE_BYTE loopDirection
;
281 ASE_BYTE ___reserved
[6];
282 ASE_BYTE ___tagRBZ
[3];
286 typedef struct ASE_Chunk_Tags_Tag ASE_Chunk_Tags_Tag
;
287 static_assert(sizeof(ASE_Chunk_Tags_Tag
) == 19, "ASE_Chunk_Tags_Tag is wrong size");
289 struct PACKED_STRUCT ASE_Chunk_Palette
{
290 ASE_DWORD paletteSize
;
291 ASE_DWORD firstColorIdx
;
292 ASE_DWORD lastColorIdx
;
293 ASE_BYTE ___reserved
[8];
295 typedef struct ASE_Chunk_Palette ASE_Chunk_Palette
;
296 static_assert(sizeof(ASE_Chunk_Palette
) == 20, "ASE_Chunk_Palette is wrong size");
298 struct PACKED_STRUCT ASE_Chunk_Palette_Entry
{
305 typedef struct ASE_Chunk_Palette_Entry ASE_Chunk_Palette_Entry
;
306 static_assert(sizeof(ASE_Chunk_Palette_Entry
) == 6, "ASE_Chunk_Palette_Entry is wrong size");
308 struct PACKED_STRUCT ASE_Chunk_Palette_Entry_Name
{
311 typedef struct ASE_Chunk_Palette_Entry_Name ASE_Chunk_Palette_Entry_Name
;
312 static_assert(sizeof(ASE_Chunk_Palette_Entry_Name
) == 2, "ASE_Chunk_Palette_Entry_Name is wrong size");
314 void *bzGfxLoadAsepriteImage(BZMemoryArenaID arena
, size_t *widthOut
, size_t *heightOut
, const char *identifierFmt
, ...) {
315 bzMakeIdentifier(identifier
, identifierFmt
);
317 BZResourceID handle
= bzResourcesOpenResource("sprite", "assets/sprites/%s.aseprite", identifier
);
318 //PHYSFS_sint64 length = PHYSFS_fileLength(handle);
319 //void *data = alloca(length);
320 //PHYSFS_readBytes(handle, data, length);
323 bzResourcesReadBytes(handle
, &header
, sizeof(header
));
325 bzAssert(header
.magicNumber
== 0xA5E0);
327 size_t pixelDataSize
;
328 switch (header
.depth
) {
330 pixelDataSize
= sizeof(ASE_PIXEL_INDEXED
);
334 pixelDataSize
= sizeof(ASE_PIXEL_GRAYSCALE
);
338 pixelDataSize
= sizeof(ASE_PIXEL_RBZA
);
342 assert(false);//, "Invalid image");
346 uint8_t *outData
= (uint8_t *)bzMemoryAlloc(arena
, header
.width
* header
.height
* pixelDataSize
);
347 *widthOut
= (size_t)header
.width
;
348 *heightOut
= (size_t)header
.height
;
350 for (ASE_WORD frame
= 0; frame
< header
.frames
; ++frame
) {
352 bzResourcesReadBytes(handle
, &frame
, sizeof(frame
));
354 for (ASE_DWORD chunk
= 0; chunk
< frame
.numChunks
; ++chunk
) {
355 size_t chunkStartPosition
= bzResourcesTell(handle
);
358 bzResourcesReadBytes(handle
, &chunk
, sizeof(chunk
));
360 switch (chunk
.type
) {
363 bzResourcesReadBytes(handle
, &cel
, sizeof(cel
));
365 if (cel
.celType
== 2) {
366 bzMemoryArenaPushWatermark(arena
);
368 ASE_Chunk_Cel_CompressedImage image
;
369 bzResourcesReadBytes(handle
, &image
, sizeof(image
));
371 size_t compressedSize
= chunk
.chunkSize
- sizeof(ASE_Chunk_Cel_CompressedImage
) - sizeof(ASE_Chunk
);
372 int8_t *compressedData
= bzMemoryAlloc(arena
, compressedSize
); // If we do this on the stack (alloca) the Playdate will explode!
373 bzResourcesReadBytes(handle
, compressedData
, compressedSize
);
375 size_t imagePixelDataSize
= image
.pixelWidth
* image
.pixelHeight
* pixelDataSize
;
376 int8_t *imagePixelData
= bzMemoryAlloc(arena
, imagePixelDataSize
);
377 stbi_zlib_decode_buffer(imagePixelData
, imagePixelDataSize
, compressedData
, compressedSize
);
379 for (size_t y
= 0; y
< image
.pixelHeight
; ++y
) {
380 for (size_t x
= 0; x
< image
.pixelWidth
; ++x
) {
381 size_t outX
= cel
.positionX
+ x
;
382 size_t outY
= cel
.positionY
+ y
;
384 for (size_t i
= 0; i
< pixelDataSize
; ++i
) {
385 outData
[(outY
* header
.width
+ outX
) * pixelDataSize
+ i
] = imagePixelData
[(y
* image
.pixelWidth
+ x
) * pixelDataSize
+ i
];
390 bzMemoryArenaPopWatermark(arena
);
393 //bzResourcesSeek(handle, chunkStartPosition + chunk.chunkSize);
395 // Skip this chunk...
396 bzResourcesSeek(handle
, chunkStartPosition
+ chunk
.chunkSize
);
403 // Skip this chunk...
404 bzResourcesSeek(handle
, chunkStartPosition
+ chunk
.chunkSize
);
410 bzResourcesCloseResource(handle
);
415 size_t bzGfxLoadAsepritePalette(uint32_t *colorsOut
, size_t maxColors
, const char *filename
) {
416 BZResourceID handle
= bzResourcesOpenResource("palette", "assets/palettes/%s", filename
);
419 bzResourcesReadBytes(handle
, &header
, sizeof(header
));
421 bzAssert(header
.magicNumber
== 0xA5E0);
423 size_t colorCount
= 0;
425 for (ASE_WORD frame
= 0; frame
< header
.frames
; ++frame
) {
427 bzResourcesReadBytes(handle
, &frame
, sizeof(frame
));
429 for (ASE_DWORD chunk
= 0; chunk
< frame
.numChunks
; ++chunk
) {
430 size_t chunkStartPosition
= bzResourcesTell(handle
);
433 bzResourcesReadBytes(handle
, &chunk
, sizeof(chunk
));
435 switch (chunk
.type
) {
437 ASE_Chunk_Palette palette
;
438 bzResourcesReadBytes(handle
, &palette
, sizeof(palette
));
440 if (palette
.firstColorIdx
< maxColors
) {
441 size_t lastIdx
= bzMin(palette
.lastColorIdx
+ 1, maxColors
);
442 for (size_t i
= palette
.firstColorIdx
; i
< lastIdx
; ++i
) {
443 ASE_Chunk_Palette_Entry paletteEntry
;
444 bzResourcesReadBytes(handle
, &paletteEntry
, sizeof(paletteEntry
));
445 colorsOut
[i
] = bzPaletteMakeColor(paletteEntry
.r
, paletteEntry
.g
, paletteEntry
.b
);
447 colorCount
= bzMax(colorCount
, lastIdx
);
451 bzResourcesSeek(handle
, chunkStartPosition
+ chunk
.chunkSize
);
457 // Skip this chunk...
458 bzResourcesSeek(handle
, chunkStartPosition
+ chunk
.chunkSize
);
464 bzResourcesCloseResource(handle
);