1 #include <bz/gfx/aseprite_internal.h>
3 #include <bz/debug/assert.h>
4 #include <bz/debug/log.h>
5 #include <bz/math/math.h>
6 #include <bz/memory/allocator.h>
7 #include <bz/renderer/palette_internal.h>
8 #include <bz/resources/resource.h>
9 #include <bz/types/identifier_internal.h>
10 #include <stdio.h> // Apparently stb_image.h needs this??
11 #include <stb_image.h>
12 #include <string.h> // memset
14 #include <assert.h> // Static assertions
16 #define PACKED_STRUCT __attribute__((__packed__))
18 typedef uint8_t ASE_BYTE
;
19 typedef uint16_t ASE_WORD
;
20 typedef int16_t ASE_SHORT
;
21 typedef uint32_t ASE_DWORD
;
22 typedef uint32_t ASE_LONG
;
23 typedef uint32_t ASE_FIXED
;
24 typedef float ASE_FLOAT
;
25 typedef double ASE_DOUBLE
;
26 typedef uint64_t ASE_QWORD
;
27 typedef int64_t ASE_LONG64
;
29 struct PACKED_STRUCT ASE_STRING
{
31 //ASE_BYTE characters[];
33 typedef struct ASE_STRING ASE_STRING
;
34 static_assert(sizeof(ASE_STRING
) == 2, "ASE_STRING is wrong size");
36 struct PACKED_STRUCT ASE_POINT
{
40 typedef struct ASE_POINT ASE_POINT
;
41 static_assert(sizeof(ASE_POINT
) == 8, "ASE_POINT is wrong size");
43 struct PACKED_STRUCT ASE_SIZE
{
47 typedef struct ASE_SIZE ASE_SIZE
;
48 static_assert(sizeof(ASE_SIZE
) == 8, "ASE_SIZE is wrong size");
50 struct PACKED_STRUCT ASE_RECT
{
54 typedef struct ASE_RECT ASE_RECT
;
55 static_assert(sizeof(ASE_RECT
) == 16, "ASE_RECT is wrong size");
57 struct PACKED_STRUCT ASE_PIXEL_RBGA
{
63 typedef struct ASE_PIXEL_RBGA ASE_PIXEL_RBGA
;
64 static_assert(sizeof(ASE_PIXEL_RBGA
) == 4, "ASE_PIXEL_RBGA is wrong size");
66 struct PACKED_STRUCT ASE_PIXEL_GRAYSCALE
{
70 typedef struct ASE_PIXEL_GRAYSCALE ASE_PIXEL_GRAYSCALE
;
71 static_assert(sizeof(ASE_PIXEL_GRAYSCALE
) == 2, "ASE_PIXEL_GRAYSCALE is wrong size");
73 struct PACKED_STRUCT ASE_PIXEL_INDEXED
{
76 typedef struct ASE_PIXEL_INDEXED ASE_PIXEL_INDEXED
;
77 static_assert(sizeof(ASE_PIXEL_INDEXED
) == 1, "ASE_PIXEL_INDEXED is wrong size");
79 struct PACKED_STRUCT ASE_Header
{
81 ASE_WORD magicNumber
; // 0xA5E0
90 ASE_BYTE transparentColorIdx
;
91 ASE_BYTE ___ignore
[3];
99 ASE_BYTE ___reserved
[84];
101 typedef struct ASE_Header ASE_Header
;
102 static_assert(sizeof(ASE_Header
) == 128, "ASE_Header is wrong size");
104 struct PACKED_STRUCT ASE_Frame
{
105 ASE_DWORD frameBytes
;
106 ASE_WORD magicNumber
; // 0xF1FA
107 ASE_WORD ___numChunks
;
109 ASE_BYTE ___reserved
[2];
112 typedef struct ASE_Frame ASE_Frame
;
113 static_assert(sizeof(ASE_Frame
) == 16, "ASE_Frame is wrong size");
115 struct PACKED_STRUCT ASE_Chunk
{
120 typedef struct ASE_Chunk ASE_Chunk
;
121 static_assert(sizeof(ASE_Chunk
) == 6, "ASE_Chunk is wrong size");
123 enum ASE_ChunkTypes
{
124 ASE_ChunkType_LayerChunk
= 0x2004,
125 ASE_ChunkType_CelChunk
= 0x2005,
126 ASE_ChunkType_CelExtraChunk
= 0x2006,
127 ASE_ChunkType_ColorProfileChunk
= 0x2007,
128 ASE_ChunkType_ExternalFilesChunk
= 0x2008,
129 ASE_ChunkType_TagsChunk
= 0x2018,
130 ASE_ChunkType_PaletteChunk
= 0x2019,
131 ASE_ChunkType_UserDataChunk
= 0x2020,
132 ASE_ChunkType_SliceChunk
= 0x2022,
133 ASE_ChunkType_TilesetChunk
= 0x2023,
135 // Ignore these, deprecated or unused...
136 ASE_ChunkType_OldPaletteChunk1
= 0x0004,
137 ASE_ChunkType_OldPaletteChunk2
= 0x0011,
138 ASE_ChunkType_MaskChunk
= 0x2016,
139 ASE_ChunkType_PathChunk
= 0x2017,
143 struct PACKED_STRUCT ASE_Chunk_OldPalette
{
145 //BZAsepriteOldPalettePacket packets[];
147 typedef struct ASE_Chunk_OldPalette ASE_Chunk_OldPalette
;
148 static_assert(sizeof(ASE_Chunk_OldPalette
) == 2, "ASE_Chunk_OldPalette is wrong size");
150 struct PACKED_STRUCT ASE_Chunk_OldPalette_Packet
{
153 //BZAsepriteOldPaletteColor colors[];
155 typedef struct ASE_Chunk_OldPalette_Packet ASE_Chunk_OldPalette_Packet
;
156 static_assert(sizeof(ASE_Chunk_OldPalette_Packet
) == 2, "ASE_Chunk_OldPalette_Packet is wrong size");
158 struct PACKED_STRUCT ASE_Chunk_OldPalette_Packet_Color
{
163 typedef struct ASE_Chunk_OldPalette_Packet_Color ASE_Chunk_OldPalette_Packet_Color
;
164 static_assert(sizeof(ASE_Chunk_OldPalette_Packet_Color
) == 3, "ASE_Chunk_OldPalette_Packet_Color is wrong size");
167 struct PACKED_STRUCT ASE_Chunk_Layer
{
175 ASE_BYTE ___reserved
[3];
178 typedef struct ASE_Chunk_Layer ASE_Chunk_Layer
;
179 static_assert(sizeof(ASE_Chunk_Layer
) == 18, "ASE_Chunk_Layer is wrong size");
181 enum ASE_Chunk_Layer_BlendModes
{
182 ASE_Chunk_Layer_BlendMode_Normal
= 0, // Should always be this
185 struct PACKED_STRUCT ASE_Chunk_Layer_Tileset
{
186 ASE_DWORD tilesetIndex
;
188 typedef struct ASE_Chunk_Layer_Tileset ASE_Chunk_Layer_Tileset
;
189 static_assert(sizeof(ASE_Chunk_Layer_Tileset
) == 4, "ASE_Chunk_Layer_Tileset is wrong size");
191 struct PACKED_STRUCT ASE_Chunk_Cel
{
198 ASE_BYTE ___reserved
[5];
200 typedef struct ASE_Chunk_Cel ASE_Chunk_Cel
;
201 static_assert(sizeof(ASE_Chunk_Cel
) == 16, "ASE_Chunk_Cel is wrong size");
203 enum ASE_Chunk_Cel_CelTypes
{
204 ASE_Chunk_Cel_CelType_RawImage
= 0,
205 ASE_Chunk_Cel_CelType_LinkedCel
= 1,
206 ASE_Chunk_Cel_CelType_CompressedImage
= 2,
207 ASE_Chunk_Cel_CelType_CompressedTilemap
= 3,
210 struct PACKED_STRUCT ASE_Chunk_Cel_RawImage
{
212 ASE_WORD pixelHeight
;
213 //ASE_BYTE pixelData[];
215 typedef struct ASE_Chunk_Cel_RawImage ASE_Chunk_Cel_RawImage
;
216 static_assert(sizeof(ASE_Chunk_Cel_RawImage
) == 4, "ASE_Chunk_Cel_RawImage is wrong size");
218 struct PACKED_STRUCT ASE_Chunk_Cel_LinkedCel
{
219 ASE_WORD framePosition
;
221 typedef struct ASE_Chunk_Cel_LinkedCel ASE_Chunk_Cel_LinkedCel
;
222 static_assert(sizeof(ASE_Chunk_Cel_LinkedCel
) == 2, "ASE_Chunk_Cel_LinkedCel is wrong size");
224 struct PACKED_STRUCT ASE_Chunk_Cel_CompressedImage
{
226 ASE_WORD pixelHeight
;
227 //ASE_BYTE pixelData[];
229 typedef struct ASE_Chunk_Cel_CompressedImage ASE_Chunk_Cel_CompressedImage
;
230 static_assert(sizeof(ASE_Chunk_Cel_CompressedImage
) == 4, "ASE_Chunk_Cel_CompressedImage is wrong size");
232 struct PACKED_STRUCT ASE_Chunk_Cel_CompressedTilemap
{
236 ASE_DWORD tileIDBitmap
;
237 ASE_DWORD flipXBitmap
;
238 ASE_DWORD flipYBitmap
;
239 ASE_DWORD rotationBitmap
;
240 ASE_BYTE ___reserved
[10];
241 //ASE_DWORD tileData[];
243 typedef struct ASE_Chunk_Cel_CompressedTilemap ASE_Chunk_Cel_CompressedTilemap
;
244 static_assert(sizeof(ASE_Chunk_Cel_CompressedTilemap
) == 32, "ASE_Chunk_Cel_CompressedTilemap is wrong size");
246 struct PACKED_STRUCT ASE_Chunk_Cel_Extra
{
252 ASE_BYTE ___reserved
[16];
254 typedef struct ASE_Chunk_Cel_Extra ASE_Chunk_Cel_Extra
;
255 static_assert(sizeof(ASE_Chunk_Cel_Extra
) == 36, "ASE_Chunk_Cel_Extra is wrong size");
257 struct PACKED_STRUCT ASE_Chunk_ColorProfile
{
261 ASE_BYTE ___reserved
[8];
263 typedef struct ASE_Chunk_ColorProfile ASE_Chunk_ColorProfile
;
264 static_assert(sizeof(ASE_Chunk_ColorProfile
) == 16, "ASE_Chunk_ColorProfile is wrong size");
266 struct PACKED_STRUCT ASE_Chunk_ColorProfile_ICC
{
270 typedef struct ASE_Chunk_ColorProfile_ICC ASE_Chunk_ColorProfile_ICC
;
271 static_assert(sizeof(ASE_Chunk_ColorProfile_ICC
) == 4, "ASE_Chunk_ColorProfile_ICC is wrong size");
273 struct PACKED_STRUCT ASE_Chunk_ExternalFiles
{
275 ASE_BYTE ___reserved
[8];
277 typedef struct ASE_Chunk_ExternalFiles ASE_Chunk_ExternalFiles
;
278 static_assert(sizeof(ASE_Chunk_ExternalFiles
) == 12, "ASE_Chunk_ExternalFiles is wrong size");
280 struct PACKED_STRUCT ASE_Chunk_ExternalFiles_Entry
{
283 ASE_BYTE ___reserved
[7];
284 ASE_STRING externalFilename
;
286 typedef struct ASE_Chunk_ExternalFiles_Entry ASE_Chunk_ExternalFiles_Entry
;
287 static_assert(sizeof(ASE_Chunk_ExternalFiles_Entry
) == 14, "ASE_Chunk_ExternalFiles_Entry is wrong size");
289 enum ASE_Chunk_ExternalFiles_Entry_Types
{
290 ASE_Chunk_ExternalFiles_EntryType_ExternalPalette
= 0,
291 ASE_Chunk_ExternalFiles_EntryType_ExternalTileset
= 1,
292 ASE_Chunk_ExternalFiles_EntryType_PropertiesExtension
= 2,
293 ASE_Chunk_ExternalFiles_EntryType_TileManagement
= 3,
296 struct PACKED_STRUCT ASE_Chunk_Mask
{
301 ASE_BYTE ___reserved
[8];
304 typedef struct ASE_Chunk_Mask ASE_Chunk_Mask
;
305 static_assert(sizeof(ASE_Chunk_Mask
) == 18, "ASE_Chunk_Mask is wrong size");
307 struct PACKED_STRUCT ASE_Chunk_Tags
{
309 ASE_BYTE ___reserved
[8];
311 typedef struct ASE_Chunk_Tags ASE_Chunk_Tags
;
312 static_assert(sizeof(ASE_Chunk_Tags
) == 10, "ASE_Chunk_Tags is wrong size");
314 struct PACKED_STRUCT ASE_Chunk_Tags_Tag
{
317 ASE_BYTE loopDirection
;
319 ASE_BYTE ___reserved
[6];
320 ASE_BYTE ___tagRBZ
[3];
324 typedef struct ASE_Chunk_Tags_Tag ASE_Chunk_Tags_Tag
;
325 static_assert(sizeof(ASE_Chunk_Tags_Tag
) == 19, "ASE_Chunk_Tags_Tag is wrong size");
327 struct PACKED_STRUCT ASE_Chunk_Palette
{
328 ASE_DWORD paletteSize
;
329 ASE_DWORD firstColorIdx
;
330 ASE_DWORD lastColorIdx
;
331 ASE_BYTE ___reserved
[8];
333 typedef struct ASE_Chunk_Palette ASE_Chunk_Palette
;
334 static_assert(sizeof(ASE_Chunk_Palette
) == 20, "ASE_Chunk_Palette is wrong size");
336 struct PACKED_STRUCT ASE_Chunk_Palette_Entry
{
343 typedef struct ASE_Chunk_Palette_Entry ASE_Chunk_Palette_Entry
;
344 static_assert(sizeof(ASE_Chunk_Palette_Entry
) == 6, "ASE_Chunk_Palette_Entry is wrong size");
346 struct PACKED_STRUCT ASE_Chunk_Palette_Entry_Name
{
349 typedef struct ASE_Chunk_Palette_Entry_Name ASE_Chunk_Palette_Entry_Name
;
350 static_assert(sizeof(ASE_Chunk_Palette_Entry_Name
) == 2, "ASE_Chunk_Palette_Entry_Name is wrong size");
352 static bool readASEHeader(ASE_Header
*headerOut
, BZResourceID handle
) {
353 bzAssert(headerOut
!= NULL
);
354 bzResourcesReadBytes(handle
, headerOut
, sizeof(ASE_Header
));
355 bzAssert(headerOut
->magicNumber
== 0xA5E0);
359 static bool readASEFrame(ASE_Frame
*frameOut
, ASE_DWORD
*numChunksOut
, BZResourceID handle
) {
360 bzAssert(frameOut
!= NULL
);
361 bzAssert(numChunksOut
!= NULL
);
363 bzResourcesReadBytes(handle
, frameOut
, sizeof(ASE_Frame
));
365 ASE_DWORD numChunks
= frameOut
->___numChunks
;
367 if (numChunks
== 0xFFFF) {
368 numChunks
= frameOut
->numChunks
;
369 if (numChunks
== 0) {
370 numChunks
= frameOut
->___numChunks
; // See docs.
374 *numChunksOut
= numChunks
;
379 static void renderChunkCel(uint8_t *outData
, ASE_SHORT
*zBuffer
, BZMemoryArenaID arena
, BZResourceID handle
, ASE_WORD layerIndex
, const ASE_Header
*header
, size_t pixelDataSize
, size_t frameIdx
, size_t frameStartPositions
[]) {
380 bzResourcesSeek(handle
, frameStartPositions
[frameIdx
]);
384 readASEFrame(&frame
, &numChunks
, handle
);
386 for (ASE_DWORD chunkIdx
= 0; chunkIdx
< numChunks
; ++chunkIdx
) {
387 size_t chunkStartPosition
= bzResourcesTell(handle
);
390 bzResourcesReadBytes(handle
, &chunk
, sizeof(chunk
));
392 if (chunk
.type
== ASE_ChunkType_CelChunk
) {
394 bzResourcesReadBytes(handle
, &cel
, sizeof(cel
));
396 if (cel
.layerIndex
== layerIndex
) {
397 if (cel
.celType
== ASE_Chunk_Cel_CelType_LinkedCel
) {
398 ASE_Chunk_Cel_LinkedCel linkedCel
;
399 bzResourcesReadBytes(handle
, &linkedCel
, sizeof(linkedCel
));
400 renderChunkCel(outData
, zBuffer
, arena
, handle
, layerIndex
, header
, pixelDataSize
, linkedCel
.framePosition
, frameStartPositions
);
401 } else if (cel
.celType
== ASE_Chunk_Cel_CelType_CompressedImage
) {
402 bzMemoryArenaPushWatermark(arena
);
404 ASE_Chunk_Cel_CompressedImage image
;
405 bzResourcesReadBytes(handle
, &image
, sizeof(image
));
407 size_t compressedSize
= chunk
.chunkSize
- sizeof(ASE_Chunk_Cel_CompressedImage
) - sizeof(ASE_Chunk_Cel
) - sizeof(ASE_Chunk
);
408 int8_t *compressedData
= bzMemoryAlloc(arena
, compressedSize
); // If we do this on the stack (alloca) the Playdate will explode!
409 bzResourcesReadBytes(handle
, compressedData
, compressedSize
);
411 size_t imagePixelDataSize
= image
.pixelWidth
* image
.pixelHeight
* pixelDataSize
;
412 int8_t *imagePixelData
= bzMemoryAlloc(arena
, imagePixelDataSize
);
413 stbi_zlib_decode_buffer(imagePixelData
, imagePixelDataSize
, compressedData
, compressedSize
);
415 for (size_t y
= 0; y
< image
.pixelHeight
; ++y
) {
416 for (size_t x
= 0; x
< image
.pixelWidth
; ++x
) {
417 size_t outX
= cel
.positionX
+ x
;
418 size_t outY
= cel
.positionY
+ y
;
420 //ASE_SHORT *currentZ = &zBuffer[outY * header->width + outX];
421 //if (*currentZ > layerIndex) {
422 for (size_t i
= 0; i
< pixelDataSize
; ++i
) {
423 uint8_t pixelData
= imagePixelData
[(y
* image
.pixelWidth
+ x
) * pixelDataSize
+ i
];
424 if (pixelData
> 0) { // FIXME, alpha...
425 outData
[outY
* header
->width
+ outX
* pixelDataSize
+ i
] = pixelData
;
428 //*currentZ = layerIndex;//cel.zIndex;
433 bzMemoryArenaPopWatermark(arena
);
436 // Found what we needed to render...
441 bzResourcesSeek(handle
, chunkStartPosition
+ chunk
.chunkSize
);
445 static bool renderCelsForLayer(uint8_t *outData
, ASE_SHORT
*zBuffer
, BZMemoryArenaID arena
, BZResourceID handle
, ASE_WORD layerIndex
, const ASE_Header
*header
, size_t pixelDataSize
) {
446 size_t framesStartPosition
= bzResourcesTell(handle
);
448 // Layers are .. complicated, you only really need to read them for the first frame...
449 ASE_Frame firstFrame
;
450 ASE_DWORD firstFrameChunks
;
451 readASEFrame(&firstFrame
, &firstFrameChunks
, handle
);
453 bool layerExists
= false;
454 bool layerVisible
= false;
455 for (ASE_DWORD chunkIdx
= 0, layerCount
= 0; chunkIdx
< firstFrameChunks
; ++chunkIdx
) {
456 size_t chunkStartPosition
= bzResourcesTell(handle
);
459 bzResourcesReadBytes(handle
, &chunk
, sizeof(chunk
));
461 if (chunk
.type
== ASE_ChunkType_LayerChunk
) {
462 ASE_Chunk_Layer layer
;
463 bzResourcesReadBytes(handle
, &layer
, sizeof(layer
));
465 if (layerCount
== layerIndex
) {
467 layerVisible
= (layer
.flags
& 1) > 0; // FIXME, named flag
473 // Skip this chunk...
474 bzResourcesSeek(handle
, chunkStartPosition
+ chunk
.chunkSize
);
478 if (layerExists
&& layerVisible
) {
479 bzResourcesSeek(handle
, framesStartPosition
);
481 size_t *frameStartPositions
= alloca(header
->frames
* sizeof(size_t)); // FIXME, alloca -> tmp
483 for (ASE_WORD frameIdx
= 0; frameIdx
< header
->frames
; ++frameIdx
) {
484 frameStartPositions
[frameIdx
] = bzResourcesTell(handle
);
488 readASEFrame(&frame
, &numChunks
, handle
);
490 for (ASE_DWORD chunkIdx
= 0; chunkIdx
< numChunks
; ++chunkIdx
) {
491 size_t chunkStartPosition
= bzResourcesTell(handle
);
494 bzResourcesReadBytes(handle
, &chunk
, sizeof(chunk
));
496 if (chunk
.type
== ASE_ChunkType_CelChunk
) {
497 uint8_t *frameOutData
= &outData
[frameIdx
* header
->height
* header
->width
* pixelDataSize
];
498 ASE_SHORT
*frameZBuffer
= NULL
;//&zBuffer[frameIdx * header->height * header->width * sizeof(ASE_SHORT)];
499 renderChunkCel(frameOutData
, frameZBuffer
, arena
, handle
, layerIndex
, header
, pixelDataSize
, frameIdx
, frameStartPositions
);
502 bzResourcesSeek(handle
, chunkStartPosition
+ chunk
.chunkSize
);
510 void *bzGfxLoadAsepriteImage(BZMemoryArenaID arena
, size_t *framesOut
, size_t *widthOut
, size_t *heightOut
, const char *identifierFmt
, ...) {
511 bzMakeIdentifier(identifier
, identifierFmt
);
513 BZResourceID handle
= bzResourcesOpenResource("sprite", "assets/sprites/%s.aseprite", identifier
);
516 readASEHeader(&header
, handle
);
518 size_t pixelDataSize
;
519 switch (header
.depth
) {
521 pixelDataSize
= sizeof(ASE_PIXEL_INDEXED
);
525 pixelDataSize
= sizeof(ASE_PIXEL_GRAYSCALE
);
529 pixelDataSize
= sizeof(ASE_PIXEL_RBGA
);
533 bzAssertMessage(false, "Invalid image");
537 uint8_t *outData
= (uint8_t *)bzMemoryAlloc(arena
, header
.frames
* header
.height
* header
.width
* pixelDataSize
); // Side by side loading needs to happen...
538 *framesOut
= (size_t)header
.frames
;
539 *widthOut
= (size_t)header
.width
;
540 *heightOut
= (size_t)header
.height
;
542 //bzMemoryArenaPushWatermark(arena);
543 ASE_SHORT
*zBuffer
= NULL
;//(ASE_SHORT *)bzMemoryAlloc(arena, header.frames * header.height * header.width * sizeof(ASE_SHORT));
544 //memset(zBuffer, 0, header.frames * header.height * header.width * sizeof(ASE_SHORT)); // FIXME
546 size_t startPosition
= bzResourcesTell(handle
);
547 for (ASE_WORD layerIndex
= 0; ; ++layerIndex
) {
549 bzResourcesSeek(handle
, startPosition
);
551 bool rendered
= renderCelsForLayer(outData
, zBuffer
, arena
, handle
, layerIndex
, &header
, pixelDataSize
);
552 if (rendered
== false) {
557 //bzMemoryArenaPopWatermark(arena);
562 size_t bzGfxLoadAsepritePalette(uint32_t *colorsOut
, size_t maxColors
, const char *filename
) {
563 BZResourceID handle
= bzResourcesOpenResource("palette", "assets/palettes/%s.aseprite", filename
);
566 readASEHeader(&header
, handle
);
568 size_t colorCount
= 0;
570 for (ASE_WORD frame
= 0; frame
< header
.frames
; ++frame
) {
573 readASEFrame(&frame
, &numChunks
, handle
);
575 for (ASE_DWORD chunk
= 0; chunk
< numChunks
; ++chunk
) {
576 size_t chunkStartPosition
= bzResourcesTell(handle
);
579 bzResourcesReadBytes(handle
, &chunk
, sizeof(chunk
));
581 switch (chunk
.type
) {
582 case ASE_ChunkType_PaletteChunk
: {
583 ASE_Chunk_Palette palette
;
584 bzResourcesReadBytes(handle
, &palette
, sizeof(palette
));
586 if (palette
.firstColorIdx
< maxColors
) {
587 size_t lastIdx
= bzMin(palette
.lastColorIdx
+ 1, maxColors
);
588 for (size_t i
= palette
.firstColorIdx
; i
< lastIdx
; ++i
) {
589 ASE_Chunk_Palette_Entry paletteEntry
;
590 bzResourcesReadBytes(handle
, &paletteEntry
, sizeof(paletteEntry
));
591 colorsOut
[i
] = bzPaletteMakeColor(paletteEntry
.r
, paletteEntry
.g
, paletteEntry
.b
);
593 colorCount
= bzMax(colorCount
, lastIdx
);
597 bzResourcesSeek(handle
, chunkStartPosition
+ chunk
.chunkSize
);
603 // Skip this chunk...
604 bzResourcesSeek(handle
, chunkStartPosition
+ chunk
.chunkSize
);
610 bzResourcesCloseResource(handle
);