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}")
|
else -> throw IllegalArgumentException("Unknown amount of channels in $it: ${data.amountOfChannels}")
|
||||||
})
|
})
|
||||||
|
|
||||||
tex.upload(when (data.amountOfChannels) {
|
val fileFormat = when (data.amountOfChannels) {
|
||||||
1 -> GL_RED
|
1 -> GL_RED
|
||||||
3 -> GL_RGB
|
3 -> GL_RGB
|
||||||
4 -> GL_RGBA
|
4 -> GL_RGBA
|
||||||
else -> throw IllegalArgumentException("Unknown amount of channels in $it: ${data.amountOfChannels}")
|
else -> throw IllegalArgumentException("Unknown amount of channels in $it: ${data.amountOfChannels}")
|
||||||
}, GL_UNSIGNED_BYTE, data.data)
|
}
|
||||||
|
|
||||||
tex.textureMinFilter = GL_NEAREST
|
data.data.thenApplyAsync({
|
||||||
tex.textureMagFilter = GL_NEAREST
|
tex.upload(fileFormat, GL_UNSIGNED_BYTE, it)
|
||||||
|
|
||||||
|
tex.textureMinFilter = GL_NEAREST
|
||||||
|
tex.textureMagFilter = GL_NEAREST
|
||||||
|
}, foregroundExecutor)
|
||||||
|
|
||||||
tex
|
tex
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package ru.dbotthepony.kstarbound.defs.image
|
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.Cache
|
||||||
|
import com.github.benmanes.caffeine.cache.CacheLoader
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine
|
import com.github.benmanes.caffeine.cache.Caffeine
|
||||||
|
import com.github.benmanes.caffeine.cache.LoadingCache
|
||||||
import com.github.benmanes.caffeine.cache.Scheduler
|
import com.github.benmanes.caffeine.cache.Scheduler
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
@ -32,6 +35,7 @@ import java.nio.ByteBuffer
|
|||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
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()
|
var get = dataRef?.get()
|
||||||
|
|
||||||
if (get != null)
|
if (get != null)
|
||||||
return get
|
return CompletableFuture.completedFuture(get)
|
||||||
|
|
||||||
lock.lock()
|
lock.lock()
|
||||||
|
|
||||||
@ -80,31 +84,14 @@ class Image private constructor(
|
|||||||
get = dataRef?.get()
|
get = dataRef?.get()
|
||||||
|
|
||||||
if (get != null)
|
if (get != null)
|
||||||
return get
|
return CompletableFuture.completedFuture(get)
|
||||||
|
|
||||||
get = dataCache.get(path) {
|
val f = dataCache.get(source)
|
||||||
val getWidth = intArrayOf(0)
|
|
||||||
val getHeight = intArrayOf(0)
|
|
||||||
val components = intArrayOf(0)
|
|
||||||
|
|
||||||
val data = STBImage.stbi_load_from_memory(
|
if (f.isDone)
|
||||||
source.readDirect(),
|
dataRef = WeakReference(f.get())
|
||||||
getWidth, getHeight,
|
|
||||||
components, 0
|
|
||||||
) ?: throw IllegalArgumentException("File $source is not an image or it is corrupted")
|
|
||||||
|
|
||||||
val address = MemoryUtil.memAddress(data)
|
return f.copy()
|
||||||
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
|
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlock()
|
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" }
|
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 offset = (this.y + y) * this@Image.width * amountOfChannels + (this.x + x) * amountOfChannels
|
||||||
val data = data
|
val data = data.join()
|
||||||
|
|
||||||
when (amountOfChannels) {
|
when (amountOfChannels) {
|
||||||
4 -> return data[offset].toInt() or
|
4 -> return data[offset].toInt() or
|
||||||
@ -273,12 +260,27 @@ class Image private constructor(
|
|||||||
private val imageCache = ConcurrentHashMap<String, Optional<Image>>()
|
private val imageCache = ConcurrentHashMap<String, Optional<Image>>()
|
||||||
private val logger = LogManager.getLogger()
|
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))
|
.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 МиБ */)
|
.maximumWeight(1_024L * 1_024L * 256L /* 256 МиБ */)
|
||||||
.scheduler(Scheduler.systemScheduler())
|
.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
|
@JvmStatic
|
||||||
fun get(path: String): Image? {
|
fun get(path: String): Image? {
|
||||||
|
Loading…
Reference in New Issue
Block a user