More work on texture atlas

This commit is contained in:
DBotThePony 2022-10-07 16:27:07 +07:00
parent 9bf31d2af0
commit 23227e21e5
Signed by: DBot
GPG Key ID: DCC23B5715498507
10 changed files with 323 additions and 227 deletions

View File

@ -23,6 +23,7 @@ import net.minecraft.world.level.ItemLike
import net.minecraftforge.registries.ForgeRegistries
import ru.dbotthepony.mc.otm.client.render.AbstractSkinElement
import ru.dbotthepony.mc.otm.client.render.SkinElement
import ru.dbotthepony.mc.otm.client.render.SkinElementType
import ru.dbotthepony.mc.otm.core.ListSet
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.isActuallyEmpty
@ -92,7 +93,7 @@ class AndroidResearchType(
private val customName: Component? = null,
// ok
val skinIcon: JsonElement? = null,
val skinIcon: JsonObject? = null,
val itemIcon: Item? = null,
iconText: Component? = null,
) {
@ -102,7 +103,7 @@ class AndroidResearchType(
val resolvedSkinIcon by lazy {
check(isClient) { "Invalid realm" }
if (skinIcon != null)
AbstractSkinElement.fromJson(skinIcon)
SkinElementType.fromJson(skinIcon)
else
null
}
@ -550,7 +551,7 @@ class AndroidResearchType(
}
val skinIcon = if (buff.readBoolean()) {
TypeAdapters.JSON_ELEMENT.fromJson(buff.readUtf())
TypeAdapters.JSON_ELEMENT.fromJson(buff.readUtf()) as JsonObject
} else {
null
}
@ -591,7 +592,7 @@ class AndroidResearchType(
val experience = value["experience"]?.asInt ?: 0
val customName = value["custom_name"]?.let(Component.Serializer::fromJson)
val iconText = value["icon_text"]?.let(Component.Serializer::fromJson)
val skinIcon = value["skin_icon"]
val skinIcon = value["skin_icon"] as JsonObject?
val itemIcon = value["item_icon"]?.let { ForgeRegistries.ITEMS.getValue(ResourceLocation(it.asString)).let { if (it == Items.AIR) null else it } }
return AndroidResearchType(

View File

@ -30,11 +30,11 @@ import java.util.*
import kotlin.math.ceil
object MatteryGUI {
val CHARGE = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_charge/android_charge"))
val CHARGE_BG = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_charge/android_charge_bg"))
val CHARGE = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_charge/android_charge"), 80f, 9f)
val CHARGE_BG = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_charge/android_charge_bg"), 80f, 9f)
val CHARGE_HUNGER = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_charge/android_charge_hunger"))
val CHARGE_HUNGER_BG = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_charge/android_charge_hunger_bg"))
val CHARGE_HUNGER = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_charge/android_charge_hunger"), 80f, 9f)
val CHARGE_HUNGER_BG = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_charge/android_charge_hunger_bg"), 80f, 9f)
private var originalBedButtonX = -1
private var originalBedButtonY = -1

View File

@ -22,14 +22,25 @@ import ru.dbotthepony.mc.otm.core.linearInterpolation
import java.lang.reflect.Type
sealed class AbstractSkinElement {
abstract val x: Float
abstract val y: Float
/**
* Expected image width in pixels, used in calculations
* and as default width argument in render methods
*/
abstract val width: Float
/**
* Expected image height in pixels, used in calculations
* and as default height argument in render methods
*/
abstract val height: Float
abstract val u0: Float
abstract val v0: Float
abstract val u1: Float
abstract val v1: Float
abstract val type: SkinElementType
open val winding: UVWindingOrder get() = UVWindingOrder.NORMAL
abstract val texture: ResourceLocation
@ -290,55 +301,11 @@ sealed class AbstractSkinElement {
uploadOnto(pose, builder, x, y, width, height, z, color, winding)
}
abstract fun toJson(): JsonElement
abstract fun toNetwork(buff: FriendlyByteBuf)
companion object : TypeAdapter<AbstractSkinElement>(), JsonSerializer<AbstractSkinElement>, JsonDeserializer<AbstractSkinElement> {
fun toNetwork(value: AbstractSkinElement, buff: FriendlyByteBuf) {
buff.writeBoolean(value is AtlasSkinElement)
value.toNetwork(buff)
fun toJson(): JsonObject {
return type.toActualJson(this)
}
fun fromNetwork(buff: FriendlyByteBuf): AbstractSkinElement {
if (buff.readBoolean()) {
return AtlasSkinElement.fromNetwork(buff)
}
return SkinElement.fromNetwork(buff)
}
fun fromJson(json: JsonElement): AbstractSkinElement {
if (json is JsonPrimitive) {
return AtlasSkinElement.fromJson(json)
} else if (json is JsonObject) {
return SkinElement.fromJson(json)
} else {
throw JsonSyntaxException("Unknown element type ${json::class.qualifiedName}")
}
}
override fun write(out: JsonWriter, value: AbstractSkinElement) {
TypeAdapters.JSON_ELEMENT.write(out, value.toJson())
}
override fun read(`in`: JsonReader): AbstractSkinElement {
return fromJson(TypeAdapters.JSON_ELEMENT.read(`in`))
}
override fun serialize(
src: AbstractSkinElement,
typeOfSrc: Type,
context: JsonSerializationContext
): JsonElement {
return src.toJson()
}
override fun deserialize(
json: JsonElement,
typeOfT: Type,
context: JsonDeserializationContext
): AbstractSkinElement {
return fromJson(json)
}
fun toNetwork(buff: FriendlyByteBuf) {
type.toActualNetwork(this, buff)
}
}

View File

@ -27,7 +27,9 @@ import java.lang.reflect.Type
import java.util.stream.Stream
class AtlasSkinElement(
val location: ResourceLocation
val location: ResourceLocation,
override val width: Float,
override val height: Float,
) : AbstractSkinElement() {
init {
synchronized(keys) {
@ -46,7 +48,7 @@ class AtlasSkinElement(
check(isClient) { "Invalid realm" }
val _textureAtlasSprite = _textureAtlasSprite
if (_textureAtlasSprite == null || changeset != WidgetAtlasHolder.INSTANCE.changeset || (WidgetAtlasHolder.INSTANCE.demandsRebuild && isClientThread())) {
if (_textureAtlasSprite == null || _textureAtlasSprite.name.let { it.namespace == "minecraft" && it.path == "missingno" } || changeset != WidgetAtlasHolder.INSTANCE.changeset || WidgetAtlasHolder.INSTANCE.speculateIfMinecraftEngineIsDumDum()) {
val get = WidgetAtlasHolder.INSTANCE.getSprite(location)
this._textureAtlasSprite = get
changeset = WidgetAtlasHolder.INSTANCE.changeset
@ -61,11 +63,6 @@ class AtlasSkinElement(
return textureAtlasSpriteImpl
}
override val x get() = textureAtlasSprite.x.toFloat()
override val y get() = textureAtlasSprite.y.toFloat()
override val width get() = textureAtlasSprite.width.toFloat()
override val height get() = textureAtlasSprite.height.toFloat()
override val u0 get() = textureAtlasSprite.u0
override val v0 get() = textureAtlasSprite.v0
override val u1 get() = textureAtlasSprite.u1
@ -87,15 +84,10 @@ class AtlasSkinElement(
return "AtlasSkinElement[$location]"
}
override fun toJson(): JsonElement {
return JsonPrimitive(location.toString())
}
override val type: SkinElementType
get() = SkinElementType.ATLAS
override fun toNetwork(buff: FriendlyByteBuf) {
buff.writeResourceLocation(location)
}
companion object : TypeAdapter<AtlasSkinElement>(), JsonSerializer<AtlasSkinElement>, JsonDeserializer<AtlasSkinElement> {
companion object {
private val keys = HashSet<ResourceLocation>()
val keysStream: Stream<ResourceLocation> get() = keys.stream()
@ -103,38 +95,6 @@ class AtlasSkinElement(
WidgetAtlasHolder.INSTANCE.queueRebuild()
}
fun fromNetwork(buff: FriendlyByteBuf): AtlasSkinElement {
return AtlasSkinElement(buff.readResourceLocation())
}
fun fromJson(element: JsonElement): AtlasSkinElement {
return AtlasSkinElement(ResourceLocation.tryParse(element.asString) ?: ResourceLocation("missing"))
}
override fun write(out: JsonWriter, value: AtlasSkinElement) {
TypeAdapters.JSON_ELEMENT.write(out, value.toJson())
}
override fun read(`in`: JsonReader): AtlasSkinElement {
return fromJson(TypeAdapters.JSON_ELEMENT.read(`in`))
}
override fun serialize(
src: AtlasSkinElement,
typeOfSrc: Type,
context: JsonSerializationContext
): JsonElement {
return src.toJson()
}
override fun deserialize(
json: JsonElement,
typeOfT: Type,
context: JsonDeserializationContext
): AtlasSkinElement {
return fromJson(json)
}
val renderTypeGUI by lazy {
val builder = RenderType.CompositeState.builder()

View File

@ -36,28 +36,28 @@ object ResearchIcons {
init {
var i = 0
ICON_TRANSFER = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_ATTACK_BOOST = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_PLASMA_SHIELD_BOOST = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_CLOAK = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_GRAVITATIONAL_STABILIZER = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_AIR_BAGS = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_JUMP_BOOST = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_FEATHER_FALLING = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_ITEM_MAGNET = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_ARROW = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_ARMOR = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_NANOBOTS = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_NIGHT_VISION = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_OXYGEN_SUPPLY = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_PLASMA_SHIELD = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_SHOCKWAVE = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_LIMB_OVERCLOCKING = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_STEP_ASSIST = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_ENDER_TELEPORT = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_WIRELESS_CHARGING = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_UNKNOWN = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_EXTENDED_REACH = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_PHANTOM_ATTRACTOR = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"))
ICON_TRANSFER = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_ATTACK_BOOST = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_PLASMA_SHIELD_BOOST = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_CLOAK = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_GRAVITATIONAL_STABILIZER = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_AIR_BAGS = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_JUMP_BOOST = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_FEATHER_FALLING = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_ITEM_MAGNET = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_ARROW = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_ARMOR = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_NANOBOTS = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_NIGHT_VISION = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_OXYGEN_SUPPLY = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_PLASMA_SHIELD = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_SHOCKWAVE = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_LIMB_OVERCLOCKING = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_STEP_ASSIST = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_ENDER_TELEPORT = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_WIRELESS_CHARGING = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_UNKNOWN = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_EXTENDED_REACH = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
ICON_PHANTOM_ATTRACTOR = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research/android_stuff-${i++}"), 18f, 18f)
}
}

View File

@ -52,91 +52,14 @@ fun ResourceLocation.vLine(
@Suppress("unused")
data class SkinElement @JvmOverloads constructor(
override val texture: ResourceLocation,
override val x: Float,
override val y: Float,
val x: Float,
val y: Float,
override val width: Float,
override val height: Float,
val imageWidth: Float = 256f,
val imageHeight: Float = 256f,
override val winding: UVWindingOrder = UVWindingOrder.NORMAL,
) : AbstractSkinElement() {
override fun toJson(): JsonObject {
return JsonObject().also {
it["texture"] = JsonPrimitive(texture.toString())
it["x"] = JsonPrimitive(x)
it["y"] = JsonPrimitive(y)
it["width"] = JsonPrimitive(width)
it["height"] = JsonPrimitive(height)
it["imageWidth"] = JsonPrimitive(imageWidth)
it["imageHeight"] = JsonPrimitive(imageHeight)
it["winding"] = JsonPrimitive(winding.name)
}
}
override fun toNetwork(buff: FriendlyByteBuf) {
buff.writeUtf(texture.toString())
buff.writeFloat(x)
buff.writeFloat(y)
buff.writeFloat(width)
buff.writeFloat(height)
buff.writeFloat(imageWidth)
buff.writeFloat(imageHeight)
buff.writeEnum(winding)
}
companion object : TypeAdapter<SkinElement>(), JsonSerializer<SkinElement>, JsonDeserializer<SkinElement> {
fun fromNetwork(buff: FriendlyByteBuf): SkinElement {
val texture = ResourceLocation(buff.readUtf())
val x = buff.readFloat()
val y = buff.readFloat()
val width = buff.readFloat()
val height = buff.readFloat()
val imageWidth = buff.readFloat()
val imageHeight = buff.readFloat()
val winding = buff.readEnum(UVWindingOrder::class.java)
return SkinElement(texture, x, y, width, height, imageWidth, imageHeight, winding)
}
fun fromJson(value: JsonObject): SkinElement {
val texture = value["texture"]?.asString ?: throw JsonSyntaxException("Missing texture element")
val x = value["x"]?.asFloat ?: throw JsonSyntaxException("Missing x element")
val y = value["y"]?.asFloat ?: throw JsonSyntaxException("Missing y element")
val width = value["width"]?.asFloat ?: throw JsonSyntaxException("Missing width element")
val height = value["height"]?.asFloat ?: throw JsonSyntaxException("Missing height element")
val imageWidth = value["imageWidth"]?.asFloat ?: throw JsonSyntaxException("Missing imageWidth element")
val imageHeight = value["imageHeight"]?.asFloat ?: throw JsonSyntaxException("Missing imageHeight element")
val winding = value["winding"]?.asString ?: throw JsonSyntaxException("Missing winding element")
return SkinElement(ResourceLocation(texture), x, y, width, height, imageWidth, imageHeight, UVWindingOrder.valueOf(winding))
}
fun fromJson(value: JsonElement): SkinElement {
return fromJson(value as? JsonObject ?: throw JsonSyntaxException("Expected JsonObject, got ${value::class.qualifiedName}"))
}
override fun write(out: JsonWriter, value: SkinElement) {
TypeAdapters.JSON_ELEMENT.write(out, value.toJson())
}
override fun read(reader: JsonReader): SkinElement {
val read = TypeAdapters.JSON_ELEMENT.read(reader)
return fromJson(read as? JsonObject ?: throw JsonSyntaxException("Expected JsonObject, got ${read::class.qualifiedName}"))
}
override fun serialize(src: SkinElement, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
return src.toJson()
}
override fun deserialize(
json: JsonElement,
typeOfT: Type,
context: JsonDeserializationContext
): SkinElement {
return fromJson(json as? JsonObject ?: throw JsonSyntaxException("Expected JsonObject, got ${json::class.qualifiedName}"))
}
}
init {
require(x >= 0f) { "Invalid x $x" }
require(y >= 0f) { "Invalid y $y" }
@ -150,4 +73,7 @@ data class SkinElement @JvmOverloads constructor(
override val v0 = this.y / imageHeight
override val u1 = (this.x + width) / imageWidth
override val v1 = (this.y + height) / imageHeight
override val type: SkinElementType
get() = SkinElementType.SINGLE
}

View File

@ -0,0 +1,172 @@
package ru.dbotthepony.mc.otm.client.render
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import com.google.gson.JsonSyntaxException
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import ru.dbotthepony.mc.otm.core.set
enum class SkinElementType {
SINGLE {
override fun toJson(value: AbstractSkinElement): JsonObject {
require(value is SkinElement) { "Invalid skin element provided, expected SkinElement, got ${value::class.qualifiedName}" }
return JsonObject().also {
it["texture"] = JsonPrimitive(value.texture.toString())
it["x"] = JsonPrimitive(value.x)
it["y"] = JsonPrimitive(value.y)
it["width"] = JsonPrimitive(value.width)
it["height"] = JsonPrimitive(value.height)
it["imageWidth"] = JsonPrimitive(value.imageWidth)
it["imageHeight"] = JsonPrimitive(value.imageHeight)
it["winding"] = JsonPrimitive(value.winding.name)
}
}
override fun toNetwork(value: AbstractSkinElement, buff: FriendlyByteBuf) {
require(value is SkinElement) { "Invalid skin element provided, expected SkinElement, got ${value::class.qualifiedName}" }
buff.writeUtf(value.texture.toString())
buff.writeFloat(value.x)
buff.writeFloat(value.y)
buff.writeFloat(value.width)
buff.writeFloat(value.height)
buff.writeFloat(value.imageWidth)
buff.writeFloat(value.imageHeight)
buff.writeEnum(value.winding)
}
override fun fromNetwork(buff: FriendlyByteBuf): AbstractSkinElement {
val texture = ResourceLocation(buff.readUtf())
val x = buff.readFloat()
val y = buff.readFloat()
val width = buff.readFloat()
val height = buff.readFloat()
val imageWidth = buff.readFloat()
val imageHeight = buff.readFloat()
val winding = buff.readEnum(UVWindingOrder::class.java)
return SkinElement(texture, x, y, width, height, imageWidth, imageHeight, winding)
}
override fun fromJson(element: JsonObject): AbstractSkinElement {
val texture = element["texture"]?.asString ?: throw JsonSyntaxException("Missing texture element")
val x = element["x"]?.asFloat ?: throw JsonSyntaxException("Missing x element")
val y = element["y"]?.asFloat ?: throw JsonSyntaxException("Missing y element")
val width = element["width"]?.asFloat ?: throw JsonSyntaxException("Missing width element")
val height = element["height"]?.asFloat ?: throw JsonSyntaxException("Missing height element")
val imageWidth = element["imageWidth"]?.asFloat ?: throw JsonSyntaxException("Missing imageWidth element")
val imageHeight = element["imageHeight"]?.asFloat ?: throw JsonSyntaxException("Missing imageHeight element")
val winding = element["winding"]?.asString ?: throw JsonSyntaxException("Missing winding element")
return SkinElement(ResourceLocation.tryParse(texture) ?: throw JsonSyntaxException("Invalid resource location: $texture"), x, y, width, height, imageWidth, imageHeight, UVWindingOrder.valueOf(winding))
}
},
ATLAS {
override fun toJson(value: AbstractSkinElement): JsonObject {
require(value is AtlasSkinElement) { "Invalid skin element provided, expected AtlasSkinElement, got ${value::class.qualifiedName}" }
return JsonObject().also {
it["location"] = JsonPrimitive(value.location.toString())
it["width"] = JsonPrimitive(value.width)
it["height"] = JsonPrimitive(value.height)
}
}
override fun toNetwork(value: AbstractSkinElement, buff: FriendlyByteBuf) {
require(value is AtlasSkinElement) { "Invalid skin element provided, expected AtlasSkinElement, got ${value::class.qualifiedName}" }
buff.writeResourceLocation(value.location)
buff.writeFloat(value.width)
buff.writeFloat(value.height)
}
override fun fromNetwork(buff: FriendlyByteBuf): AbstractSkinElement {
val location = ResourceLocation(buff.readUtf())
val width = buff.readFloat()
val height = buff.readFloat()
return AtlasSkinElement(location, width, height)
}
override fun fromJson(element: JsonObject): AbstractSkinElement {
val location = element["location"]?.asString ?: throw JsonSyntaxException("Missing location element")
val width = element["width"]?.asFloat ?: throw JsonSyntaxException("Missing width element")
val height = element["height"]?.asFloat ?: throw JsonSyntaxException("Missing height element")
return AtlasSkinElement(ResourceLocation.tryParse(location) ?: throw JsonSyntaxException("Invalid resource location: $location"), width, height)
}
},
SUBELEMENT {
override fun toJson(value: AbstractSkinElement): JsonObject {
require(value is SubSkinElement) { "Invalid skin element provided, expected SubSkinElement, got ${value::class.qualifiedName}" }
return JsonObject().also {
it["parent"] = value.parent.toJson()
it["xOffset"] = JsonPrimitive(value.xOffset)
it["yOffset"] = JsonPrimitive(value.yOffset)
it["subWidth"] = JsonPrimitive(value.subWidth)
it["subHeight"] = JsonPrimitive(value.subHeight)
}
}
override fun toNetwork(value: AbstractSkinElement, buff: FriendlyByteBuf) {
require(value is SubSkinElement) { "Invalid skin element provided, expected SubSkinElement, got ${value::class.qualifiedName}" }
value.parent.toNetwork(buff)
buff.writeFloat(value.xOffset)
buff.writeFloat(value.yOffset)
buff.writeFloat(value.subWidth)
buff.writeFloat(value.subHeight)
}
override fun fromNetwork(buff: FriendlyByteBuf): AbstractSkinElement {
val parent = fromNetwork(buff)
val xOffset = buff.readFloat()
val yOffset = buff.readFloat()
val subWidth = buff.readFloat()
val subHeight = buff.readFloat()
return SubSkinElement(parent, xOffset, yOffset, subWidth, subHeight)
}
override fun fromJson(element: JsonObject): AbstractSkinElement {
val parent = element["parent"] as? JsonObject ?: throw JsonSyntaxException("Invalid parent")
val xOffset = element["xOffset"].asFloat
val yOffset = element["yOffset"].asFloat
val subWidth = element["subWidth"].asFloat
val subHeight = element["subHeight"].asFloat
return SubSkinElement(fromJson(parent), xOffset, yOffset, subWidth, subHeight)
}
};
protected abstract fun toJson(value: AbstractSkinElement): JsonObject
protected abstract fun toNetwork(value: AbstractSkinElement, buff: FriendlyByteBuf)
protected abstract fun fromNetwork(buff: FriendlyByteBuf): AbstractSkinElement
protected abstract fun fromJson(element: JsonObject): AbstractSkinElement
fun toActualJson(value: AbstractSkinElement): JsonObject {
return toJson(value).also {
it["type"] = JsonPrimitive(name)
}
}
fun toActualNetwork(value: AbstractSkinElement, buff: FriendlyByteBuf) {
buff.writeEnum(this)
toNetwork(value, buff)
}
companion object {
fun fromNetwork(buff: FriendlyByteBuf): AbstractSkinElement {
val type = buff.readEnum(SkinElementType::class.java)
return type.fromNetwork(buff)
}
fun fromJson(element: JsonObject): AbstractSkinElement {
val type = SkinElementType.valueOf(element["type"].asString)
return type.fromJson(element)
}
}
}

View File

@ -0,0 +1,39 @@
package ru.dbotthepony.mc.otm.client.render
import net.minecraft.resources.ResourceLocation
class SubSkinElement(
val parent: AbstractSkinElement,
val xOffset: Float = 0f,
val yOffset: Float = 0f,
val subWidth: Float = parent.width,
val subHeight: Float = parent.height,
) : AbstractSkinElement() {
override val width: Float
get() = subWidth
override val height: Float
get() = subHeight
override val u0: Float
get() = parent.u0 + (xOffset / parent.width) * (parent.u1 - parent.u0)
override val v0: Float
get() = parent.v0 + (yOffset / parent.height) * (parent.v1 - parent.v0)
override val u1: Float
get() = parent.u1 + ((xOffset + subWidth) / parent.width) * (parent.u1 - parent.u0)
override val v1: Float
get() = parent.v1 + ((yOffset + subHeight) / parent.height) * (parent.v1 - parent.v0)
override val texture: ResourceLocation
get() = parent.texture
override val type: SkinElementType
get() = SkinElementType.SUBELEMENT
}
fun AbstractSkinElement.subElement(
x: Float = 0f,
y: Float = 0f,
width: Float = this.width,
height: Float = this.height,
) = SubSkinElement(this, x, y, width, height)

View File

@ -28,6 +28,10 @@ class WidgetAtlasHolder private constructor(manager: TextureManager) : TextureAt
private set
var demandsRebuild = false
private set
var demandsRebuildAt = 0L
private set
var dirtyUntil = 0L
private set
private var resourceManager by Delegates.notNull<ResourceManager>()
private var profileManager by Delegates.notNull<ProfilerFiller>()
@ -38,23 +42,46 @@ class WidgetAtlasHolder private constructor(manager: TextureManager) : TextureAt
resourceManager = p_118891_
profileManager = p_118892_
changeset++
dirtyUntil = System.nanoTime() + 1_000_000_000L
return super.prepare(p_118891_, p_118892_)
}
override fun apply(p_118894_: TextureAtlas.Preparations, p_118895_: ResourceManager, p_118896_: ProfilerFiller) {
once = true
demandsRebuild = false
resourceManager = p_118895_
profileManager = p_118896_
changeset++
dirtyUntil = System.nanoTime() + 1_000_000_000L
super.apply(p_118894_, p_118895_, p_118896_)
}
fun rebuildIfRequired(): Boolean {
if (once && demandsRebuild && demandsRebuildAt <= System.nanoTime() && isClientThread()) {
apply(prepare(resourceManager, profileManager), resourceManager, profileManager)
}
return demandsRebuild
}
fun speculateIfMinecraftEngineIsDumDum(): Boolean {
return demandsRebuild || dirtyUntil >= System.nanoTime()
}
public override fun getSprite(p_118902_: ResourceLocation): TextureAtlasSprite {
if (!once) {
throw IllegalStateException("Trying to get sprite too early")
}
if (demandsRebuild && isClientThread()) {
apply(prepare(resourceManager, profileManager), resourceManager, profileManager)
}
rebuildIfRequired()
return super.getSprite(p_118902_)
}
fun queueRebuild() {
if (!demandsRebuild) {
demandsRebuild = true
demandsRebuildAt = System.nanoTime() + 1_000_000_000L
}
}
override fun getResourcesToLoad(): Stream<ResourceLocation> {

View File

@ -5,6 +5,7 @@ import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.client.render.AtlasSkinElement
import ru.dbotthepony.mc.otm.client.render.WidgetLocation
import ru.dbotthepony.mc.otm.client.render.element
import ru.dbotthepony.mc.otm.client.render.subElement
object ScrollBarConstants {
const val WIDTH = 14f
@ -12,21 +13,24 @@ object ScrollBarConstants {
const val TEXTURE_WIDTH = 22f
const val TEXTURE_HEIGHT = 68f
val TOP = WidgetLocation.SCROLL.element(0f, 45f, 14f, 2f, TEXTURE_WIDTH, TEXTURE_HEIGHT)
val BODY = WidgetLocation.SCROLL.element(0f, 46f, 14f, 6f, TEXTURE_WIDTH, TEXTURE_HEIGHT)
val BOTTOM = WidgetLocation.SCROLL.element(0f, 51f, 14f, 2f, TEXTURE_WIDTH, TEXTURE_HEIGHT)
val BACKGROUND = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar/background"), 14f, 8f)
val BACKGROUND_SLIM = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar_slim/background"), 8f, 8f)
val BUTTON = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar/idle"))
val BUTTON_HOVER = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar/hovered"))
val BUTTON_PRESS = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar/pressed"))
val BUTTON_DISABLED = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar/disabled"))
val TOP = BACKGROUND.subElement(height = 2f)
val BODY = BACKGROUND.subElement(x = 2f, height = 6f)
val BOTTOM = BACKGROUND.subElement(x = 7f, height = 2f)
val SLIM_TOP = WidgetLocation.SCROLL.element(14f, 45f, 8f, 2f, TEXTURE_WIDTH, TEXTURE_HEIGHT)
val SLIM_BODY = WidgetLocation.SCROLL.element(14f, 46f, 8f, 6f, TEXTURE_WIDTH, TEXTURE_HEIGHT)
val SLIM_BOTTOM = WidgetLocation.SCROLL.element(14f, 51f, 8f, 2f, TEXTURE_WIDTH, TEXTURE_HEIGHT)
val BUTTON = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar/idle"), 12f, 15f)
val BUTTON_HOVER = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar/hovered"), 12f, 15f)
val BUTTON_PRESS = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar/pressed"), 12f, 15f)
val BUTTON_DISABLED = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar/disabled"), 12f, 15f)
val SLIM_BUTTON = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar_slim/idle"))
val SLIM_BUTTON_HOVER = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar_slim/hovered"))
val SLIM_BUTTON_PRESS = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar_slim/pressed"))
val SLIM_BUTTON_DISABLED = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar_slim/disabled"))
val SLIM_TOP = BACKGROUND_SLIM.subElement(height = 2f)
val SLIM_BODY = BACKGROUND_SLIM.subElement(x = 2f, height = 6f)
val SLIM_BOTTOM = BACKGROUND_SLIM.subElement(x = 7f, height = 2f)
val SLIM_BUTTON = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar_slim/idle"), 6f, 15f)
val SLIM_BUTTON_HOVER = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar_slim/hovered"), 6f, 15f)
val SLIM_BUTTON_PRESS = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar_slim/pressed"), 6f, 15f)
val SLIM_BUTTON_DISABLED = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "widgets/scrollbar_slim/disabled"), 6f, 15f)
}