DecodeTapestry.kt 5.57 KB
Newer Older
1
package net.torvald.terrarum.modulebasegame.gameactors
Minjae Song's avatar
Minjae Song committed
2

Minjae Song's avatar
Minjae Song committed
3 4
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Pixmap
5
import net.torvald.terrarum.gameworld.toUint
Minjae Song's avatar
Minjae Song committed
6
import java.io.File
7 8
import java.nio.charset.Charset
import java.util.*
Minjae Song's avatar
Minjae Song committed
9 10 11

object DecodeTapestry {

12
    val colourIndices64 = arrayOf(
Minjae Song's avatar
Minjae Song committed
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
            0x333.fourBitCol(),
            0x600.fourBitCol(),
            0xA36.fourBitCol(),
            0x636.fourBitCol(),
            0x73B.fourBitCol(),
            0x427.fourBitCol(),
            0x44C.fourBitCol(),
            0x038.fourBitCol(),
            0x47B.fourBitCol(),
            0x466.fourBitCol(),
            0x353.fourBitCol(),
            0x453.fourBitCol(),
            0x763.fourBitCol(),
            0xA63.fourBitCol(),
            0x742.fourBitCol(),
            0x000.fourBitCol(),
            0x666.fourBitCol(),
            0xA00.fourBitCol(),
            0xE2A.fourBitCol(),
            0xD2F.fourBitCol(),
            0x92F.fourBitCol(),
            0x548.fourBitCol(),
            0x32F.fourBitCol(),
            0x36F.fourBitCol(),
            0x588.fourBitCol(),
            0x390.fourBitCol(),
            0x5F0.fourBitCol(),
            0x684.fourBitCol(),
            0xBA2.fourBitCol(),
            0xE60.fourBitCol(),
            0x854.fourBitCol(),
            0x533.fourBitCol(),
            0x999.fourBitCol(),
            0xE00.fourBitCol(),
            0xE6A.fourBitCol(),
            0xE6F.fourBitCol(),
            0x848.fourBitCol(),
            0x62F.fourBitCol(),
            0x66F.fourBitCol(),
            0x4AF.fourBitCol(),
            0x5BA.fourBitCol(),
            0x8FE.fourBitCol(),
            0x7F8.fourBitCol(),
            0x9E0.fourBitCol(),
            0xFE0.fourBitCol(),
            0xEA0.fourBitCol(),
            0xC85.fourBitCol(),
            0xE55.fourBitCol(),
            0xCCC.fourBitCol(),
            0xFFF.fourBitCol(),
            0xFDE.fourBitCol(),
            0xEAF.fourBitCol(),
            0xA3B.fourBitCol(),
            0x96F.fourBitCol(),
            0xAAF.fourBitCol(),
            0x7AF.fourBitCol(),
            0x3DF.fourBitCol(),
            0xBFF.fourBitCol(),
            0xBFB.fourBitCol(),
            0xAF6.fourBitCol(),
            0xFEB.fourBitCol(),
            0xFD7.fourBitCol(),
            0xE96.fourBitCol(),
            0xEBA.fourBitCol()
    )

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
    val colourIndices16 = arrayOf(
            0x000.fourBitCol(),
            0xfff.fourBitCol(),
            0x666.fourBitCol(),
            0xccc.fourBitCol(),
            0xfe0.fourBitCol(),
            0xe60.fourBitCol(),
            0xe00.fourBitCol(),
            0xe2a.fourBitCol(),
            0x427.fourBitCol(),
            0x32f.fourBitCol(),
            0x4af.fourBitCol(),
            0x5f0.fourBitCol(),
            0x390.fourBitCol(),
            0x353.fourBitCol(),
            0x533.fourBitCol(),
            0xa63.fourBitCol()
    )

Minjae Song's avatar
Minjae Song committed
98
    private fun Int.fourBitCol() = Color(
Minjae Song's avatar
Minjae Song committed
99
            this.and(0xF00).shl(20) or this.and(0xF00).shl(16) or
100 101 102
                    this.and(0x0F0).shl(16) or this.and(0x0F0).shl(12) or
                    this.and(0x00F).shl(12) or this.and(0x00F).shl(8) or
                    0xFF
Minjae Song's avatar
Minjae Song committed
103 104
    )

105 106 107 108 109
    val MAGIC = "TEAF".toByteArray(charset = Charset.forName("US-ASCII"))
    val FORMAT_16 = 1
    val FORMAT_64 = 2

    operator fun invoke(fileObj: File): TapestryObject {
110 111
        fun magicMismatch(magic: ByteArray, array: ByteArray): Boolean {
            return !Arrays.equals(array.sliceArray(0..magic.lastIndex), magic)
112 113 114 115 116 117
        }

        val file = fileObj.readBytes()

        val magic = file.copyOfRange(0, 4)

118
        if (magicMismatch(MAGIC, magic))
119 120 121 122 123 124 125 126 127
            throw RuntimeException("Invalid file --  type mismatch: expected header " +
                                   "${MAGIC[0]} ${MAGIC[1]} ${MAGIC[2]} ${MAGIC[3]}; got " +
                                   "${magic[0]} ${magic[1]} ${magic[2]} ${magic[3]}")

        val colourModel = file[4].toUint()

        if (colourModel != FORMAT_16 && colourModel != FORMAT_64)
            throw RuntimeException("Invalid colour model: $colourModel")

128
        val width = file[7].toUint().shl(8) + file[6].toUint()
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150

        val artNameBytes = ArrayList<Byte>()
        val authorNameBytes = ArrayList<Byte>()

        var readCounter = 8

        while (file[readCounter] != 0x00.toByte()) {
            artNameBytes.add(file[readCounter])
            readCounter++
        }

        readCounter++ // jump over null terminator

        while (file[readCounter] != 0x00.toByte()) {
            authorNameBytes.add(file[readCounter])
            readCounter++
        }

        readCounter++ // jump over null terminator



151 152
        val artName = String(artNameBytes.toByteArray(), charset = Charset.forName("UTF-8"))
        val authorName = String(authorNameBytes.toByteArray(), charset = Charset.forName("UTF-8"))
153 154 155

        val imageDataSize = file.size - readCounter
        val height = imageDataSize / width
Minjae Song's avatar
Minjae Song committed
156
        val outImageData = Pixmap(width, height, Pixmap.Format.RGBA8888)
157 158 159 160 161 162
        val counterOffset = readCounter
        while (readCounter < file.size) {
            val ofs = readCounter - counterOffset
            val palIndex = file[readCounter].toUint()

            if (colourModel == FORMAT_16) {
Minjae Song's avatar
Minjae Song committed
163 164
                outImageData.setColor(colourIndices16[palIndex])
                outImageData.drawPixel(ofs % width, ofs / width)
165 166
            }
            else {
Minjae Song's avatar
Minjae Song committed
167 168
                outImageData.setColor(colourIndices64[palIndex])
                outImageData.drawPixel(ofs % width, ofs / width)
169 170 171 172
            }

            readCounter++
        }
Minjae Song's avatar
Minjae Song committed
173

174
        return TapestryObject(outImageData, artName, authorName)
Minjae Song's avatar
Minjae Song committed
175 176
    }
}