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);