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(ItemReference.Factory(STRINGS))
|
||||||
registerTypeAdapterFactory(TreasurePoolDefinition.Companion)
|
registerTypeAdapterFactory(TreasurePoolDefinition.Companion)
|
||||||
|
|
||||||
|
registerTypeAdapter(Image.Companion)
|
||||||
|
|
||||||
registerTypeAdapterFactory(with(RegistryReferenceFactory()) {
|
registerTypeAdapterFactory(with(RegistryReferenceFactory()) {
|
||||||
add(Registries.tiles)
|
add(Registries.tiles)
|
||||||
add(Registries.tileModifiers)
|
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.Cache
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine
|
import com.github.benmanes.caffeine.cache.Caffeine
|
||||||
|
import com.github.benmanes.caffeine.cache.Scheduler
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.lwjgl.BufferUtils
|
import org.lwjgl.BufferUtils
|
||||||
import org.lwjgl.glfw.Callbacks
|
import org.lwjgl.glfw.Callbacks
|
||||||
@ -73,6 +74,7 @@ import java.nio.ByteBuffer
|
|||||||
import java.nio.ByteOrder
|
import java.nio.ByteOrder
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.ForkJoinPool
|
import java.util.concurrent.ForkJoinPool
|
||||||
import java.util.concurrent.ForkJoinWorkerThread
|
import java.util.concurrent.ForkJoinWorkerThread
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
@ -282,13 +284,15 @@ class StarboundClient : Closeable {
|
|||||||
val stack = Matrix3fStack()
|
val stack = Matrix3fStack()
|
||||||
|
|
||||||
// минимальное время хранения 5 минут и...
|
// минимальное время хранения 5 минут и...
|
||||||
private val named2DTextures0: Cache<String, GLTexture2D> = Caffeine.newBuilder()
|
val named2DTextures0: Cache<Image, GLTexture2D> = Caffeine.newBuilder()
|
||||||
.expireAfterAccess(Duration.ofMinutes(1))
|
.expireAfterAccess(Duration.ofMinutes(1))
|
||||||
|
.scheduler(Scheduler.systemScheduler())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
// ...бесконечное хранение пока кто-то все ещё использует текстуру
|
// ...бесконечное хранение пока кто-то все ещё использует текстуру
|
||||||
private val named2DTextures1: Cache<String, GLTexture2D> = Caffeine.newBuilder()
|
val named2DTextures1: Cache<Image, GLTexture2D> = Caffeine.newBuilder()
|
||||||
.weakValues()
|
.weakValues()
|
||||||
|
.weakKeys()
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
private val fontShaderPrograms = ArrayList<WeakReference<FontProgram>>()
|
private val fontShaderPrograms = ArrayList<WeakReference<FontProgram>>()
|
||||||
@ -502,44 +506,6 @@ class StarboundClient : Closeable {
|
|||||||
|
|
||||||
fun isSameThread() = thread === Thread.currentThread()
|
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 newEBO() = BufferObject.EBO()
|
||||||
fun newVBO() = BufferObject.VBO()
|
fun newVBO() = BufferObject.VBO()
|
||||||
fun newVAO() = VertexArrayObject()
|
fun newVAO() = VertexArrayObject()
|
||||||
|
@ -7,7 +7,6 @@ import org.apache.logging.log4j.LogManager
|
|||||||
import org.lwjgl.opengl.GL45.*
|
import org.lwjgl.opengl.GL45.*
|
||||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||||
import ru.dbotthepony.kstarbound.Registries
|
import ru.dbotthepony.kstarbound.Registries
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
|
||||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||||
import ru.dbotthepony.kstarbound.client.gl.*
|
import ru.dbotthepony.kstarbound.client.gl.*
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.UberShader
|
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.ITileAccess
|
||||||
import ru.dbotthepony.kstarbound.world.api.ITileState
|
import ru.dbotthepony.kstarbound.world.api.ITileState
|
||||||
import ru.dbotthepony.kstarbound.world.api.TileColor
|
import ru.dbotthepony.kstarbound.world.api.TileColor
|
||||||
import ru.dbotthepony.kvector.arrays.Matrix3f
|
|
||||||
import ru.dbotthepony.kvector.vector.RGBAColor
|
import ru.dbotthepony.kvector.vector.RGBAColor
|
||||||
import ru.dbotthepony.kvector.vector.Vector2i
|
import ru.dbotthepony.kvector.vector.Vector2i
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.concurrent.Callable
|
import java.util.concurrent.Callable
|
||||||
import kotlin.collections.HashMap
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Хранит в себе программы для отрисовки определённых [TileDefinition]
|
* Хранит в себе программы для отрисовки определённых [TileDefinition]
|
||||||
@ -116,7 +113,7 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val client get() = renderers.client
|
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) {
|
val equalityTester: EqualityRuleTester = when (def) {
|
||||||
is TileDefinition -> TileEqualityTester(def)
|
is TileDefinition -> TileEqualityTester(def)
|
||||||
@ -152,7 +149,7 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
|
|||||||
var mins = piece.texturePosition
|
var mins = piece.texturePosition
|
||||||
var maxs = piece.texturePosition + piece.textureSize
|
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()
|
val variant = (getter.randomDoubleFor(pos) * def.renderParameters.variants).toInt()
|
||||||
mins += piece.variantStride * variant
|
mins += piece.variantStride * variant
|
||||||
maxs += piece.variantStride * variant
|
maxs += piece.variantStride * variant
|
||||||
@ -187,11 +184,11 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
|
|||||||
): TestResult {
|
): TestResult {
|
||||||
if (matchPiece.test(getter, equalityTester, pos)) {
|
if (matchPiece.test(getter, equalityTester, pos)) {
|
||||||
for (renderPiece in matchPiece.pieces) {
|
for (renderPiece in matchPiece.pieces) {
|
||||||
if (renderPiece.piece.texture != null) {
|
if (renderPiece.piece.image != null) {
|
||||||
val program = if (isBackground) {
|
val program = if (isBackground) {
|
||||||
renderers.background(client.loadTexture(renderPiece.piece.texture!!))
|
renderers.background(renderPiece.piece.image!!.texture)
|
||||||
} else {
|
} else {
|
||||||
renderers.foreground(client.loadTexture(renderPiece.piece.texture!!))
|
renderers.foreground(renderPiece.piece.image!!.texture)
|
||||||
}
|
}
|
||||||
|
|
||||||
tesselateAt(
|
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) {
|
override fun render(client: StarboundClient, layer: IGeometryLayer, x: Float, y: Float) {
|
||||||
val sprite = path.sprite ?: return
|
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 program = if (fullbright) client.programs.positionTexture else client.programs.positionTextureLightmap
|
||||||
|
|
||||||
val mat = transform.map({ it.copy() }, {
|
val mat = transform.map({ it.copy() }, {
|
||||||
|
@ -11,16 +11,22 @@ import com.google.gson.JsonArray
|
|||||||
import com.google.gson.JsonNull
|
import com.google.gson.JsonNull
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import com.google.gson.JsonSyntaxException
|
import com.google.gson.JsonSyntaxException
|
||||||
|
import com.google.gson.TypeAdapter
|
||||||
import com.google.gson.stream.JsonReader
|
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.Object2ObjectArrayMap
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import org.lwjgl.opengl.GL45
|
||||||
import org.lwjgl.stb.STBImage
|
import org.lwjgl.stb.STBImage
|
||||||
import org.lwjgl.system.MemoryUtil
|
import org.lwjgl.system.MemoryUtil
|
||||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNIT
|
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNIT
|
||||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITi
|
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITi
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
import ru.dbotthepony.kstarbound.api.IStarboundFile
|
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.io.stream2STBIO
|
||||||
import ru.dbotthepony.kstarbound.util.contains
|
import ru.dbotthepony.kstarbound.util.contains
|
||||||
import ru.dbotthepony.kstarbound.util.get
|
import ru.dbotthepony.kstarbound.util.get
|
||||||
@ -56,6 +62,7 @@ class Image private constructor(
|
|||||||
private val spritesInternal = Object2ObjectLinkedOpenHashMap<String, Sprite>()
|
private val spritesInternal = Object2ObjectLinkedOpenHashMap<String, Sprite>()
|
||||||
private var dataRef: WeakReference<ByteBuffer>? = null
|
private var dataRef: WeakReference<ByteBuffer>? = null
|
||||||
private val lock = ReentrantLock()
|
private val lock = ReentrantLock()
|
||||||
|
//private val _texture = ThreadLocal<WeakReference<GLTexture2D>>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (sprites == null) {
|
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 size = Vector2i(width, height)
|
||||||
val sprites: Map<String, Sprite> = Collections.unmodifiableMap(this.spritesInternal)
|
val sprites: Map<String, Sprite> = Collections.unmodifiableMap(this.spritesInternal)
|
||||||
val first: Sprite = this.spritesInternal.values.first()
|
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)
|
const val FILL_RATIO = 1 / (PIXELS_IN_STARBOUND_UNIT * PIXELS_IN_STARBOUND_UNIT)
|
||||||
|
|
||||||
private val objects by lazy { Starbound.gson.getAdapter(JsonObject::class.java) }
|
private val objects by lazy { Starbound.gson.getAdapter(JsonObject::class.java) }
|
||||||
@ -317,6 +361,20 @@ class Image private constructor(
|
|||||||
}.orElse(null)
|
}.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 {
|
private fun generateFakeNames(dimensions: Vector2i): JsonArray {
|
||||||
return JsonArray(dimensions.y).also {
|
return JsonArray(dimensions.y).also {
|
||||||
var stripElem = 0
|
var stripElem = 0
|
||||||
|
@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList
|
|||||||
import com.google.common.collect.ImmutableMap
|
import com.google.common.collect.ImmutableMap
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||||
import org.apache.logging.log4j.LogManager
|
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.io.json.builder.JsonFactory
|
||||||
import ru.dbotthepony.kstarbound.util.WriteOnce
|
import ru.dbotthepony.kstarbound.util.WriteOnce
|
||||||
import ru.dbotthepony.kstarbound.world.api.ITileAccess
|
import ru.dbotthepony.kstarbound.world.api.ITileAccess
|
||||||
@ -12,7 +13,7 @@ import ru.dbotthepony.kvector.vector.Vector2i
|
|||||||
|
|
||||||
@JsonFactory
|
@JsonFactory
|
||||||
data class RenderPiece(
|
data class RenderPiece(
|
||||||
val texture: String? = null,
|
val image: Image? = null,
|
||||||
val textureSize: Vector2i,
|
val textureSize: Vector2i,
|
||||||
val texturePosition: Vector2i,
|
val texturePosition: Vector2i,
|
||||||
val colorStride: Vector2i? = null,
|
val colorStride: Vector2i? = null,
|
||||||
|
Loading…
Reference in New Issue
Block a user