-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Supports generating code for .TTF files and .ASE files (with tags/ani…
…mations and slices information) (#1741) * Supports generating code for .TTF files and .ASE files (with tags/animations and slices information) * Adds ImageDataView. play and stop helpers
- Loading branch information
Showing
9 changed files
with
385 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
129 changes: 129 additions & 0 deletions
129
buildSrc/src/main/kotlin/korlibs/korge/gradle/util/ASEInfo.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package korlibs.korge.gradle.util | ||
|
||
data class ASEInfo( | ||
val slices: List<AseSlice> = emptyList(), | ||
val tags: List<AseTag> = emptyList(), | ||
) { | ||
data class AseSlice( | ||
val sliceName: String, | ||
val hasNinePatch: Boolean, | ||
val hasPivotInfo: Boolean, | ||
) | ||
|
||
data class AseTag( | ||
val fromFrame: Int, | ||
val toFrame: Int, | ||
val direction: Int, | ||
val tagColor: Int, | ||
val tagName: String | ||
) | ||
|
||
companion object { | ||
fun getAseInfo(file: SFile): ASEInfo { | ||
return getAseInfo(file.readBytes()) | ||
} | ||
|
||
fun getAseInfo(data: ByteArray): ASEInfo { | ||
return getAseInfo(ByteArraySimpleInputStream(ByteArraySlice(data))) | ||
} | ||
|
||
fun getAseInfo(s: ByteArraySimpleInputStream): ASEInfo { | ||
if (s.length == 0) return ASEInfo() | ||
|
||
val slices = arrayListOf<AseSlice>() | ||
val tags = arrayListOf<AseTag>() | ||
|
||
val fileSize = s.readS32LE() | ||
if (s.length < fileSize) error("File too short") | ||
val headerMagic = s.readU16LE() | ||
if (headerMagic != 0xA5E0) error("Not an Aseprite file : headerMagic=$headerMagic") | ||
val numFrames = s.readU16LE() | ||
val imageWidth = s.readU16LE() | ||
val imageHeight = s.readU16LE() | ||
val bitsPerPixel = s.readU16LE() | ||
val bytesPerPixel = bitsPerPixel / 8 | ||
val flags = s.readU32LE() | ||
val speed = s.readU16LE() | ||
s.skip(4) | ||
s.skip(4) | ||
val transparentIndex = s.readU8() | ||
s.skip(3) | ||
val numColors = s.readU16LE() | ||
val pixelWidth = s.readU8() | ||
val pixelHeight = s.readU8() | ||
val gridX = s.readS16LE() | ||
val gridY = s.readS16LE() | ||
val gridWidth = s.readU16LE() | ||
val gridHeight = s.readU16LE() | ||
s.skip(84) | ||
|
||
//println("ASE fileSize=$fileSize, headerMagic=$headerMagic, numFrames=$numFrames, $imageWidth x $imageHeight, bitsPerPixel=$bitsPerPixel, numColors=$numColors, gridWidth=$gridWidth, gridHeight=$gridHeight") | ||
|
||
for (frameIndex in 0 until numFrames) { | ||
//println("FRAME: $frameIndex") | ||
val bytesInFrame = s.readS32LE() | ||
val fs = s.readStream(bytesInFrame - 4) | ||
val frameMagic = fs.readU16LE() | ||
//println(" bytesInFrame=$bytesInFrame, frameMagic=$frameMagic") | ||
if (frameMagic != 0xF1FA) error("Invalid ASE sprite file or error parsing : frameMagic=$frameMagic") | ||
fs.readU16LE() | ||
val frameDuration = fs.readU16LE() | ||
fs.skip(2) | ||
val numChunks = fs.readS32LE() | ||
|
||
//println(" - $numChunks") | ||
|
||
for (nc in 0 until numChunks) { | ||
val chunkSize = fs.readS32LE() | ||
val chunkType = fs.readU16LE() | ||
val cs = fs.readStream(chunkSize - 6) | ||
|
||
//println(" chunkType=$chunkType, chunkSize=$chunkSize") | ||
|
||
when (chunkType) { | ||
0x2022 -> { // SLICE KEYS | ||
val numSliceKeys = cs.readS32LE() | ||
val sliceFlags = cs.readS32LE() | ||
cs.skip(4) | ||
val sliceName = cs.readAseString() | ||
val hasNinePatch = sliceFlags.hasBitSet(0) | ||
val hasPivotInfo = sliceFlags.hasBitSet(1) | ||
val aslice = AseSlice(sliceName, hasNinePatch, hasPivotInfo) | ||
slices += aslice | ||
} | ||
0x2018 -> { // TAGS | ||
// Tags | ||
val numTags = cs.readU16LE() | ||
cs.skip(8) | ||
//println(" tags: numTags=$numTags") | ||
|
||
for (tag in 0 until numTags) { | ||
val fromFrame = cs.readU16LE() | ||
val toFrame = cs.readU16LE() | ||
val direction = cs.readU8() | ||
cs.skip(8) | ||
val tagColor = cs.readS32LE() | ||
val tagName = cs.readAseString() | ||
val atag = AseTag(fromFrame, toFrame, direction, tagColor, tagName) | ||
tags += atag | ||
//println(" tag[$tag]=$atag") | ||
} | ||
} | ||
// Unsupported tag | ||
else -> { | ||
|
||
} | ||
} | ||
} | ||
} | ||
|
||
return ASEInfo( | ||
slices = slices, | ||
tags = tags, | ||
) | ||
} | ||
|
||
fun ByteArraySimpleInputStream.readAseString(): String = readBytes(readU16LE()).toString(Charsets.UTF_8) | ||
public infix fun Int.hasBitSet(index: Int): Boolean = ((this ushr index) and 1) != 0 | ||
} | ||
} |
96 changes: 96 additions & 0 deletions
96
buildSrc/src/main/kotlin/korlibs/korge/gradle/util/InputStreamExt.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package korlibs.korge.gradle.util | ||
|
||
import java.io.* | ||
|
||
class ByteArraySlice(val ba: ByteArray, val pos: Int = 0, val size: Int = ba.size - pos) { | ||
fun sliceRange(range: IntRange): ByteArraySlice { | ||
return ByteArraySlice(ba, pos + range.first, range.last - range.first - 1) | ||
} | ||
val length: Int get() = size | ||
operator fun get(index: Int): Byte = ba[pos + index] | ||
fun sliceArray(range: IntRange): ByteArray { | ||
return ba.sliceArray((pos + range.first) .. (pos + range.last)) | ||
} | ||
|
||
override fun toString(): String= "ByteArraySlice[$size]" | ||
} | ||
|
||
class ByteArraySimpleInputStream( | ||
val data: ByteArraySlice, | ||
var pos: Int = 0 | ||
) { | ||
val available: Int get() = length - pos | ||
val length: Int get() = data.size | ||
|
||
fun read(): Int { | ||
if (pos >= length) return -1 | ||
return data[pos++].toInt() and 0xFF | ||
} | ||
|
||
fun readU8(): Int { | ||
val v = this.read() | ||
if (v < 0) error("Can't read byte at $pos in $data") | ||
return v | ||
} | ||
|
||
fun readU16LE(): Int { | ||
val v0 = readU8() | ||
val v1 = readU8() | ||
return (v0 shl 0) or (v1 shl 8) | ||
} | ||
|
||
fun readS16LE(): Int = (readU16LE() shl 16) shr 16 | ||
|
||
fun skip(count: Int): Int { | ||
val oldPos = pos | ||
pos += count | ||
return oldPos | ||
} | ||
|
||
fun readS32LE(): Int { | ||
val v0 = readU8() | ||
val v1 = readU8() | ||
val v2 = readU8() | ||
val v3 = readU8() | ||
return (v0 shl 0) or (v1 shl 8) or (v2 shl 16) or (v3 shl 24) | ||
} | ||
|
||
fun readU32LE(): Long { | ||
return readS32LE().toLong() and 0xFFFFFFFFL | ||
} | ||
|
||
fun readStream(count: Int): ByteArraySimpleInputStream { | ||
val pos = skip(count) | ||
return ByteArraySimpleInputStream(data.sliceRange(pos until (pos + count)), 0) | ||
} | ||
|
||
fun readBytes(count: Int): ByteArray { | ||
val start = skip(count) | ||
return data.sliceArray(start until (start + count)) | ||
} | ||
} | ||
|
||
fun InputStream.readU8(): Int { | ||
val v = this.read() | ||
if (v < 0) error("Can't read byte") | ||
return v | ||
} | ||
|
||
fun InputStream.readU16LE(): Int { | ||
val v0 = readU8() | ||
val v1 = readU8() | ||
return (v0 shl 0) or (v1 shl 8) | ||
} | ||
|
||
fun InputStream.readS32LE(): Int { | ||
val v0 = readU8() | ||
val v1 = readU8() | ||
val v2 = readU8() | ||
val v3 = readU8() | ||
return (v0 shl 0) or (v1 shl 8) or (v2 shl 16) or (v3 shl 24) | ||
} | ||
|
||
fun InputStream.readU32LE(): Long { | ||
return readS32LE().toLong() and 0xFFFFFFFFL | ||
} | ||
|
Oops, something went wrong.