using System.IO;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Assertions;
namespace UnityEditor.U2D.Aseprite
{
///
/// Aseprite cell types.
///
public enum CellTypes
{
RawImage = 0,
LinkedCell = 1,
CompressedImage = 2,
CompressedTileMap = 3
}
///
/// Parsed representation of an Aseprite Cell chunk.
///
public class CellChunk : BaseChunk
{
public override ChunkTypes chunkType => ChunkTypes.Cell;
internal CellChunk(uint chunkSize, ushort colorDepth, PaletteChunk paletteChunk, byte alphaPaletteEntry) : base(chunkSize)
{
m_ColorDepth = colorDepth;
m_PaletteChunk = paletteChunk;
m_AlphaPaletteEntry = alphaPaletteEntry;
}
readonly ushort m_ColorDepth;
readonly PaletteChunk m_PaletteChunk;
readonly byte m_AlphaPaletteEntry;
///
/// The layer index is a number to identify a layer in the sprite.
/// Layers are numbered in the same order as Layer Chunks appear in the file.
///
public ushort layerIndex { get; private set; }
///
/// The Cell's X position on the canvas.
///
public short posX { get; private set; }
///
/// The Cell's Y position on the canvas.
///
public short posY { get; private set; }
///
/// Opacity level of the cell (0 = transparent, 255 = opaque).
///
public byte opacity { get; private set; }
///
/// The type of cell.
///
public CellTypes cellType { get; private set; }
///
/// The frame index of the cell (Only available for Linked Cells).
///
public int linkedToFrame { get; private set; } = -1;
///
/// The width of the cell in pixels.
///
public ushort width { get; private set; }
///
/// The height of the cell in pixels.
///
public ushort height { get; private set; }
///
/// The image data of the cell.
///
public NativeArray image { get; private set; }
///
/// User data associated with the cell.
///
public UserDataChunk dataChunk { get; set; }
protected override void InternalRead(BinaryReader reader)
{
layerIndex = reader.ReadUInt16();
posX = reader.ReadInt16();
posY = reader.ReadInt16();
opacity = reader.ReadByte();
cellType = (CellTypes)reader.ReadUInt16();
// Not in use bytes
for (var i = 0; i < 7; ++i)
{
var miscVal = reader.ReadByte();
Assert.IsTrue(miscVal == 0);
}
if (cellType == CellTypes.RawImage)
{
width = reader.ReadUInt16();
height = reader.ReadUInt16();
byte[] imageData = null;
if (m_ColorDepth == 32)
imageData = reader.ReadBytes(width * height * 4);
else if (m_ColorDepth == 16)
imageData = reader.ReadBytes(width * height * 2);
else if (m_ColorDepth == 8)
imageData = reader.ReadBytes(width * height);
if (imageData != null)
image = AsepriteUtilities.GenerateImageData(m_ColorDepth, imageData, m_PaletteChunk, m_AlphaPaletteEntry);
}
else if (cellType == CellTypes.LinkedCell)
{
linkedToFrame = reader.ReadUInt16();
}
else if (cellType == CellTypes.CompressedImage)
{
width = reader.ReadUInt16();
height = reader.ReadUInt16();
var dataSize = (int)m_ChunkSize - ChunkHeader.stride - 20;
var decompressedData = AsepriteUtilities.ReadAndDecompressedData(reader, dataSize);
image = AsepriteUtilities.GenerateImageData(m_ColorDepth, decompressedData, m_PaletteChunk, m_AlphaPaletteEntry);
}
else if (cellType == CellTypes.CompressedTileMap) // Not implemented yet.
{
width = reader.ReadUInt16();
height = reader.ReadUInt16();
var bitsPerTile = reader.ReadUInt16();
var tileIdMask = reader.ReadUInt32();
var xFlipMask = reader.ReadUInt32();
var yFlipMask = reader.ReadUInt32();
var rotation90Mask = reader.ReadUInt32();
// Not in use bytes
for (var i = 0; i < 10; ++i)
reader.ReadByte();
var dataSize = (int)m_ChunkSize - ChunkHeader.stride - 48;
var decompressedData = AsepriteUtilities.ReadAndDecompressedData(reader, dataSize);
var bytesPerTile = bitsPerTile / 8;
var noOfTiles = decompressedData.Length / bytesPerTile;
using var memoryStream = new MemoryStream(decompressedData);
using var binaryReader = new BinaryReader(memoryStream);
for (var i = 0; i < noOfTiles; ++i)
{
uint tileIndex = 0;
if (bitsPerTile == 32)
tileIndex = binaryReader.ReadUInt32();
else if (bitsPerTile == 16)
tileIndex = binaryReader.ReadUInt16();
else if (bitsPerTile == 8)
tileIndex = binaryReader.ReadByte();
}
}
}
public override void Dispose()
{
image.DisposeIfCreated();
}
}
}