From 3593dd8bbcf686fde86cf4548e227bcd54ba3020 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 31 Aug 2022 13:26:08 +0700 Subject: [PATCH] Wide power gauge --- .../mc/otm/client/render/SkinElement.kt | 27 ++++++++++ .../otm/client/screen/AndroidStationScreen.kt | 3 +- .../mc/otm/client/screen/BatteryBankScreen.kt | 3 +- .../client/screen/ChemicalGeneratorScreen.kt | 3 +- .../mc/otm/client/screen/DriveRackScreen.kt | 3 +- .../mc/otm/client/screen/PlatePressScreen.kt | 3 +- .../mc/otm/client/screen/StorageBusScreen.kt | 3 +- .../client/screen/StorageExporterScreen.kt | 3 +- .../client/screen/StorageImporterScreen.kt | 3 +- .../screen/StoragePowerSupplierScreen.kt | 3 +- .../otm/client/screen/panels/EditablePanel.kt | 2 + .../mc/otm/client/screen/widget/Gauges.kt | 47 +++++++++++++++--- .../textures/gui/widgets.png | Bin 3190 -> 3270 bytes .../textures/gui/widgets.xcf | 4 +- 14 files changed, 88 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/SkinElement.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/SkinElement.kt index d19f37b97..5d90523d8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/SkinElement.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/SkinElement.kt @@ -5,6 +5,7 @@ import com.mojang.blaze3d.vertex.PoseStack import net.minecraft.resources.ResourceLocation import ru.dbotthepony.mc.otm.client.screen.panels.DockProperty +@Suppress("unused") class SkinGrid( val texture: ResourceLocation, val width: Float, @@ -71,6 +72,23 @@ fun ResourceLocation.pixel( textureHeight: Float = 256f ) = SkinElement(this, x, y, 1f, 1f, textureWidth, textureHeight) +fun ResourceLocation.hLine( + x: Float, + y: Float, + width: Float, + textureWidth: Float = 256f, + textureHeight: Float = 256f +) = SkinElement(this, x, y, width, 1f, textureWidth, textureHeight) + +fun ResourceLocation.vLine( + x: Float, + y: Float, + height: Float, + textureWidth: Float = 256f, + textureHeight: Float = 256f +) = SkinElement(this, x, y, 1f, height, textureWidth, textureHeight) + +@Suppress("unused") class SkinElement @JvmOverloads constructor( val texture: ResourceLocation, val x: Float, @@ -80,6 +98,15 @@ class SkinElement @JvmOverloads constructor( val imageWidth: Float = 256f, val imageHeight: Float = 256f ) { + init { + require(x >= 0f) { "Invalid x $x" } + require(y >= 0f) { "Invalid y $y" } + require(w > 0f) { "Invalid width $w" } + require(h > 0f) { "Invalid height $h" } + require(imageWidth > 0f) { "Invalid image width $imageWidth" } + require(imageHeight > 0f) { "Invalid image height $imageHeight" } + } + @JvmOverloads fun render( stack: PoseStack, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/AndroidStationScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/AndroidStationScreen.kt index 67aaa490b..46231a05f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/AndroidStationScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/AndroidStationScreen.kt @@ -23,6 +23,7 @@ import ru.dbotthepony.mc.otm.client.render.drawLine import ru.dbotthepony.mc.otm.client.render.drawRect import ru.dbotthepony.mc.otm.client.screen.panels.* import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel import ru.dbotthepony.mc.otm.core.RGBAColor import ru.dbotthepony.mc.otm.ifPresentK import ru.dbotthepony.mc.otm.menu.AndroidStationMenu @@ -477,7 +478,7 @@ class AndroidStationScreen constructor(p_97741_: AndroidStationMenu, p_97742_: I override fun makeMainFrame(): FramePanel { val frame = super.makeMainFrame()!! - PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) + WidePowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) SlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) SlotPanel(this, frame, menu.androidBattery, 38f, 17f) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/BatteryBankScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/BatteryBankScreen.kt index 54ca80a92..6ea0a912f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/BatteryBankScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/BatteryBankScreen.kt @@ -6,6 +6,7 @@ import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel import ru.dbotthepony.mc.otm.client.screen.panels.SlotPanel import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel class BatteryBankScreen(menu: BatteryBankMenu, p_97742_: Inventory, p_97743_: Component) : MatteryScreen(menu, p_97742_, p_97743_) { @@ -13,7 +14,7 @@ class BatteryBankScreen(menu: BatteryBankMenu, p_97742_: Inventory, p_97743_: Co override fun makeMainFrame(): FramePanel{ val frame = super.makeMainFrame()!! - PowerGaugePanel(this, frame, menu.powerLevel, LEFT_MARGIN, GAUGE_TOP_WITHOUT_SLOT) + WidePowerGaugePanel(this, frame, menu.powerLevel, LEFT_MARGIN, GAUGE_TOP_WITHOUT_SLOT) for (i in 0 .. 5) SlotPanel(this, frame, menu.storageSlots[i], 44f + 18 * i, 32f) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ChemicalGeneratorScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ChemicalGeneratorScreen.kt index 0583d109f..a07cda9fc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ChemicalGeneratorScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ChemicalGeneratorScreen.kt @@ -6,13 +6,14 @@ import ru.dbotthepony.mc.otm.TranslatableComponent import ru.dbotthepony.mc.otm.client.screen.panels.* import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel import ru.dbotthepony.mc.otm.menu.ChemicalGeneratorMenu class ChemicalGeneratorScreen(menu: ChemicalGeneratorMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { override fun makeMainFrame(): FramePanel { val frame = super.makeMainFrame()!! - PowerGaugePanel(this, frame, menu.energy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) + WidePowerGaugePanel(this, frame, menu.energy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) SlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) val self = this diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/DriveRackScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/DriveRackScreen.kt index 3607e856c..b36a6a69c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/DriveRackScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/DriveRackScreen.kt @@ -6,6 +6,7 @@ import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel import ru.dbotthepony.mc.otm.client.screen.panels.SlotPanel import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel class DriveRackScreen(menu: DriveRackMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { @@ -13,7 +14,7 @@ class DriveRackScreen(menu: DriveRackMenu, inventory: Inventory, title: Componen override fun makeMainFrame(): FramePanel { val frame = super.makeMainFrame()!! - PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) + WidePowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) SlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) SlotPanel(this, frame, menu.storageSlots[0], 71f, 32f) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/PlatePressScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/PlatePressScreen.kt index cf3fb4d4c..1ba015646 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/PlatePressScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/PlatePressScreen.kt @@ -6,6 +6,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel import ru.dbotthepony.mc.otm.client.screen.panels.SlotPanel import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel import ru.dbotthepony.mc.otm.menu.PlatePressMenu class PlatePressScreen(menu: PlatePressMenu, inventory: Inventory, title: Component) : @@ -13,7 +14,7 @@ class PlatePressScreen(menu: PlatePressMenu, inventory: Inventory, title: Compon override fun makeMainFrame(): FramePanel { val frame = super.makeMainFrame()!! - PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) + WidePowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) SlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) SlotPanel(this, frame, menu.inputSlot, 56f, PROGRESS_SLOT_TOP) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StorageBusScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StorageBusScreen.kt index 7a15af8f4..845d3d43a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StorageBusScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StorageBusScreen.kt @@ -8,6 +8,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.FilterSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel import ru.dbotthepony.mc.otm.client.screen.panels.SlotPanel import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel import ru.dbotthepony.mc.otm.menu.StorageBusMenu @@ -16,7 +17,7 @@ class StorageBusScreen(menu: StorageBusMenu, inventory: Inventory, title: Compon override fun makeMainFrame(): FramePanel { val frame = super.makeMainFrame()!! - PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) + WidePowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) SlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) for (row in 0 .. 2) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StorageExporterScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StorageExporterScreen.kt index d6db6c394..fc5b57dd1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StorageExporterScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StorageExporterScreen.kt @@ -8,6 +8,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.FilterSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel import ru.dbotthepony.mc.otm.client.screen.panels.SlotPanel import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel import ru.dbotthepony.mc.otm.menu.StorageExporterMenu @@ -16,7 +17,7 @@ class StorageExporterScreen(menu: StorageExporterMenu, inventory: Inventory, tit override fun makeMainFrame(): FramePanel { val frame = super.makeMainFrame()!! - PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) + WidePowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) SlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) for (row in 0 .. 2) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StorageImporterScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StorageImporterScreen.kt index ffd545cfd..997156713 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StorageImporterScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StorageImporterScreen.kt @@ -8,6 +8,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.FilterSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel import ru.dbotthepony.mc.otm.client.screen.panels.SlotPanel import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel import ru.dbotthepony.mc.otm.menu.StorageImporterMenu @@ -16,7 +17,7 @@ class StorageImporterScreen(menu: StorageImporterMenu, inventory: Inventory, tit override fun makeMainFrame(): FramePanel { val frame = super.makeMainFrame()!! - PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) + WidePowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) SlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) for (row in 0 .. 2) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StoragePowerSupplierScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StoragePowerSupplierScreen.kt index fbd4b9d60..057811411 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StoragePowerSupplierScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/StoragePowerSupplierScreen.kt @@ -5,6 +5,7 @@ import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.TranslatableComponent import ru.dbotthepony.mc.otm.client.screen.panels.* import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel import ru.dbotthepony.mc.otm.core.formatPower import ru.dbotthepony.mc.otm.menu.StoragePowerSupplierMenu @@ -14,7 +15,7 @@ class StoragePowerSupplierScreen(menu: StoragePowerSupplierMenu, inventory: Inve override fun makeMainFrame(): FramePanel { val frame = super.makeMainFrame()!! - PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) + WidePowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) SlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) object : Label(this@StoragePowerSupplierScreen, frame, 28f, 17f, width = 140f) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt index e1e0a4597..3938703bf 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt @@ -17,6 +17,8 @@ data class ScreenPos(val x: Float, val y: Float) @JvmRecord data class DockProperty @JvmOverloads constructor(val left: Float = 0f, val top: Float = 0f, val right: Float = 0f, val bottom: Float = 0f) { + val isEmpty get() = left == 0f && right == 0f && top == 0f && bottom == 0f + companion object { val EMPTY = DockProperty() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/Gauges.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/Gauges.kt index fc7901bce..649ccb3b1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/Gauges.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/Gauges.kt @@ -5,11 +5,8 @@ import com.mojang.blaze3d.vertex.PoseStack import net.minecraft.ChatFormatting import net.minecraft.network.chat.Component import ru.dbotthepony.mc.otm.TranslatableComponent -import ru.dbotthepony.mc.otm.client.render.SkinElement +import ru.dbotthepony.mc.otm.client.render.* import ru.dbotthepony.mc.otm.client.screen.MatteryScreen -import ru.dbotthepony.mc.otm.client.render.UVWindingOrder -import ru.dbotthepony.mc.otm.client.render.WidgetLocation -import ru.dbotthepony.mc.otm.client.render.element import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.core.formatMatterLevel import ru.dbotthepony.mc.otm.core.formatPowerLevel @@ -21,8 +18,10 @@ open class PowerGaugePanel @JvmOverloads constructor( parent: EditablePanel? = null, val widget: LevelGaugeWidget, x: Float = 0f, - y: Float = 0f -): EditablePanel(screen, parent, x, y, width = GAUGE_BACKGROUND.w, height = GAUGE_BACKGROUND.h) { + y: Float = 0f, + width: Float = 9f, + height: Float = 48f +) : EditablePanel(screen, parent, x, y, width, height) { init { scissor = true } @@ -35,9 +34,25 @@ open class PowerGaugePanel @JvmOverloads constructor( } override fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) { - GAUGE_BACKGROUND.render(stack) val height = this.height * widget.percentage() - GAUGE_FOREGROUND.renderPartial(stack, y = this.height - height, height = height, winding = UVWindingOrder.U0_V1_U1_V0) + + if (width >= 18f) { + GAUGE_BACKGROUND_WIDE.render(stack, width = width, height = this.height) + GAUGE_FOREGROUND_WIDE.renderPartial( + stack, + y = this.height - height, + height = height, + width = width, + winding = UVWindingOrder.U0_V1_U1_V0) + } else { + GAUGE_BACKGROUND.render(stack, width = width, height = this.height) + GAUGE_FOREGROUND.renderPartial( + stack, + y = this.height - height, + height = height, + width = width, + winding = UVWindingOrder.U0_V1_U1_V0) + } } override fun innerRenderTooltips(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float): Boolean { @@ -52,9 +67,25 @@ open class PowerGaugePanel @JvmOverloads constructor( companion object { val GAUGE_BACKGROUND = WidgetLocation.WIDGETS.element(x = 0f, y = 48f, w = 9f, h = 48f) val GAUGE_FOREGROUND = WidgetLocation.WIDGETS.element(x = 9f, y = 48f, w = 9f, h = 48f) + + val GAUGE_BACKGROUND_WIDE = WidgetLocation.WIDGETS.element(x = 238f, y = 0f, w = 18f, h = 48f) + val GAUGE_FOREGROUND_WIDE = WidgetLocation.WIDGETS.element(x = 220f, y = 0f, w = 18f, h = 48f) } } +/** + * Shortcut to [PowerGaugePanel] with doubled width + */ +fun WidePowerGaugePanel( + screen: MatteryScreen<*>, + parent: EditablePanel? = null, + widget: LevelGaugeWidget, + x: Float = 0f, + y: Float = 0f, + width: Float = 18f, + height: Float = 48f +) = PowerGaugePanel(screen, parent, widget, x, y, width, height) + open class MatterGaugePanel @JvmOverloads constructor( screen: MatteryScreen<*>, parent: EditablePanel? = null, diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets.png index 18d0611f3999f5c498a754170d8f9eecda269b95..8401ea7507420177e0839686c6759546241b76ef 100644 GIT binary patch literal 3270 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 JP-RC>`VaO1&ei|` literal 3190 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 b;gF?j!JG3#!zWY`8{@p(ecftZ@R$AzvRK