Iterate IGUIRenderable, update panels to accept IGUIRenderable where applicable

This commit is contained in:
DBotThePony 2023-07-08 02:15:09 +07:00
parent f9c1258afe
commit b957378c60
Signed by: DBot
GPG Key ID: DCC23B5715498507
8 changed files with 126 additions and 69 deletions

View File

@ -22,13 +22,13 @@ sealed class AbstractMatterySprite : IGUIRenderable {
* Expected image width in pixels, used in calculations
* and as default width argument in render methods
*/
abstract val width: Float
abstract override val width: Float
/**
* Expected image height in pixels, used in calculations
* and as default height argument in render methods
*/
abstract val height: Float
abstract override val height: Float
abstract val u0: Float
abstract val v0: Float
@ -45,7 +45,7 @@ sealed class AbstractMatterySprite : IGUIRenderable {
abstract val type: SpriteType
open val winding: UVWindingOrder get() = UVWindingOrder.NORMAL
override val winding: UVWindingOrder get() = UVWindingOrder.NORMAL
abstract val texture: ResourceLocation
@ -76,23 +76,19 @@ sealed class AbstractMatterySprite : IGUIRenderable {
renderRaw(stack, x, y, width, height, winding)
}
fun render(
graphics: GuiGraphics,
x: Float = 0f,
y: Float = 0f,
width: Float = this.width,
height: Float = this.height,
winding: UVWindingOrder = this.winding
override fun render(
guiGraphics: GuiGraphics,
x: Float,
y: Float,
width: Float,
height: Float,
winding: UVWindingOrder
) {
render(graphics.pose(), x, y, width, height, winding)
render(guiGraphics.pose(), x, y, width, height, winding)
}
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, width: Float, height: Float) {
return render(guiGraphics, x, y, width, height, winding)
}
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, gravity: RenderGravity) {
return render(guiGraphics, gravity.x(x, width), gravity.y(y, height), width, height, winding)
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, gravity: RenderGravity, winding: UVWindingOrder) {
render(guiGraphics.pose(), x, y, width, height, winding)
}
@JvmOverloads

View File

@ -4,23 +4,40 @@ import net.minecraft.client.gui.GuiGraphics
import net.minecraft.world.item.ItemStack
interface IGUIRenderable {
fun render(guiGraphics: GuiGraphics, x: Float, y: Float, gravity: RenderGravity = RenderGravity.TOP_LEFT)
/**
* Expected width of this gui element, in pixels
*/
val width: Float
/**
* Render at specified [x], [y] with fixed [width] x [height]
* Expected height of this gui element, in pixels
*/
fun render(guiGraphics: GuiGraphics, x: Float, y: Float, width: Float, height: Float)
val height: Float
/**
* Utilized only for purpose of default argument
*/
val winding: UVWindingOrder get() = UVWindingOrder.NORMAL
fun render(guiGraphics: GuiGraphics, x: Float = 0f, y: Float = 0f, gravity: RenderGravity = RenderGravity.TOP_LEFT, winding: UVWindingOrder = this.winding) {
render(guiGraphics, gravity.x(x, width), gravity.y(y, height), width, height, winding)
}
/**
* Render at specified position [x], [y] with size of [width] x [height], optionally with UV [winding], if we are rendering flat texture/sprite
*/
fun render(guiGraphics: GuiGraphics, x: Float = 0f, y: Float = 0f, width: Float = this.width, height: Float = this.height, winding: UVWindingOrder = this.winding)
fun composeBefore(other: IGUIRenderable): IGUIRenderable {
return object : IGUIRenderable {
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, gravity: RenderGravity) {
this@IGUIRenderable.render(guiGraphics, x, y, gravity)
other.render(guiGraphics, x, y, gravity)
}
override val width: Float
get() = this@IGUIRenderable.width.coerceAtLeast(other.width)
override val height: Float
get() = this@IGUIRenderable.height.coerceAtLeast(other.height)
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, width: Float, height: Float) {
this@IGUIRenderable.render(guiGraphics, x, y, width, height)
other.render(guiGraphics, x, y, width, height)
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, width: Float, height: Float, winding: UVWindingOrder) {
this@IGUIRenderable.render(guiGraphics, x, y, width, height, winding)
other.render(guiGraphics, x, y, width, height, winding)
}
}
}
@ -29,6 +46,53 @@ interface IGUIRenderable {
return other.composeBefore(this)
}
fun padded(left: Float, top: Float, right: Float, bottom: Float): IGUIRenderable {
return object : IGUIRenderable {
override val width: Float
get() = this@IGUIRenderable.width
override val height: Float
get() = this@IGUIRenderable.height
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, width: Float, height: Float, winding: UVWindingOrder) {
this@IGUIRenderable.render(guiGraphics, x + left, y + top, width + right + left, height + bottom + top, winding)
}
}
}
/**
* Locks argument values to default ones and aligns render position to center of render rectangle
*
* e.g. for example, if we want [ItemStackIcon] to always render as 16x16 pixels icon, even if required render
* dimensions are bigger (e.g. 18x18), after calling [fix] on [ItemStackIcon] it will always render as 16x16 icon,
* positioned on center of render canvas (e.g. rendering on +0+0 with 18x18 size will put icon at +1+1 and render as 16x16;
* rendering on +0+0 with 32x32 canvas will put icon at +8+8 and render as 16x16)
*/
fun fixed(fixedWidth: Boolean = true, fixedHeight: Boolean = true, fixedWinding: Boolean = true): IGUIRenderable {
if (!fixedHeight && !fixedWidth && !fixedWinding) return this
return object : IGUIRenderable {
override val width: Float
get() = this@IGUIRenderable.width
override val height: Float
get() = this@IGUIRenderable.height
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, width: Float, height: Float, winding: UVWindingOrder) {
var realX = x
var realY = y
if (fixedWidth && width > this.width) {
realX += (width - this.width) / 2f
}
if (fixedHeight && height > this.height) {
realY += (height - this.height) / 2f
}
this@IGUIRenderable.render(guiGraphics, realX, realY, if (fixedWidth) this.width else width, if (fixedHeight) this.height else height, if (fixedWinding) this.winding else winding)
}
}
}
companion object {
fun of(value: ItemStack, width: Float = 16f, height: Float = 16f): IGUIRenderable {
return ItemStackIcon(value, width, height)
@ -40,12 +104,8 @@ interface IGUIRenderable {
}
}
data class ItemStackIcon(private val itemStack: ItemStack, val width: Float = 16f, val height: Float = 16f) : IGUIRenderable {
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, gravity: RenderGravity) {
return render(guiGraphics, gravity.x(x, width), gravity.y(y, height), width, height)
}
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, width: Float, height: Float) {
data class ItemStackIcon(private val itemStack: ItemStack, override val width: Float = 16f, override val height: Float = 16f) : IGUIRenderable {
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, width: Float, height: Float, winding: UVWindingOrder) {
if (x % 1f == 0f && y % 1f == 0f && width == 16f && height == 16f) {
guiGraphics.renderFakeItem(itemStack, x.toInt(), y.toInt())
clearDepth(guiGraphics.pose(), x, y, width, height)

View File

@ -1,12 +1,11 @@
package ru.dbotthepony.mc.otm.client.screen.panels.button
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.ChatFormatting
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.render.AbstractMatterySprite
import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.core.GetterSetter
import ru.dbotthepony.mc.otm.core.TextComponent
@ -21,8 +20,8 @@ abstract class BooleanRectangleButtonPanel<out S : Screen>(
width: Float,
height: Float,
val prop: GetterSetter<Boolean>,
var skinElementActive: AbstractMatterySprite? = null,
var skinElementInactive: AbstractMatterySprite? = null,
var skinElementActive: IGUIRenderable? = null,
var skinElementInactive: IGUIRenderable? = null,
val onChange: ((newValue: Boolean) -> Unit)? = null,
var tooltipActive: Component? = null,
var tooltipInactive: Component? = null,

View File

@ -4,6 +4,8 @@ import com.mojang.blaze3d.platform.InputConstants
import net.minecraft.ChatFormatting
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting
import ru.dbotthepony.mc.otm.capability.FlowDirection
@ -12,6 +14,7 @@ import ru.dbotthepony.mc.otm.client.isCtrlDown
import ru.dbotthepony.mc.otm.client.isShiftDown
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.render.AbstractMatterySprite
import ru.dbotthepony.mc.otm.client.render.ItemStackIcon
import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.client.screen.panels.Dock
@ -21,6 +24,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
import ru.dbotthepony.mc.otm.config.ClientConfig
import ru.dbotthepony.mc.otm.core.GetterSetter
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
@ -36,6 +40,11 @@ import java.util.function.Predicate
import kotlin.math.ceil
import kotlin.math.pow
private val gunpowder = ItemStackIcon(ItemStack(Items.GUNPOWDER)).fixed()
private val barrier = ItemStackIcon(ItemStack(Items.BARRIER)).fixed()
private val redstone = ItemStackIcon(ItemStack(Items.REDSTONE)).fixed()
private val redstoneUnderBarrier = barrier.composeAfter(redstone).fixed()
private fun <S : MatteryScreen<*>> makeRedstoneSettingButton(
screen: S,
parent: EditablePanel<*>?,
@ -53,9 +62,9 @@ private fun <S : MatteryScreen<*>> makeRedstoneSettingButton(
set(value) {}
init {
add(RedstoneSetting.IGNORED, tooltip = RedstoneSetting.IGNORED.description, skinElement = Widgets18.REDSTONE_IGNORED)
add(RedstoneSetting.LOW, tooltip = RedstoneSetting.LOW.description, skinElement = Widgets18.REDSTONE_LOW)
add(RedstoneSetting.HIGH, tooltip = RedstoneSetting.HIGH.description, skinElement = Widgets18.REDSTONE_HIGH)
add(RedstoneSetting.IGNORED, tooltip = RedstoneSetting.IGNORED.description, skinElement = if (ClientConfig.REDSTONE_CONTROLS_ITEM_ICONS) gunpowder else Widgets18.REDSTONE_IGNORED)
add(RedstoneSetting.LOW, tooltip = RedstoneSetting.LOW.description, skinElement = if (ClientConfig.REDSTONE_CONTROLS_ITEM_ICONS) redstoneUnderBarrier else Widgets18.REDSTONE_LOW)
add(RedstoneSetting.HIGH, tooltip = RedstoneSetting.HIGH.description, skinElement = if (ClientConfig.REDSTONE_CONTROLS_ITEM_ICONS) redstone else Widgets18.REDSTONE_HIGH)
}
}
}

View File

@ -8,6 +8,7 @@ import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.render.AbstractMatterySprite
import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.core.GetterSetter
@ -49,14 +50,14 @@ abstract class EnumRectangleButtonPanel<out S : Screen, T : Enum<T>>(
data class Entry<T : Enum<T>>(
val key: T,
val skinElement: AbstractMatterySprite?,
val skinElement: IGUIRenderable?,
val winding: UVWindingOrder = UVWindingOrder.NORMAL,
val tooltip: Component? = null
)
protected val enumMapping = EnumMap<T, Entry<T>>(enum)
fun add(key: T, skinElement: AbstractMatterySprite? = null, tooltip: Component? = null, winding: UVWindingOrder = UVWindingOrder.NORMAL): EnumRectangleButtonPanel<S, T> {
fun add(key: T, skinElement: IGUIRenderable? = null, tooltip: Component? = null, winding: UVWindingOrder = UVWindingOrder.NORMAL): EnumRectangleButtonPanel<S, T> {
return add(Entry(key = key, skinElement = skinElement, winding = winding, tooltip = tooltip))
}

View File

@ -4,6 +4,7 @@ import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.screens.Screen
import ru.dbotthepony.mc.otm.client.render.AbstractMatterySprite
import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
@ -16,8 +17,8 @@ open class LargeRectangleButtonPanel<out S : Screen>(
width: Float = SIZE,
height: Float = SIZE,
onPress: ((clickButton: Int) -> Unit)? = null,
val skinElement: AbstractMatterySprite? = null,
val skinElementWinding: UVWindingOrder? = null,
var skinElement: IGUIRenderable? = null,
var skinElementWinding: UVWindingOrder? = null,
) : RectangleButtonPanel<S>(screen, parent, x, y, width, height, onPress) {
final override val IDLE = Widgets18.BUTTON_IDLE
final override val HOVERED = Widgets18.BUTTON_HOVERED
@ -28,7 +29,7 @@ open class LargeRectangleButtonPanel<out S : Screen>(
super.innerRender(graphics, mouseX, mouseY, partialTick)
if (skinElementWinding != null) {
skinElement?.render(graphics, width = width, height = height, winding = skinElementWinding)
skinElement?.render(graphics, width = width, height = height, winding = skinElementWinding!!)
} else {
skinElement?.render(graphics, width = width, height = height)
}

View File

@ -5,6 +5,7 @@ import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.screens.Screen
import ru.dbotthepony.mc.otm.client.playGuiClickSound
import ru.dbotthepony.mc.otm.client.render.AbstractMatterySprite
import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.core.TextComponent
import java.util.function.IntConsumer
@ -19,10 +20,10 @@ abstract class RectangleButtonPanel<out S : Screen>(
height: Float,
var onPress: IntConsumer? = null,
) : AbstractButtonPanel<S>(screen, parent, x, y, width, height) {
abstract val PRESSED: AbstractMatterySprite
abstract val HOVERED: AbstractMatterySprite
abstract val IDLE: AbstractMatterySprite
abstract val DISABLED: AbstractMatterySprite
abstract val PRESSED: IGUIRenderable
abstract val HOVERED: IGUIRenderable
abstract val IDLE: IGUIRenderable
abstract val DISABLED: IGUIRenderable
override fun onClick(mouseButton: Int) {
onPress?.accept(mouseButton)

View File

@ -4,38 +4,28 @@ import net.minecraftforge.common.ForgeConfigSpec
import net.minecraftforge.fml.ModLoadingContext
import net.minecraftforge.fml.config.ModConfig
object ClientConfig {
private val specBuilder = ForgeConfigSpec.Builder()
@Suppress("JoinDeclarationAndAssignment")
private val spec: ForgeConfigSpec
private var registered = false
var ALWAYS_DISPLAY_MATTER_VALUE: Boolean by specBuilder
object ClientConfig : AbstractConfig("client", ModConfig.Type.CLIENT) {
var ALWAYS_DISPLAY_MATTER_VALUE: Boolean by builder
.define("ALWAYS_DISPLAY_MATTER_VALUE", false)
var EXOPACK_INVENTORY_ROWS: Int by specBuilder
var EXOPACK_INVENTORY_ROWS: Int by builder
.comment("Amount of inventory rows to show when wearing Exosuit")
.defineInRange("EXOPACK_INVENTORY_ROWS", 3, 3, 6)
var JUMP_BOOST_LOOK_ANGLE: Double by specBuilder
var JUMP_BOOST_LOOK_ANGLE: Double by builder
.comment("If looking below this angle (actually, looking 'above' as you see in game, but not as you expect it, check with debug screen), Crouch + Jump will trigger jump boost android ability")
.defineInRange("JUMP_BOOST_LOOK_ANGLE", 30.0, -180.0, 180.0)
var EXOPACK_FREE_SCROLL: Boolean by specBuilder
var EXOPACK_FREE_SCROLL: Boolean by builder
.comment("Allow to scroll Exopack inventory in non OTM inventories when hovering just over inventory slots, not only scrollbar")
.define("EXOPACK_FREE_SCROLL", true)
var ANDROID_HEALTH_HUD: Boolean by specBuilder
var ANDROID_HEALTH_HUD: Boolean by builder
.comment("Replace hearts with health bar on HUD when you are an android")
.define("ANDROID_HEALTH_HUD", true)
init {
spec = specBuilder.build()
}
fun register() {
check(!registered) { "Already registered config" }
registered = true
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, spec)
}
var REDSTONE_CONTROLS_ITEM_ICONS: Boolean by builder
.comment("Display redstone control button using items instead of custom sprites")
.comment("For those who want it.")
.define("REDSTONE_CONTROLS_ITEM_ICONS", false)
}