Async image data loading
This commit is contained in:
parent
7cb9a7951f
commit
c8488c3565
@ -520,15 +520,19 @@ class StarboundClient : Closeable {
|
||||
else -> throw IllegalArgumentException("Unknown amount of channels in $it: ${data.amountOfChannels}")
|
||||
})
|
||||
|
||||
tex.upload(when (data.amountOfChannels) {
|
||||
1 -> GL_RED
|
||||
3 -> GL_RGB
|
||||
4 -> GL_RGBA
|
||||
else -> throw IllegalArgumentException("Unknown amount of channels in $it: ${data.amountOfChannels}")
|
||||
}, GL_UNSIGNED_BYTE, data.data)
|
||||
val fileFormat = when (data.amountOfChannels) {
|
||||
1 -> GL_RED
|
||||
3 -> GL_RGB
|
||||
4 -> GL_RGBA
|
||||
else -> throw IllegalArgumentException("Unknown amount of channels in $it: ${data.amountOfChannels}")
|
||||
}
|
||||
|
||||
tex.textureMinFilter = GL_NEAREST
|
||||
tex.textureMagFilter = GL_NEAREST
|
||||
data.data.thenApplyAsync({
|
||||
tex.upload(fileFormat, GL_UNSIGNED_BYTE, it)
|
||||
|
||||
tex.textureMinFilter = GL_NEAREST
|
||||
tex.textureMagFilter = GL_NEAREST
|
||||
}, foregroundExecutor)
|
||||
|
||||
tex
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
package ru.dbotthepony.kstarbound.defs.image
|
||||
|
||||
import com.github.benmanes.caffeine.cache.AsyncLoadingCache
|
||||
import com.github.benmanes.caffeine.cache.Cache
|
||||
import com.github.benmanes.caffeine.cache.CacheLoader
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache
|
||||
import com.github.benmanes.caffeine.cache.Scheduler
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.gson.JsonArray
|
||||
@ -32,6 +35,7 @@ import java.nio.ByteBuffer
|
||||
import java.time.Duration
|
||||
import java.util.Collections
|
||||
import java.util.Optional
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
@ -68,11 +72,11 @@ class Image private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
val data: ByteBuffer get() {
|
||||
val data: CompletableFuture<ByteBuffer> get() {
|
||||
var get = dataRef?.get()
|
||||
|
||||
if (get != null)
|
||||
return get
|
||||
return CompletableFuture.completedFuture(get)
|
||||
|
||||
lock.lock()
|
||||
|
||||
@ -80,31 +84,14 @@ class Image private constructor(
|
||||
get = dataRef?.get()
|
||||
|
||||
if (get != null)
|
||||
return get
|
||||
return CompletableFuture.completedFuture(get)
|
||||
|
||||
get = dataCache.get(path) {
|
||||
val getWidth = intArrayOf(0)
|
||||
val getHeight = intArrayOf(0)
|
||||
val components = intArrayOf(0)
|
||||
val f = dataCache.get(source)
|
||||
|
||||
val data = STBImage.stbi_load_from_memory(
|
||||
source.readDirect(),
|
||||
getWidth, getHeight,
|
||||
components, 0
|
||||
) ?: throw IllegalArgumentException("File $source is not an image or it is corrupted")
|
||||
if (f.isDone)
|
||||
dataRef = WeakReference(f.get())
|
||||
|
||||
val address = MemoryUtil.memAddress(data)
|
||||
Starbound.CLEANER.register(data) { STBImage.nstbi_image_free(address) }
|
||||
|
||||
check(getWidth[0] == width && getHeight[0] == height && components[0] == amountOfChannels) {
|
||||
"Actual loaded image differs from constructed (this $width x $height with $amountOfChannels channels; loaded ${getWidth[0]} x ${getHeight[0]} with ${components[0]} channels)"
|
||||
}
|
||||
|
||||
data
|
||||
}
|
||||
|
||||
dataRef = WeakReference(get)
|
||||
return get
|
||||
return f.copy()
|
||||
} finally {
|
||||
lock.unlock()
|
||||
}
|
||||
@ -149,7 +136,7 @@ class Image private constructor(
|
||||
require(x in 0 until width && y in 0 until height) { "Position out of bounds: $x $y" }
|
||||
|
||||
val offset = (this.y + y) * this@Image.width * amountOfChannels + (this.x + x) * amountOfChannels
|
||||
val data = data
|
||||
val data = data.join()
|
||||
|
||||
when (amountOfChannels) {
|
||||
4 -> return data[offset].toInt() or
|
||||
@ -273,12 +260,27 @@ class Image private constructor(
|
||||
private val imageCache = ConcurrentHashMap<String, Optional<Image>>()
|
||||
private val logger = LogManager.getLogger()
|
||||
|
||||
private val dataCache: Cache<String, ByteBuffer> = Caffeine.newBuilder()
|
||||
private val dataCache: AsyncLoadingCache<IStarboundFile, ByteBuffer> = Caffeine.newBuilder()
|
||||
.expireAfterAccess(Duration.ofMinutes(1))
|
||||
.weigher<String, ByteBuffer> { key, value -> value.capacity() }
|
||||
.weigher<IStarboundFile, ByteBuffer> { key, value -> value.capacity() }
|
||||
.maximumWeight(1_024L * 1_024L * 256L /* 256 МиБ */)
|
||||
.scheduler(Scheduler.systemScheduler())
|
||||
.build()
|
||||
.buildAsync(CacheLoader {
|
||||
val getWidth = intArrayOf(0)
|
||||
val getHeight = intArrayOf(0)
|
||||
val components = intArrayOf(0)
|
||||
|
||||
val data = STBImage.stbi_load_from_memory(
|
||||
it.readDirect(),
|
||||
getWidth, getHeight,
|
||||
components, 0
|
||||
) ?: throw IllegalArgumentException("File $it is not an image or it is corrupted")
|
||||
|
||||
val address = MemoryUtil.memAddress(data)
|
||||
Starbound.CLEANER.register(data) { STBImage.nstbi_image_free(address) }
|
||||
|
||||
data
|
||||
})
|
||||
|
||||
@JvmStatic
|
||||
fun get(path: String): Image? {
|
||||
|
Loading…
Reference in New Issue
Block a user