]> git.bts.cx Git - benzene.git/blobdiff - src/bz/gfx/aseprite.c
Fixed Aseprite rendering system
[benzene.git] / src / bz / gfx / aseprite.c
index 046ca246488f378ba191537b92f8ed693c254d37..b2a829ff0bdbf442333ed4bd96186bf1b2f51058 100644 (file)
@@ -376,13 +376,141 @@ static bool readASEFrame(ASE_Frame *frameOut, ASE_DWORD *numChunksOut, BZResourc
        return true;
 }
 
+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[]) {
+       bzResourcesSeek(handle, frameStartPositions[frameIdx]);
+       
+       ASE_Frame frame;
+       ASE_DWORD numChunks;
+       readASEFrame(&frame, &numChunks, handle);
+
+       for (ASE_DWORD chunkIdx = 0; chunkIdx < numChunks; ++chunkIdx) {
+               size_t chunkStartPosition = bzResourcesTell(handle);
+
+               ASE_Chunk chunk;
+               bzResourcesReadBytes(handle, &chunk, sizeof(chunk));
+
+               if (chunk.type == ASE_ChunkType_CelChunk) {
+                       ASE_Chunk_Cel cel;
+                       bzResourcesReadBytes(handle, &cel, sizeof(cel));
+
+                       if (cel.layerIndex == layerIndex) {
+                               if (cel.celType == ASE_Chunk_Cel_CelType_LinkedCel) {
+                                       ASE_Chunk_Cel_LinkedCel linkedCel;
+                                       bzResourcesReadBytes(handle, &linkedCel, sizeof(linkedCel));
+                                       renderChunkCel(outData, zBuffer, arena, handle, layerIndex, header, pixelDataSize, linkedCel.framePosition, frameStartPositions);
+                               } else if (cel.celType == ASE_Chunk_Cel_CelType_CompressedImage) {
+                                       bzMemoryArenaPushWatermark(arena);
+
+                                       ASE_Chunk_Cel_CompressedImage image;
+                                       bzResourcesReadBytes(handle, &image, sizeof(image));
+
+                                       size_t compressedSize = chunk.chunkSize - sizeof(ASE_Chunk_Cel_CompressedImage) - sizeof(ASE_Chunk_Cel) - sizeof(ASE_Chunk);
+                                       int8_t *compressedData = bzMemoryAlloc(arena, compressedSize); // If we do this on the stack (alloca) the Playdate will explode!
+                                       bzResourcesReadBytes(handle, compressedData, compressedSize);
+
+                                       size_t imagePixelDataSize = image.pixelWidth * image.pixelHeight * pixelDataSize;
+                                       int8_t *imagePixelData = bzMemoryAlloc(arena, imagePixelDataSize);
+                                       stbi_zlib_decode_buffer(imagePixelData, imagePixelDataSize, compressedData, compressedSize);
+
+                                       for (size_t y = 0; y < image.pixelHeight; ++y) {
+                                               for (size_t x = 0; x < image.pixelWidth; ++x) {
+                                                       size_t outX = cel.positionX + x;
+                                                       size_t outY = cel.positionY + y;
+
+                                                       //ASE_SHORT *currentZ = &zBuffer[outY * header->width + outX];
+                                                       //if (*currentZ > layerIndex) {
+                                                               for (size_t i = 0; i < pixelDataSize; ++i) {
+                                                                       uint8_t pixelData = imagePixelData[(y * image.pixelWidth + x) * pixelDataSize + i];
+                                                                       if (pixelData > 0) { // FIXME, alpha...
+                                                                               outData[outY * header->width + outX * pixelDataSize + i] = pixelData;
+                                                                       }
+                                                               }
+                                                               //*currentZ = layerIndex;//cel.zIndex;
+                                                       //}
+                                               }
+                                       }
+
+                                       bzMemoryArenaPopWatermark(arena);
+                               }
+
+                               // Found what we needed to render...
+                               break;
+                       }
+               }
+
+               bzResourcesSeek(handle, chunkStartPosition + chunk.chunkSize);
+       }                               
+}
+
+static bool renderCelsForLayer(uint8_t *outData, ASE_SHORT *zBuffer, BZMemoryArenaID arena, BZResourceID handle, ASE_WORD layerIndex, const ASE_Header *header, size_t pixelDataSize) {
+       size_t framesStartPosition = bzResourcesTell(handle);
+
+       // Layers are .. complicated, you only really need to read them for the first frame...
+       ASE_Frame firstFrame;
+       ASE_DWORD firstFrameChunks;
+       readASEFrame(&firstFrame, &firstFrameChunks, handle);
+
+       bool layerExists = false;
+       bool layerVisible = false;
+       for (ASE_DWORD chunkIdx = 0, layerCount = 0; chunkIdx < firstFrameChunks; ++chunkIdx) {
+               size_t chunkStartPosition = bzResourcesTell(handle);
+
+               ASE_Chunk chunk;
+               bzResourcesReadBytes(handle, &chunk, sizeof(chunk));
+
+               if (chunk.type == ASE_ChunkType_LayerChunk) {
+                       ASE_Chunk_Layer layer;
+                       bzResourcesReadBytes(handle, &layer, sizeof(layer));
+
+                       if (layerCount == layerIndex) {
+                               layerExists = true;
+                               layerVisible = (layer.flags & 1) > 0; // FIXME, named flag
+                               break;
+                       } else {
+                               layerCount++;
+                       }
+               }// else {
+                       // Skip this chunk...
+                       bzResourcesSeek(handle, chunkStartPosition + chunk.chunkSize);
+               //}
+       }
+
+       if (layerExists && layerVisible) {
+               bzResourcesSeek(handle, framesStartPosition);
+
+               size_t *frameStartPositions = alloca(header->frames * sizeof(size_t)); // FIXME, alloca -> tmp
+
+               for (ASE_WORD frameIdx = 0; frameIdx < header->frames; ++frameIdx) {
+                       frameStartPositions[frameIdx] = bzResourcesTell(handle);
+
+                       ASE_Frame frame;
+                       ASE_DWORD numChunks;
+                       readASEFrame(&frame, &numChunks, handle);
+
+                       for (ASE_DWORD chunkIdx = 0; chunkIdx < numChunks; ++chunkIdx) {
+                               size_t chunkStartPosition = bzResourcesTell(handle);
+
+                               ASE_Chunk chunk;
+                               bzResourcesReadBytes(handle, &chunk, sizeof(chunk));
+
+                               if (chunk.type == ASE_ChunkType_CelChunk) {
+                                       uint8_t *frameOutData = &outData[frameIdx * header->height * header->width * pixelDataSize];
+                                       ASE_SHORT *frameZBuffer = NULL;//&zBuffer[frameIdx * header->height * header->width * sizeof(ASE_SHORT)];
+                                       renderChunkCel(frameOutData, frameZBuffer, arena, handle, layerIndex, header, pixelDataSize, frameIdx, frameStartPositions);
+                               }
+
+                               bzResourcesSeek(handle, chunkStartPosition + chunk.chunkSize);
+                       }
+               }
+       }
+
+       return layerExists;
+}
+
 void *bzGfxLoadAsepriteImage(BZMemoryArenaID arena, size_t *framesOut, size_t *widthOut, size_t *heightOut, const char *identifierFmt, ...) {
        bzMakeIdentifier(identifier, identifierFmt);
 
        BZResourceID handle = bzResourcesOpenResource("sprite", "assets/sprites/%s.aseprite", identifier);
-       //PHYSFS_sint64 length = PHYSFS_fileLength(handle);
-       //void *data = alloca(length);
-       //PHYSFS_readBytes(handle, data, length);
        
        ASE_Header header;
        readASEHeader(&header, handle);
@@ -402,121 +530,37 @@ void *bzGfxLoadAsepriteImage(BZMemoryArenaID arena, size_t *framesOut, size_t *w
                        break;
        
                default:
-                       assert(false);//, "Invalid image");
+                       bzAssertMessage(false, "Invalid image");
                        break;
        }
 
-       uint8_t *outData = (uint8_t *)bzMemoryAlloc(arena, header.frames * header.width * header.height * pixelDataSize); // Side by side loading needs to happen...
+       uint8_t *outData = (uint8_t *)bzMemoryAlloc(arena, header.frames * header.height * header.width * pixelDataSize); // Side by side loading needs to happen...
        *framesOut = (size_t)header.frames;
        *widthOut = (size_t)header.width;
        *heightOut = (size_t)header.height;
 
-       bzMemoryArenaPushWatermark(arena);
-       size_t zBufferSize = header.width * header.height * sizeof(ASE_SHORT);
-       ASE_SHORT *zBuffer = (ASE_SHORT *)bzMemoryAlloc(arena, zBufferSize);
+       //bzMemoryArenaPushWatermark(arena);
+       ASE_SHORT *zBuffer = NULL;//(ASE_SHORT *)bzMemoryAlloc(arena, header.frames * header.height * header.width * sizeof(ASE_SHORT));
+       //memset(zBuffer, 0, header.frames * header.height * header.width * sizeof(ASE_SHORT)); // FIXME
 
-       size_t frameImageSize = header.width * header.height * pixelDataSize;
-
-       for (ASE_WORD frameIdx = 0; frameIdx < header.frames; ++frameIdx) {
-               ASE_Frame frame;
-               ASE_DWORD numChunks = 0;
-               readASEFrame(&frame, &numChunks, handle);
-               bzLog("FRAME %d: %d chunks", frameIdx, numChunks);
+       size_t startPosition = bzResourcesTell(handle);
+       for (ASE_WORD layerIndex = 0; ; ++layerIndex) {
+               // Reset...
+               bzResourcesSeek(handle, startPosition);
 
-               memset(zBuffer, 0, zBufferSize);
-
-               bool layerVisible[16];
-               size_t nextLayer = 0;
-
-               size_t layerStartOffset[16];
-
-               for (ASE_DWORD chunk = 0; chunk < numChunks; ++chunk) {
-                       size_t chunkStartPosition = bzResourcesTell(handle);
-
-                       ASE_Chunk chunk;
-                       bzResourcesReadBytes(handle, &chunk, sizeof(chunk));
-
-                       switch (chunk.type) {
-                               case ASE_ChunkType_LayerChunk: {
-                                       bzLog("LAYER %d: %d chunks", frameIdx, numChunks);
-
-
-                                       ASE_Chunk_Layer layer;
-                                       bzResourcesReadBytes(handle, &layer, sizeof(layer));
-
-                                       layerVisible[nextLayer] = (layer.flags & 1) > 0;
-                                       ++nextLayer;
-
-                                       bzResourcesSeek(handle, chunkStartPosition + chunk.chunkSize);
-                                       break;
-                               }
-
-                               case ASE_ChunkType_CelChunk: {
-                                       bzLog("CELL %d: %d chunks", frameIdx, numChunks);
-                                       ASE_Chunk_Cel cel;
-                                       bzResourcesReadBytes(handle, &cel, sizeof(cel));
-
-/////                                  ASE_Chunk_Cel_CelType_LinkedCel aaaahhh
-
-                                       if (layerVisible[cel.layerIndex] && cel.celType == ASE_Chunk_Cel_CelType_CompressedImage) {
-                                               bzMemoryArenaPushWatermark(arena);
-
-                                               ASE_Chunk_Cel_CompressedImage image;
-                                               bzResourcesReadBytes(handle, &image, sizeof(image));
-
-                                               size_t compressedSize = chunk.chunkSize - sizeof(ASE_Chunk_Cel_CompressedImage) - sizeof(ASE_Chunk_Cel) - sizeof(ASE_Chunk);
-                                               int8_t *compressedData = bzMemoryAlloc(arena, compressedSize); // If we do this on the stack (alloca) the Playdate will explode!
-                                               bzResourcesReadBytes(handle, compressedData, compressedSize);
-
-                                               size_t imagePixelDataSize = image.pixelWidth * image.pixelHeight * pixelDataSize;
-                                               int8_t *imagePixelData = bzMemoryAlloc(arena, imagePixelDataSize);
-                                               stbi_zlib_decode_buffer(imagePixelData, imagePixelDataSize, compressedData, compressedSize);
-
-                                               for (size_t y = 0; y < image.pixelHeight; ++y) {
-                                                       for (size_t x = 0; x < image.pixelWidth; ++x) {
-                                                               size_t outX = cel.positionX + x;
-                                                               size_t outY = cel.positionY + y;
-
-                                                               ASE_SHORT *currentZ = &zBuffer[outY * header.width + outX];
-
-                                                               if (*currentZ <= cel.zIndex) {
-                                                                       for (size_t i = 0; i < pixelDataSize; ++i) {
-                                                                               uint8_t pixelData = imagePixelData[(y * image.pixelWidth + x) * pixelDataSize + i];
-                                                                               if (pixelData > 0) { // FIXME, alpha...
-                                                                                       outData[frameIdx * frameImageSize + (outY * header.width + outX) * pixelDataSize + i] = pixelData;
-                                                                               }
-                                                                       }
-                                                                       *currentZ = cel.zIndex;
-                                                               }
-                                                       }
-                                               }
-
-                                               bzMemoryArenaPopWatermark(arena);
-                                       } else {
-                                               // Skip this chunk...
-                                               bzResourcesSeek(handle, chunkStartPosition + chunk.chunkSize);
-                                       }
-
-                                       break;
-                               }
-                               
-                               default:
-                                       // Skip this chunk...
-                                       bzResourcesSeek(handle, chunkStartPosition + chunk.chunkSize);
-                                       break;
-                       }
+               bool rendered = renderCelsForLayer(outData, zBuffer, arena, handle, layerIndex, &header, pixelDataSize);
+               if (rendered == false) {
+                       break;
                }
        }
-       
-       bzMemoryArenaPopWatermark(arena);
 
-       bzResourcesCloseResource(handle);
+       //bzMemoryArenaPopWatermark(arena);
 
        return outData;
 }
 
 size_t bzGfxLoadAsepritePalette(uint32_t *colorsOut, size_t maxColors, const char *filename) {
-       BZResourceID handle = bzResourcesOpenResource("palette", "assets/palettes/%s", filename);
+       BZResourceID handle = bzResourcesOpenResource("palette", "assets/palettes/%s.aseprite", filename);
        
        ASE_Header header;
        readASEHeader(&header, handle);
@@ -525,16 +569,8 @@ size_t bzGfxLoadAsepritePalette(uint32_t *colorsOut, size_t maxColors, const cha
 
        for (ASE_WORD frame = 0; frame < header.frames; ++frame) {
                ASE_Frame frame;
-               bzResourcesReadBytes(handle, &frame, sizeof(frame));
-
-               ASE_DWORD numChunks = frame.___numChunks;
-
-               if (numChunks == 0xFFFF) {
-                       numChunks = frame.numChunks;
-                       if (numChunks == 0) {
-                               numChunks = frame.___numChunks; // See docs.
-                       }
-               }
+               ASE_DWORD numChunks;
+               readASEFrame(&frame, &numChunks, handle);
 
                for (ASE_DWORD chunk = 0; chunk < numChunks; ++chunk) {
                        size_t chunkStartPosition = bzResourcesTell(handle);