Have textures be logically loaded from Image itself
This commit is contained in:
parent
c8488c3565
commit
0b163481e7
@ -190,6 +190,8 @@ object Starbound : ISBFileLocator {
|
||||
registerTypeAdapterFactory(ItemReference.Factory(STRINGS))
|
||||
registerTypeAdapterFactory(TreasurePoolDefinition.Companion)
|
||||
|
||||
registerTypeAdapter(Image.Companion)
|
||||
|
||||
registerTypeAdapterFactory(with(RegistryReferenceFactory()) {
|
||||
add(Registries.tiles)
|
||||
add(Registries.tileModifiers)
|
||||
|
@ -2,6 +2,7 @@ package ru.dbotthepony.kstarbound.client
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import com.github.benmanes.caffeine.cache.Scheduler
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.lwjgl.BufferUtils
|
||||
import org.lwjgl.glfw.Callbacks
|
||||
@ -73,6 +74,7 @@ import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.ForkJoinPool
|
||||
import java.util.concurrent.ForkJoinWorkerThread
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
@ -282,13 +284,15 @@ class StarboundClient : Closeable {
|
||||
val stack = Matrix3fStack()
|
||||
|
||||
// минимальное время хранения 5 минут и...
|
||||
private val named2DTextures0: Cache<String, GLTexture2D> = Caffeine.newBuilder()
|
||||
val named2DTextures0: Cache<Image, GLTexture2D> = Caffeine.newBuilder()
|
||||
.expireAfterAccess(Duration.ofMinutes(1))
|
||||
.scheduler(Scheduler.systemScheduler())
|
||||
.build()
|
||||
|
||||
// ...бесконечное хранение пока кто-то все ещё использует текстуру
|
||||
private val named2DTextures1: Cache<String, GLTexture2D> = Caffeine.newBuilder()
|
||||
val named2DTextures1: Cache<Image, GLTexture2D> = Caffeine.newBuilder()
|
||||
.weakValues()
|
||||
.weakKeys()
|
||||
.build()
|
||||
|
||||
private val fontShaderPrograms = ArrayList<WeakReference<FontProgram>>()
|
||||
@ -502,44 +506,6 @@ class StarboundClient : Closeable {
|
||||
|
||||
fun isSameThread() = thread === Thread.currentThread()
|
||||
|
||||
fun loadTexture(path: String): GLTexture2D {
|
||||
ensureSameThread()
|
||||
|
||||
return named2DTextures0.get(path) {
|
||||
named2DTextures1.get(it) {
|
||||
val data = Image.get(it)
|
||||
|
||||
if (data == null) {
|
||||
LOGGER.error("Texture $it is not found!")
|
||||
missingTexture
|
||||
} else {
|
||||
val tex = GLTexture2D(data.width, data.height, when (data.amountOfChannels) {
|
||||
1 -> GL_R8
|
||||
3 -> GL_RGB8
|
||||
4 -> GL_RGBA8
|
||||
else -> throw IllegalArgumentException("Unknown amount of channels in $it: ${data.amountOfChannels}")
|
||||
})
|
||||
|
||||
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}")
|
||||
}
|
||||
|
||||
data.data.thenApplyAsync({
|
||||
tex.upload(fileFormat, GL_UNSIGNED_BYTE, it)
|
||||
|
||||
tex.textureMinFilter = GL_NEAREST
|
||||
tex.textureMagFilter = GL_NEAREST
|
||||
}, foregroundExecutor)
|
||||
|
||||
tex
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun newEBO() = BufferObject.EBO()
|
||||
fun newVBO() = BufferObject.VBO()
|
||||
fun newVAO() = VertexArrayObject()
|
||||
|
@ -7,7 +7,6 @@ import org.apache.logging.log4j.LogManager
|
||||
import org.lwjgl.opengl.GL45.*
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.Registries
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.client.gl.*
|
||||
import ru.dbotthepony.kstarbound.client.gl.shader.UberShader
|
||||
@ -16,12 +15,10 @@ import ru.dbotthepony.kstarbound.defs.tile.*
|
||||
import ru.dbotthepony.kstarbound.world.api.ITileAccess
|
||||
import ru.dbotthepony.kstarbound.world.api.ITileState
|
||||
import ru.dbotthepony.kstarbound.world.api.TileColor
|
||||
import ru.dbotthepony.kvector.arrays.Matrix3f
|
||||
import ru.dbotthepony.kvector.vector.RGBAColor
|
||||
import ru.dbotthepony.kvector.vector.Vector2i
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.Callable
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
/**
|
||||
* Хранит в себе программы для отрисовки определённых [TileDefinition]
|
||||
@ -116,7 +113,7 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
|
||||
}
|
||||
|
||||
val client get() = renderers.client
|
||||
val texture = def.renderParameters.texture?.imagePath?.value?.let { client.loadTexture(it).also { it.textureMagFilter = GL_NEAREST }}
|
||||
val texture = def.renderParameters.texture?.image?.texture?.also { it.textureMagFilter = GL_NEAREST }
|
||||
|
||||
val equalityTester: EqualityRuleTester = when (def) {
|
||||
is TileDefinition -> TileEqualityTester(def)
|
||||
@ -152,7 +149,7 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
|
||||
var mins = piece.texturePosition
|
||||
var maxs = piece.texturePosition + piece.textureSize
|
||||
|
||||
if (def.renderParameters.variants != 0 && piece.variantStride != null && piece.texture == null) {
|
||||
if (def.renderParameters.variants != 0 && piece.variantStride != null && piece.image == null) {
|
||||
val variant = (getter.randomDoubleFor(pos) * def.renderParameters.variants).toInt()
|
||||
mins += piece.variantStride * variant
|
||||
maxs += piece.variantStride * variant
|
||||
@ -187,11 +184,11 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
|
||||
): TestResult {
|
||||
if (matchPiece.test(getter, equalityTester, pos)) {
|
||||
for (renderPiece in matchPiece.pieces) {
|
||||
if (renderPiece.piece.texture != null) {
|
||||
if (renderPiece.piece.image != null) {
|
||||
val program = if (isBackground) {
|
||||
renderers.background(client.loadTexture(renderPiece.piece.texture!!))
|
||||
renderers.background(renderPiece.piece.image!!.texture)
|
||||
} else {
|
||||
renderers.foreground(client.loadTexture(renderPiece.piece.texture!!))
|
||||
renderers.foreground(renderPiece.piece.image!!.texture)
|
||||
}
|
||||
|
||||
tesselateAt(
|
||||
|
@ -82,7 +82,7 @@ sealed class Drawable(val position: Vector2f, val color: RGBAColor, val fullbrig
|
||||
|
||||
override fun render(client: StarboundClient, layer: IGeometryLayer, x: Float, y: Float) {
|
||||
val sprite = path.sprite ?: return
|
||||
val texture = client.loadTexture(path.imagePath.value!!)
|
||||
val texture = path.image!!.texture
|
||||
val program = if (fullbright) client.programs.positionTexture else client.programs.positionTextureLightmap
|
||||
|
||||
val mat = transform.map({ it.copy() }, {
|
||||
|
@ -11,16 +11,22 @@ import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonNull
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonSyntaxException
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.lwjgl.opengl.GL45
|
||||
import org.lwjgl.stb.STBImage
|
||||
import org.lwjgl.system.MemoryUtil
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNIT
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITi
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.api.IStarboundFile
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLTexture2D
|
||||
import ru.dbotthepony.kstarbound.io.json.consumeNull
|
||||
import ru.dbotthepony.kstarbound.io.stream2STBIO
|
||||
import ru.dbotthepony.kstarbound.util.contains
|
||||
import ru.dbotthepony.kstarbound.util.get
|
||||
@ -56,6 +62,7 @@ class Image private constructor(
|
||||
private val spritesInternal = Object2ObjectLinkedOpenHashMap<String, Sprite>()
|
||||
private var dataRef: WeakReference<ByteBuffer>? = null
|
||||
private val lock = ReentrantLock()
|
||||
//private val _texture = ThreadLocal<WeakReference<GLTexture2D>>()
|
||||
|
||||
init {
|
||||
if (sprites == null) {
|
||||
@ -97,6 +104,43 @@ class Image private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
val texture: GLTexture2D get() {
|
||||
//val get = _texture.get()?.get()
|
||||
val client = StarboundClient.current()
|
||||
|
||||
/*if (get != null) {
|
||||
// update access time
|
||||
client.named2DTextures0.getIfPresent(this)
|
||||
client.named2DTextures1.getIfPresent(this)
|
||||
return get
|
||||
}*/
|
||||
|
||||
val value = client.named2DTextures0.get(this) {
|
||||
client.named2DTextures1.get(this) {
|
||||
val (memFormat, fileFormat) = when (amountOfChannels) {
|
||||
1 -> GL45.GL_R8 to GL45.GL_RED
|
||||
3 -> GL45.GL_RGB8 to GL45.GL_RGB
|
||||
4 -> GL45.GL_RGBA8 to GL45.GL_RGBA
|
||||
else -> throw IllegalArgumentException("Unknown amount of channels in $it: $amountOfChannels")
|
||||
}
|
||||
|
||||
val tex = GLTexture2D(width, height, memFormat)
|
||||
|
||||
data.thenApplyAsync({
|
||||
tex.upload(fileFormat, GL45.GL_UNSIGNED_BYTE, it)
|
||||
|
||||
tex.textureMinFilter = GL45.GL_NEAREST
|
||||
tex.textureMagFilter = GL45.GL_NEAREST
|
||||
}, client.foregroundExecutor)
|
||||
|
||||
tex
|
||||
}
|
||||
}
|
||||
|
||||
//_texture.set(WeakReference(value))
|
||||
return value
|
||||
}
|
||||
|
||||
val size = Vector2i(width, height)
|
||||
val sprites: Map<String, Sprite> = Collections.unmodifiableMap(this.spritesInternal)
|
||||
val first: Sprite = this.spritesInternal.values.first()
|
||||
@ -250,7 +294,7 @@ class Image private constructor(
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
companion object : TypeAdapter<Image>() {
|
||||
const val FILL_RATIO = 1 / (PIXELS_IN_STARBOUND_UNIT * PIXELS_IN_STARBOUND_UNIT)
|
||||
|
||||
private val objects by lazy { Starbound.gson.getAdapter(JsonObject::class.java) }
|
||||
@ -317,6 +361,20 @@ class Image private constructor(
|
||||
}.orElse(null)
|
||||
}
|
||||
|
||||
override fun write(out: JsonWriter, value: Image?) {
|
||||
if (value == null)
|
||||
out.nullValue()
|
||||
else
|
||||
out.value(value.path)
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): Image? {
|
||||
if (`in`.consumeNull())
|
||||
return null
|
||||
else
|
||||
return get(`in`.nextString())
|
||||
}
|
||||
|
||||
private fun generateFakeNames(dimensions: Vector2i): JsonArray {
|
||||
return JsonArray(dimensions.y).also {
|
||||
var stripElem = 0
|
||||
|
@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.kstarbound.defs.image.Image
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||
import ru.dbotthepony.kstarbound.util.WriteOnce
|
||||
import ru.dbotthepony.kstarbound.world.api.ITileAccess
|
||||
@ -12,7 +13,7 @@ import ru.dbotthepony.kvector.vector.Vector2i
|
||||
|
||||
@JsonFactory
|
||||
data class RenderPiece(
|
||||
val texture: String? = null,
|
||||
val image: Image? = null,
|
||||
val textureSize: Vector2i,
|
||||
val texturePosition: Vector2i,
|
||||
val colorStride: Vector2i? = null,
|
||||
|
Loading…
Reference in New Issue
Block a user