prevent duplicate texture loading

This commit is contained in:
Bixilon 2021-05-26 16:59:56 +02:00
parent 6d8a2412cb
commit 746620d549
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
16 changed files with 68 additions and 96 deletions

View File

@ -59,7 +59,7 @@ enum class EntityMetaDataFields(val defaultValue: Any? = null) {
AREA_EFFECT_CLOUD_RADIUS(0.5f),
AREA_EFFECT_CLOUD_COLOR(0),
AREA_EFFECT_CLOUD_WAITING(false),
AREA_EFFECT_CLOUD_PARTICLE(ParticleData(ParticleType(ResourceLocation("effect")))),
AREA_EFFECT_CLOUD_PARTICLE(ParticleData(ParticleType(ResourceLocation("effect"), mutableListOf()))),
ABSTRACT_ARROW_FLAGS(0.toByte()),
ABSTRACT_ARROW_PIERCE_LEVEL(0.toByte()),

View File

@ -17,10 +17,11 @@ import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.registry.RegistryItem
import de.bixilon.minosoft.data.mappings.registry.ResourceLocationDeserializer
import de.bixilon.minosoft.data.mappings.versions.Registries
import de.bixilon.minosoft.gui.rendering.textures.Texture
data class ParticleType(
override val resourceLocation: ResourceLocation,
// ToDo
val textures: List<ResourceLocation>,
) : RegistryItem {
override fun toString(): String {
@ -29,7 +30,14 @@ data class ParticleType(
companion object : ResourceLocationDeserializer<ParticleType> {
override fun deserialize(mappings: Registries?, resourceLocation: ResourceLocation, data: JsonObject): ParticleType {
return ParticleType(resourceLocation)
val textures: MutableList<ResourceLocation> = mutableListOf()
data["render"]?.asJsonObject?.get("textures")?.asJsonArray?.let {
for (texture in it) {
val textureResourceLocation = ResourceLocation(texture.asString)
textures += Texture.getResourceTextureIdentifier(textureResourceLocation.namespace, textureName = "particle/${textureResourceLocation.path}")
}
}
return ParticleType(resourceLocation, textures.toList())
}
}
}

View File

@ -38,7 +38,6 @@ import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.play.PositionAndRotationS2CP
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.CountUpAndDownLatch
import de.bixilon.minosoft.util.KUtil.synchronizedListOf
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import de.bixilon.minosoft.util.Queue
import de.bixilon.minosoft.util.Stopwatch
@ -79,7 +78,7 @@ class RenderWindow(
private val screenshotTaker = ScreenshotTaker(this)
val tintColorCalculator = TintColorCalculator(connection.world)
val font = Font()
val textures = TextureArray(synchronizedListOf())
val textures = TextureArray(synchronizedMapOf())
val rendererMap: MutableMap<ResourceLocation, Renderer> = synchronizedMapOf()
@ -200,16 +199,16 @@ class RenderWindow(
Log.log(LogMessageType.RENDERING_LOADING) { "Generating font and gathering textures (${stopwatch.labTime()})..." }
textures.allTextures.add(Texture(RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION))
textures.allTextures.getOrPut(RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION) { Texture(RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION) }
WHITE_TEXTURE = TextureLikeTexture(
texture = Texture(ResourceLocation("minosoft:textures/white.png")),
uvStart = Vec2(0, 0),
uvEnd = Vec2(1.0f, 1.0f),
size = Vec2i(16, 16)
)
textures.allTextures.add(WHITE_TEXTURE.texture)
textures.allTextures.getOrPut(WHITE_TEXTURE.texture.resourceLocation) { WHITE_TEXTURE.texture }
font.load(connection.assetsManager)
font.load(connection.assetsManager, textures.allTextures)
Log.log(LogMessageType.RENDERING_LOADING) { "Initializing renderer (${stopwatch.labTime()})..." }
@ -219,7 +218,6 @@ class RenderWindow(
Log.log(LogMessageType.RENDERING_LOADING) { "Preloading textures (${stopwatch.labTime()})..." }
font.preLoadAtlas(textures)
textures.preLoad(connection.assetsManager)
font.loadAtlas()

View File

@ -135,7 +135,7 @@ class WorldRenderer(
override fun init() {
allBlocks = getAllBlocks(connection.version.registries)
renderWindow.textures.allTextures.addAll(resolveBlockTextureIds(allBlocks!!))
resolveBlockTextureIds(allBlocks!!, renderWindow.textures.allTextures)
// register keybindings
@ -210,16 +210,12 @@ class WorldRenderer(
glDepthMask(true)
}
private fun resolveBlockTextureIds(blocks: Collection<BlockState>): List<Texture> {
val textures: MutableList<Texture> = mutableListOf()
val textureMap: MutableMap<String, Texture> = synchronizedMapOf()
private fun resolveBlockTextureIds(blocks: Collection<BlockState>, textures: MutableMap<ResourceLocation, Texture>) {
for (block in blocks) {
for (model in block.renderers) {
model.resolveTextures(textures, textureMap)
model.resolveTextures(textures)
}
}
return textures
}

View File

@ -1,5 +1,6 @@
package de.bixilon.minosoft.gui.rendering.chunk.models.renderable
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.gui.rendering.chunk.models.FaceSize
import de.bixilon.minosoft.gui.rendering.textures.Texture
@ -9,23 +10,13 @@ interface BlockLikeRenderer {
fun render(context: BlockLikeRenderContext)
fun resolveTextures(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>)
fun resolveTextures(textures: MutableMap<ResourceLocation, Texture>)
fun postInit() {}
companion object {
fun resolveTexture(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>, textureName: String): Texture? {
var texture: Texture? = null
val index: Int? = textureMap[textureName]?.let {
texture = it
indexed.indexOf(it)
}
if (index == null) {
texture = Texture(Texture.getResourceTextureIdentifier(textureName = textureName))
textureMap[textureName] = texture!!
indexed.add(texture!!)
}
return texture
fun resolveTexture(textures: MutableMap<ResourceLocation, Texture>, textureResourceLocation: ResourceLocation): Texture {
return textures.getOrPut(textureResourceLocation) { Texture(textureResourceLocation) }
}
}
}

View File

@ -16,6 +16,7 @@ package de.bixilon.minosoft.gui.rendering.chunk.models.renderable
import com.google.common.collect.HashBiMap
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.Directions
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.biomes.Biome
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderConstants
@ -54,10 +55,10 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) : BlockLikeRenderer {
}
}
override fun resolveTextures(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>) {
for ((key, textureName) in textures) {
override fun resolveTextures(textures: MutableMap<ResourceLocation, Texture>) {
for ((key, textureName) in this.textures) {
if (!textureName.startsWith("#")) {
textureMapping[key] = BlockLikeRenderer.resolveTexture(indexed, textureMap, textureName = textureName)!!
textureMapping[key] = BlockLikeRenderer.resolveTexture(textures, textureResourceLocation = Texture.getResourceTextureIdentifier(textureName = textureName))
}
}
}

View File

@ -1,6 +1,7 @@
package de.bixilon.minosoft.gui.rendering.chunk.models.renderable
import de.bixilon.minosoft.data.Directions
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.biomes.Biome
import de.bixilon.minosoft.data.mappings.blocks.BlockState
import de.bixilon.minosoft.data.mappings.blocks.properties.BlockProperties
@ -221,9 +222,9 @@ class FluidRenderer(
return false
}
override fun resolveTextures(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>) {
stillTexture = BlockLikeRenderer.resolveTexture(indexed, textureMap, stillFluid.renderTexture.toString())!!
flowingTexture = BlockLikeRenderer.resolveTexture(indexed, textureMap, flowingFluid.renderTexture.toString())!!
override fun resolveTextures(textures: MutableMap<ResourceLocation, Texture>) {
stillTexture = BlockLikeRenderer.resolveTexture(textures, Texture.getResourceTextureIdentifier(stillFluid.renderTexture!!.namespace, stillFluid.renderTexture.path))
flowingTexture = BlockLikeRenderer.resolveTexture(textures, Texture.getResourceTextureIdentifier(flowingFluid.renderTexture!!.namespace, flowingFluid.renderTexture.path))
}
companion object {

View File

@ -14,6 +14,7 @@
package de.bixilon.minosoft.gui.rendering.chunk.models.renderable
import de.bixilon.minosoft.data.Directions
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.gui.rendering.chunk.models.FaceSize
import de.bixilon.minosoft.gui.rendering.textures.Texture
@ -45,9 +46,9 @@ class MultipartRenderer(
}
}
override fun resolveTextures(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>) {
override fun resolveTextures(textures: MutableMap<ResourceLocation, Texture>) {
for (model in models) {
model.resolveTextures(indexed, textureMap)
model.resolveTextures(textures)
}
}
}

View File

@ -14,16 +14,15 @@
package de.bixilon.minosoft.gui.rendering.font
import de.bixilon.minosoft.data.assets.AssetsManager
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.gui.rendering.textures.Texture
import de.bixilon.minosoft.gui.rendering.textures.TextureArray
class Font {
lateinit var providers: List<FontProvider>
private var preLoaded = false
private var loaded = false
fun load(assetsManager: AssetsManager) {
providers = FontLoader.loadFontProviders(assetsManager)
fun load(assetsManager: AssetsManager, textures: MutableMap<ResourceLocation, Texture>) {
providers = FontLoader.loadFontProviders(assetsManager, textures)
}
fun getChar(char: Char): FontChar {
@ -35,24 +34,8 @@ class Font {
throw IllegalStateException("$char can not be rendered!")
}
fun preLoadAtlas(textureArray: TextureArray) {
check(!preLoaded) { "Font has already been preloaded!" }
val textures: MutableList<Texture> = mutableListOf()
for (provider in providers) {
for (atlasPage in provider.atlasTextures) {
textures.add(atlasPage)
}
}
textureArray.allTextures.addAll(textures)
preLoaded = true
}
fun loadAtlas() {
check(!loaded) { "Font has already a atlas texture!" }
check(preLoaded) { "Font hasn't been preloaded!" }
for (provider in providers) {
for (char in provider.chars.values) {

View File

@ -37,17 +37,17 @@ object FontLoader {
return ret
}
private fun loadBitmapFontProvider(atlasPath: ResourceLocation, height: Int? = 8, ascent: Int, chars: List<Char>, assetsManager: AssetsManager): FontProvider {
private fun loadBitmapFontProvider(atlasPath: ResourceLocation, height: Int? = 8, ascent: Int, chars: List<Char>, assetsManager: AssetsManager, textures: MutableMap<ResourceLocation, Texture>): FontProvider {
val width = if (ascent == 7) { // ToDo: Why?
8
} else {
9
}
val provider = FontProvider(width)
val atlasTexture = Texture((Texture.getResourceTextureIdentifier(atlasPath.namespace, atlasPath.path)))
val atlasResourceLocation = Texture.getResourceTextureIdentifier(atlasPath.namespace, atlasPath.path)
val atlasTexture = textures.getOrPut(atlasResourceLocation) { Texture(atlasResourceLocation) }
atlasTexture.load(assetsManager)
val height = height ?: atlasTexture.size.x / FONT_ATLAS_SIZE
provider.atlasTextures.add(atlasTexture)
val charsCoordinates: MutableList<MutableList<FontChar>> = mutableListOf() // ToDo: Remove this
for ((i, char) in chars.withIndex()) {
if (i % FONT_ATLAS_SIZE == 0) {
@ -89,21 +89,22 @@ object FontLoader {
}
private fun loadUnicodeFontProvider(template: ResourceLocation, sizes: InputStream, assetsManager: AssetsManager): FontProvider {
private fun loadUnicodeFontProvider(template: ResourceLocation, sizes: InputStream, assetsManager: AssetsManager, textures: MutableMap<ResourceLocation, Texture>): FontProvider {
val provider = FontProvider(UNICODE_SIZE)
var i = 0
lateinit var currentAtlasTexture: Texture
while (sizes.available() > 0) {
if (i % 256 == 0) {
currentAtlasTexture = if (MISSING_UNICODE_PAGES.contains(i / UNICODE_CHARS_PER_PAGE)) {
val textureResourceLocation = if (MISSING_UNICODE_PAGES.contains(i / UNICODE_CHARS_PER_PAGE)) {
// ToDo: Why is this texture missing in minecraft?
Texture(RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION)
RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION
} else {
// new page (texture)
Texture(Texture.getResourceTextureIdentifier(template.namespace, template.path.format("%02x".format(i / 256))))
Texture.getResourceTextureIdentifier(template.namespace, template.path.format("%02x".format(i / 256)))
}
currentAtlasTexture = textures.getOrPut(textureResourceLocation) { Texture(textureResourceLocation) }
currentAtlasTexture.load(assetsManager)
provider.atlasTextures.add(currentAtlasTexture)
}
val sizeByte = sizes.read()
val fontChar = FontChar(currentAtlasTexture, (i % UNICODE_CHARS_PER_PAGE) / FONT_ATLAS_SIZE, (i % UNICODE_CHARS_PER_PAGE) % FONT_ATLAS_SIZE, (sizeByte shr 4) and 0x0F, (sizeByte and 0x0F) + 1, UNICODE_SIZE)
@ -113,13 +114,13 @@ object FontLoader {
return provider
}
fun loadFontProvider(data: JsonObject, assetsManager: AssetsManager): FontProvider {
fun loadFontProvider(data: JsonObject, assetsManager: AssetsManager, textures: MutableMap<ResourceLocation, Texture>): FontProvider {
return when (data["type"].asString) {
"bitmap" -> {
loadBitmapFontProvider(ResourceLocation(data["file"].asString), data["height"]?.asInt, data["ascent"].asInt, getCharArray(data["chars"].asJsonArray), assetsManager)
loadBitmapFontProvider(ResourceLocation(data["file"].asString), data["height"]?.asInt, data["ascent"].asInt, getCharArray(data["chars"].asJsonArray), assetsManager, textures)
}
"legacy_unicode" -> {
loadUnicodeFontProvider(ResourceLocation(data["template"].asString), assetsManager.readAssetAsStream(ResourceLocation(data["sizes"].asString)), assetsManager)
loadUnicodeFontProvider(ResourceLocation(data["template"].asString), assetsManager.readAssetAsStream(ResourceLocation(data["sizes"].asString)), assetsManager, textures)
}
"ttf" -> {
TODO("True Type Fonts are not implemented yet")
@ -129,10 +130,10 @@ object FontLoader {
}
fun loadFontProviders(assetsManager: AssetsManager): List<FontProvider> {
fun loadFontProviders(assetsManager: AssetsManager, textures: MutableMap<ResourceLocation, Texture>): List<FontProvider> {
val ret: MutableList<FontProvider> = mutableListOf()
for (providerElement in assetsManager.readJsonAsset(FONT_JSON_RESOURCE_LOCATION).asJsonObject["providers"].asJsonArray) {
val provider = loadFontProvider(providerElement.asJsonObject, assetsManager)
val provider = loadFontProvider(providerElement.asJsonObject, assetsManager, textures)
ret.add(provider)
}
return ret

View File

@ -13,9 +13,8 @@
package de.bixilon.minosoft.gui.rendering.font
import de.bixilon.minosoft.gui.rendering.textures.Texture
class FontProvider(val width: Int) {
class FontProvider(
val width: Int,
) {
val chars: MutableMap<Char, FontChar> = mutableMapOf()
val atlasTextures: MutableList<Texture> = mutableListOf()
}

View File

@ -57,10 +57,9 @@ class HUDRenderer(val connection: PlayConnection, val renderWindow: RenderWindow
override fun init() {
hudShader.load(Minosoft.MINOSOFT_ASSETS_MANAGER)
val (hudTextures, hudAtlasElements) = HUDAtlasElement.deserialize(Minosoft.MINOSOFT_ASSETS_MANAGER.readJsonAsset(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "mapping/atlas.json")).toResourceLocationMap())
this.hudAtlasElements = hudAtlasElements
this.hudAtlasElements = HUDAtlasElement.deserialize(Minosoft.MINOSOFT_ASSETS_MANAGER.readJsonAsset(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "mapping/atlas.json")).toResourceLocationMap(), renderWindow.textures.allTextures)
renderWindow.textures.allTextures.addAll(hudTextures.toList())
registerDefaultElements()

View File

@ -39,13 +39,12 @@ data class HUDAtlasElement(
}
companion object {
fun deserialize(json: Map<ResourceLocation, JsonObject>): Pair<Collection<Texture>, Map<ResourceLocation, HUDAtlasElement>> {
val textures: MutableMap<ResourceLocation, Texture> = mutableMapOf()
fun deserialize(json: Map<ResourceLocation, JsonObject>, textures: MutableMap<ResourceLocation, Texture>): Map<ResourceLocation, HUDAtlasElement> {
val ret: MutableMap<ResourceLocation, HUDAtlasElement> = mutableMapOf()
for ((resourceLocation, data) in json) {
ret[resourceLocation] = deserialize(data, textures)
}
return Pair(textures.values, ret)
return ret
}
fun deserialize(json: JsonObject, textures: MutableMap<ResourceLocation, Texture>): HUDAtlasElement {

View File

@ -14,7 +14,6 @@
package de.bixilon.minosoft.gui.rendering.particle
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.RendererBuilder
@ -37,14 +36,7 @@ class ParticleRenderer(
private lateinit var particleShader: Shader
private var particleMesh = ParticleMesh()
private val texture = Texture(DUMMY_PARTICLE_RESOURCE_LOCATION)
override fun init() {
particleMesh.load()
connection.registerEvent(CallbackEventInvoker.of<CameraMatrixChangeEvent> {
renderWindow.queue += {
particleShader.use().setMat4("uViewProjectionMatrix", it.viewProjectionMatrix)
@ -52,7 +44,12 @@ class ParticleRenderer(
particleShader.use().setVec3("uCameraUp", Vec3(it.viewMatrix[0][1], it.viewMatrix[1][1], it.viewMatrix[2][1]))
}
})
renderWindow.textures.allTextures += texture
particleMesh.load()
connection.registries.particleTypeRegistry.forEach {
for (resourceLocation in it.textures) {
renderWindow.textures.allTextures[resourceLocation] = Texture(resourceLocation)
}
}
}
override fun postInit() {
@ -82,7 +79,7 @@ class ParticleRenderer(
return min + random.nextFloat() * (max - min)
}
for (i in 0 until 123456) {
particleMesh.addVertex(Vec3(randomFlot(0.0f, 200.0f), randomFlot(6.0f, 200.0f), randomFlot(0.0f, 200.0f)), randomFlot(0.05f, 0.2f), texture, ChatColors.getRandomColor())
// particleMesh.addVertex(Vec3(randomFlot(0.0f, 200.0f), randomFlot(6.0f, 200.0f), randomFlot(0.0f, 200.0f)), randomFlot(0.05f, 0.2f), texture, ChatColors.getRandomColor())
}
@ -96,8 +93,6 @@ class ParticleRenderer(
companion object : RendererBuilder<ParticleRenderer> {
override val RESOURCE_LOCATION = ResourceLocation("minosoft:particle")
private val DUMMY_PARTICLE_RESOURCE_LOCATION = ResourceLocation("minecraft:textures/particle/spark_4.png")
override fun build(connection: PlayConnection, renderWindow: RenderWindow): ParticleRenderer {
return ParticleRenderer(connection, renderWindow)

View File

@ -48,7 +48,7 @@ class SkyRenderer(
)
private val skyboxMesh = SkyboxMesh()
private var skySunMesh = SimpleTextureMesh()
private var sunTexture = Texture(SUN_TEXTURE_RESOURCE_LOCATION)
private lateinit var sunTexture: Texture
private var recalculateSunNextFrame: Boolean = true
private var bottomColor = ChatColors.BLACK
private var topColor = RenderConstants.DEFAULT_SKY_COLOR
@ -74,7 +74,7 @@ class SkyRenderer(
recalculateSunNextFrame = true
}
})
renderWindow.textures.allTextures.add(sunTexture)
sunTexture = renderWindow.textures.allTextures.getOrPut(SUN_TEXTURE_RESOURCE_LOCATION) { Texture(SUN_TEXTURE_RESOURCE_LOCATION) }
}
private fun setSunMatrix(projectionViewMatrix: Mat4) {

View File

@ -30,14 +30,14 @@ import org.lwjgl.opengl.GL31.GL_UNIFORM_BUFFER
import org.lwjgl.opengl.GL31.glBindBuffer
import java.nio.ByteBuffer
class TextureArray(val allTextures: MutableList<Texture>) {
class TextureArray(val allTextures: MutableMap<ResourceLocation, Texture>) {
val animator = Animator()
private var textureIds = Array(TEXTURE_RESOLUTION_ID_MAP.size) { -1 }
private val texturesByResolution = Array<MutableList<Texture>>(TEXTURE_RESOLUTION_ID_MAP.size) { mutableListOf() }
fun preLoad(assetsManager: AssetsManager?) {
for (texture in allTextures) {
for (texture in allTextures.values) {
if (!texture.isLoaded) {
texture.load(assetsManager!!)
}