From 9d5334e5d89db420ade2d1e46aee0baa957b7f4e Mon Sep 17 00:00:00 2001 From: Josh Larson Date: Mon, 18 Jul 2022 15:45:07 -0500 Subject: [PATCH] Sped up targa bitmap loading significantly --- .../parsers/terrain/bitmap/TargaBitmap.kt | 128 ++++++++---------- .../parsers/terrain/filters/FilterBitmap.kt | 8 +- 2 files changed, 60 insertions(+), 76 deletions(-) diff --git a/src/main/java/com/projectswg/common/data/swgiff/parsers/terrain/bitmap/TargaBitmap.kt b/src/main/java/com/projectswg/common/data/swgiff/parsers/terrain/bitmap/TargaBitmap.kt index 36db024..ea88a14 100644 --- a/src/main/java/com/projectswg/common/data/swgiff/parsers/terrain/bitmap/TargaBitmap.kt +++ b/src/main/java/com/projectswg/common/data/swgiff/parsers/terrain/bitmap/TargaBitmap.kt @@ -2,6 +2,7 @@ package com.projectswg.common.data.swgiff.parsers.terrain.bitmap import java.io.FileInputStream import java.io.InputStream +import kotlin.math.min class TargaBitmap { @@ -9,62 +10,19 @@ class TargaBitmap { private var colorMapType: Byte = 0 private var dataTypeCode: Byte = 0 private var colorMapDepth: Byte = 0 - private var bitsPerPixel: Byte = 0 + private var bitsPerPixel: Int = 0 private var imageDescriptor: Byte = 0 private var colorMapOrigin: Short = 0 private var colorMapLength: Short = 0 private var originX: Short = 0 private var originY: Short = 0 - var width: Short = 0 + var width: Int = 0 private set - var height: Short = 0 + var height: Int = 0 private set - private lateinit var pixelData: Array + private lateinit var pixelData: ByteArray var fileName: String? = null - inner class TargaColorPixel : TargaPixel() { - var r = 0.toChar() - var g = 0.toChar() - var b = 0.toChar() - var a = 0.toChar() - - override fun read(buffer: InputStream, bytes: Int) { - when (bytes) { - 4 -> { - r = Char(buffer.read().toUShort()) - g = Char(buffer.read().toUShort()) - b = Char(buffer.read().toUShort()) - a = Char(buffer.read().toUShort()) - } - 3 -> { - r = Char(buffer.read().toUShort()) - g = Char(buffer.read().toUShort()) - b = Char(buffer.read().toUShort()) - a = 0.toChar() - } - 2 -> { - val first = Char(buffer.read().toUShort()) - val second = Char(buffer.read().toUShort()) - r = (first.code and 0x7c shl 1).toChar() - g = (first.code and 0x03 shl 6 or (second.code and 0xe0 shl 2)).toChar() - b = (second.code and 0x1f shl 3).toChar() - a = (first.code and 0x80).toChar() - } - } - } - } - - inner class TargaBlackPixel : TargaPixel() { - var `val` = 0.toChar() - override fun read(buffer: InputStream, bytes: Int) { - `val` = Char(buffer.readByte().toUShort()) - } - } - - abstract inner class TargaPixel { - abstract fun read(buffer: InputStream, bytes: Int) - } - fun readFile(filePath: String) { fileName = filePath FileInputStream("clientdata/$filePath").use { inputStream -> @@ -76,9 +34,9 @@ class TargaBitmap { colorMapDepth = inputStream.readByte() originX = inputStream.readShort() originY = inputStream.readShort() - width = inputStream.readShort() - height = inputStream.readShort() - bitsPerPixel = inputStream.readByte() + width = inputStream.readShort().toInt() + height = inputStream.readShort().toInt() + bitsPerPixel = inputStream.readByte().toInt() imageDescriptor = inputStream.readByte() var length = 0 @@ -89,37 +47,35 @@ class TargaBitmap { else if (height > width) length = height * height - pixelData = arrayOfNulls(length) - for (i in 0 until length) { - var pixel: TargaPixel? = null - when (dataTypeCode.toInt()) { - 3 -> pixel = TargaBlackPixel() - 2, 10 -> pixel = TargaColorPixel() - } - pixelData[i] = pixel - } inputStream.skip((idLength + colorMapType * colorMapLength).toLong()) - val bytes = bitsPerPixel / 8 - if (width <= height) { - for (i in width - 1 downTo 0) { - for (j in 0 until height) { - pixelData[i * width + j]!!.read(inputStream, bytes) - } - } + if (bitsPerPixel == 8) { + pixelData = inputStream.readNBytes(length) } else { - for (i in height - 1 downTo 0) { - for (j in 0 until width) { - pixelData[i * height + j]!!.read(inputStream, bytes) - } + assert(dataTypeCode == 2.toByte() || dataTypeCode == 10.toByte()) + pixelData = ByteArray(length * 4) + val pixelLoaderFunction = when (bitsPerPixel) { + 16 -> ::read2ByteColorPixel + 24 -> ::read3ByteColorPixel + 32 -> ::read4ByteColorPixel + else -> throw NotImplementedError("unsupported bits per pixel: $bitsPerPixel") + } + val bytesPerPixel = bitsPerPixel / 8 + var index = 0 + for (i in 0 until length) { + pixelLoaderFunction(inputStream, pixelData, index) + index += bytesPerPixel } } } } - fun getData(offset: Int): Char { + fun getData(offset: Int): Byte { if (offset < 0 || offset >= width * height) throw ArrayIndexOutOfBoundsException(offset) - return (pixelData[offset] as TargaBlackPixel?)!!.`val` + val smaller = min(width, height) + val y = offset / smaller + val x = offset % smaller + return pixelData[(smaller - y - 1) * smaller + x] } private fun InputStream.readByte(): Byte { @@ -130,4 +86,32 @@ class TargaBitmap { return ((read() or (read() shl 8)) and 0xFFFF).toShort() } + companion object { + private fun read4ByteColorPixel(src: InputStream, dst: ByteArray, indexIn: Int) { + var index: Int = indexIn + dst[index++] = src.read().toByte() + dst[index++] = src.read().toByte() + dst[index++] = src.read().toByte() + dst[index] = src.read().toByte() + } + + private fun read3ByteColorPixel(src: InputStream, dst: ByteArray, indexIn: Int) { + var index: Int = indexIn + dst[index++] = src.read().toByte() + dst[index++] = src.read().toByte() + dst[index++] = src.read().toByte() + dst[index] = 0 + } + + private fun read2ByteColorPixel(src: InputStream, dst: ByteArray, indexIn: Int) { + var index: Int = indexIn + val first = src.read() + val second = src.read() + dst[index++] = (first and 0x7c shl 1).toByte() + dst[index++] = (first and 0x03 shl 6 or (second and 0xe0 shl 2)).toByte() + dst[index++] = (second and 0x1f shl 3).toByte() + dst[index] = (first and 0x80).toByte() + } + } + } diff --git a/src/main/java/com/projectswg/common/data/swgiff/parsers/terrain/filters/FilterBitmap.kt b/src/main/java/com/projectswg/common/data/swgiff/parsers/terrain/filters/FilterBitmap.kt index 6259cc7..11f3ba7 100644 --- a/src/main/java/com/projectswg/common/data/swgiff/parsers/terrain/filters/FilterBitmap.kt +++ b/src/main/java/com/projectswg/common/data/swgiff/parsers/terrain/filters/FilterBitmap.kt @@ -40,12 +40,12 @@ class FilterBitmap : FilterLayer() { var v25 = (v44 * (height - v41 - 1)).toInt() val v26 = (v39 * v44 / arg6).toInt() var v27 = (v43 * v44 / arg6).toInt() - val v28 = (bitmap.getData(v27 + v25).code and 0xFF).toFloat() + val v28 = (bitmap.getData(v27 + v25).toInt() and 0xFF).toFloat() //byte mapValue = v28; - var arg2 = (bitmap.getData(v26 + v25).code and 0xFF).toFloat() + var arg2 = (bitmap.getData(v26 + v25).toInt() and 0xFF).toFloat() val v29 = (v44 * (height - arg1 - 1)).toInt() - v25 = bitmap.getData(v29 + v27).code and 0xFF - v27 = bitmap.getData(v26 + v29).code and 0xFF + v25 = bitmap.getData(v29 + v27).toInt() and 0xFF + v27 = bitmap.getData(v26 + v29).toInt() and 0xFF arg6 = v25.toFloat() arg1 = v27.toFloat() val v30 = v42 - v43.toDouble()