From f40863a821218938b8f53f17a4441ad5c973d0e3 Mon Sep 17 00:00:00 2001 From: Empa <42304516+ItsEmpa@users.noreply.github.com> Date: Sat, 7 Sep 2024 20:59:56 +0200 Subject: Feature: Personal Compactor Overlay (#1869) Co-authored-by: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> Co-authored-by: Cal Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Co-authored-by: ItsEmpa --- .../skyhanni/utils/renderables/Renderable.kt | 78 +++++++++++++- .../utils/renderables/RenderableInventory.kt | 120 +++++++++++++++++++++ .../utils/renderables/RenderableTooltips.kt | 56 +++++----- 3 files changed, 227 insertions(+), 27 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableInventory.kt (limited to 'src/main/java/at/hannibal2/skyhanni/utils/renderables') diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt index a49f58b00..91abc636d 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -201,6 +201,7 @@ interface Renderable { highlightsOnHoverSlots: List = listOf(), stack: ItemStack? = null, color: LorenzColor? = null, + spacedTitle: Boolean = false, bypassChecks: Boolean = false, snapsToTopIfToLong: Boolean = true, condition: () -> Boolean = { true }, @@ -231,6 +232,7 @@ interface Renderable { stack = stack, borderColor = color, snapsToTopIfToLong = snapsToTopIfToLong, + spacedTitle = spacedTitle, ) GlStateManager.popMatrix() } @@ -839,6 +841,25 @@ interface Renderable { } } + fun paddingContainer( + content: Renderable, + topSpacing: Int = 0, + bottomSpacing: Int = 0, + leftSpacing: Int = 0, + rightSpacing: Int = 0, + ) = object : Renderable { + override val width = content.width + leftSpacing + rightSpacing + override val height = content.height + topSpacing + bottomSpacing + override val horizontalAlign = content.horizontalAlign + override val verticalAlign = content.verticalAlign + + override fun render(posX: Int, posY: Int) { + GlStateManager.translate(leftSpacing.toFloat(), topSpacing.toFloat(), 0f) + content.render(posX + leftSpacing, posY + topSpacing) + GlStateManager.translate(-leftSpacing.toFloat(), -topSpacing.toFloat(), 0f) + } + } + fun scrollList( list: List, height: Int, @@ -1063,11 +1084,56 @@ interface Renderable { } } + fun drawInsideFixedSizedImage( + input: Renderable, + texture: ResourceLocation, + width: Int = input.width, + height: Int = input.height, + alpha: Int = 255, + padding: Int = 2, + uMin: Float = 0f, + uMax: Float = 1f, + vMin: Float = 0f, + vMax: Float = 1f, + horizontalAlign: HorizontalAlignment = HorizontalAlignment.LEFT, + verticalAlign: VerticalAlignment = VerticalAlignment.TOP, + ) = object : Renderable { + override val width = width + override val height = height + override val horizontalAlign = horizontalAlign + override val verticalAlign = verticalAlign + + override fun render(posX: Int, posY: Int) { + Minecraft.getMinecraft().textureManager.bindTexture(texture) + GlStateManager.color(1f, 1f, 1f, alpha / 255f) + Utils.drawTexturedRect( + 0f, + 0f, + width.toFloat(), + height.toFloat(), + uMin, + uMax, + vMin, + vMax, + GL11.GL_NEAREST + ) + GlStateManager.color(1f, 1f, 1f, 1f) + + GlStateManager.translate(padding.toFloat(), padding.toFloat(), 0f) + input.render(posX + padding, posY + padding) + GlStateManager.translate(-padding.toFloat(), -padding.toFloat(), 0f) + } + } + fun image( texture: ResourceLocation, width: Int, height: Int, alpha: Int = 255, + uMin: Float = 0f, + uMax: Float = 1f, + vMin: Float = 0f, + vMax: Float = 1f, horizontalAlign: HorizontalAlignment = HorizontalAlignment.LEFT, verticalAlign: VerticalAlignment = VerticalAlignment.TOP, ) = object : Renderable { @@ -1079,7 +1145,17 @@ interface Renderable { override fun render(posX: Int, posY: Int) { Minecraft.getMinecraft().textureManager.bindTexture(texture) GlStateManager.color(1f, 1f, 1f, alpha / 255f) - Utils.drawTexturedRect(0f, 0f, width.toFloat(), height.toFloat(), GL11.GL_NEAREST) + Utils.drawTexturedRect( + 0f, + 0f, + width.toFloat(), + height.toFloat(), + uMin, + uMax, + vMin, + vMax, + GL11.GL_NEAREST + ) GlStateManager.color(1f, 1f, 1f, 1f) } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableInventory.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableInventory.kt new file mode 100644 index 000000000..6f783a485 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableInventory.kt @@ -0,0 +1,120 @@ +package at.hannibal2.skyhanni.utils.renderables + +import at.hannibal2.skyhanni.utils.RenderUtils.HorizontalAlignment +import at.hannibal2.skyhanni.utils.RenderUtils.VerticalAlignment +import net.minecraft.item.ItemStack +import net.minecraft.util.ResourceLocation +import kotlin.math.ceil + +object RenderableInventory { + + private val inventoryTextures by lazy { ResourceLocation("skyhanni", "gui/slot.png") } + private const val TEXTURE_WIDTH = 90 + private const val TEXTURE_HEIGHT = 54 + + private enum class SlotsUv(val uMin: Int, val uMax: Int, val vMin: Int, val vMax: Int) { + TOP_LEFT_CORNER(14, 18, 32, 36), + TOP_BORDER(18, 36, 32, 36), + TOP_RIGHT_CORNER(36, 40, 32, 36), + LEFT_BORDER(68, 72, 18, 36), + CENTER(0, 18, 0, 18), + RIGHT_BORDER(72, 76, 18, 36), + BOTTOM_LEFT_CORNER(14, 18, 36, 40), + BOTTOM_BORDER(18, 36, 36, 40), + BOTTOM_RIGHT_CORNER(36, 40, 36, 40), + HALF_EMPTY(54, 63, 0, 18), + EMPTY(18, 36, 0, 18), + ; + + fun getUvCoords(): FloatArray { + return floatArrayOf( + (uMin.toFloat() / TEXTURE_WIDTH), + (uMax.toFloat() / TEXTURE_WIDTH), + (vMin.toFloat() / TEXTURE_HEIGHT), + (vMax.toFloat() / TEXTURE_HEIGHT), + ) + } + + fun height() = vMax - vMin + fun width() = uMax - uMin + } + + private fun createUvList(size: Int, maxSize: Int) = buildList { + val length = if (size >= maxSize) maxSize else size + val lastLength = if (size % maxSize == 0) maxSize else size % maxSize + val isWeird = lastLength % 2 != length % 2 + + val rows = ceil(size.toDouble() / maxSize).toInt() + + for (i in 0 until rows + 2) { + val row = mutableListOf() + if (i == 0) { // top border + row.add(SlotsUv.TOP_LEFT_CORNER) + row.addAll(List(length) { SlotsUv.TOP_BORDER }) + row.add(SlotsUv.TOP_RIGHT_CORNER) + } else if (i == rows + 1) { // last border + row.add(SlotsUv.BOTTOM_LEFT_CORNER) + row.addAll(List(length) { SlotsUv.BOTTOM_BORDER }) + row.add(SlotsUv.BOTTOM_RIGHT_CORNER) + } else if (i == rows && rows != 1) { // last row + val spaces = if (isWeird) (length - lastLength) - 1 else length - lastLength + row.add(SlotsUv.LEFT_BORDER) + row.addAll(List(spaces / 2) { SlotsUv.EMPTY }) + if (isWeird) row.add(SlotsUv.HALF_EMPTY) + row.addAll(List(lastLength) { SlotsUv.CENTER }) + if (isWeird) row.add(SlotsUv.HALF_EMPTY) + row.addAll(List(spaces / 2) { SlotsUv.EMPTY }) + row.add(SlotsUv.RIGHT_BORDER) + } else { + row.add(SlotsUv.LEFT_BORDER) + row.addAll(List(length) { SlotsUv.CENTER }) + row.add(SlotsUv.RIGHT_BORDER) + } + add(row.toList()) + } + } + + fun fakeInventory( + items: List, + maxRowSize: Int, + scale: Double, + horizontalAlign: HorizontalAlignment = HorizontalAlignment.LEFT, + verticalAlign: VerticalAlignment = VerticalAlignment.TOP, + ): Renderable { + val uvList = createUvList(items.size, maxRowSize) + var index = 0 + val finalList = uvList.map { uvRow -> + uvRow.map { uv -> + val uvArray = uv.getUvCoords() + val renderable = if (uv == SlotsUv.CENTER) { + (items[index]?.let { item -> + Renderable.itemStack( + item, + scale, + 0, + 0, + ) + } ?: Renderable.placeholder((16 * scale).toInt(), (16 * scale).toInt())).also { index++ } + } else Renderable.placeholder(0, 0) + Renderable.drawInsideFixedSizedImage( + renderable, + inventoryTextures, + (uv.width() * scale).toInt(), + (uv.height() * scale).toInt(), + padding = scale.toInt(), + uMin = uvArray[0], + uMax = uvArray[1], + vMin = uvArray[2], + vMax = uvArray[3], + ) + } + } + + return Renderable.verticalContainer( + finalList.map { Renderable.horizontalContainer(it, 0) }, + 0, + horizontalAlign = horizontalAlign, + verticalAlign = verticalAlign, + ) + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableTooltips.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableTooltips.kt index 0d2c88785..b37c89bb5 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableTooltips.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableTooltips.kt @@ -14,7 +14,6 @@ import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.fml.common.gameevent.TickEvent import net.minecraftforge.fml.common.gameevent.TickEvent.RenderTickEvent -import java.awt.Color @SkyHanniModule object RenderableTooltips { @@ -35,8 +34,9 @@ object RenderableTooltips { stack: ItemStack? = null, borderColor: LorenzColor? = null, snapsToTopIfToLong: Boolean = true, + spacedTitle: Boolean = false ) { - tooltip = DeferredTooltip(tips, stack, borderColor, snapsToTopIfToLong) + tooltip = DeferredTooltip(tips, stack, borderColor, snapsToTopIfToLong, spacedTitle) } private fun drawHoveringText() { @@ -45,9 +45,10 @@ object RenderableTooltips { if (tips.isEmpty()) return val x = Utils.getMouseX() + 12 - val y = Utils.getMouseY() - if (tips.size > 1) 2 else -7 - val borderColorStart = Color(tooltip.getBorderColor()).darker().rgb and 0x00FFFFFF or (200 shl 24) + val y = Utils.getMouseY() - if (tips.size > 1) 1 else -7 + val borderColorStart = tooltip.getBorderColor() val scaled = ScaledResolution(Minecraft.getMinecraft()) + val isSpacedTitle = tooltip.isSpacedTitle() val tooltipTextWidth = tips.maxOf { it.width } val tooltipHeight = tips.sumOf { it.height } @@ -58,11 +59,11 @@ object RenderableTooltips { if (tooltip.snapsToTopIfToLong && tooltipHeight + 8 > scaled.scaledHeight) 4 // Snap to Top if to Long else - scaled.scaledHeight - tooltipHeight - 4 // Limit Bottom + scaled.scaledHeight - tooltipHeight - 6 // Limit Bottom } else -> { - y - 12 // normal + y - 10 // normal } } val tooltipX = if (x + tooltipTextWidth + 4 > scaled.scaledWidth) { @@ -81,19 +82,19 @@ object RenderableTooltips { RenderUtils.drawGradientRect( left = -3, top = -4, - right = tooltipTextWidth + 3, + right = tooltipTextWidth + 2, bottom = -3, ) RenderUtils.drawGradientRect( left = -3, top = tooltipHeight + 3, - right = tooltipTextWidth + 3, + right = tooltipTextWidth + 2, bottom = tooltipHeight + 4, ) RenderUtils.drawGradientRect( left = -3, top = -3, - right = tooltipTextWidth + 3, + right = tooltipTextWidth + 2, bottom = tooltipHeight + 3, ) RenderUtils.drawGradientRect( @@ -103,9 +104,9 @@ object RenderableTooltips { bottom = tooltipHeight + 3, ) RenderUtils.drawGradientRect( - left = tooltipTextWidth + 3, + left = tooltipTextWidth + 2, top = -3, - right = tooltipTextWidth + 4, + right = tooltipTextWidth + 3, bottom = tooltipHeight + 3, ) val borderColorEnd = borderColorStart and 0xFEFEFE shr 1 or (borderColorStart and -0x1000000) @@ -118,9 +119,9 @@ object RenderableTooltips { endColor = borderColorEnd ) RenderUtils.drawGradientRect( - left = tooltipTextWidth + 2, + left = tooltipTextWidth + 1, top = -3 + 1, - right = tooltipTextWidth + 3, + right = tooltipTextWidth + 2, bottom = tooltipHeight + 3 - 1, startColor = borderColorStart, endColor = borderColorEnd @@ -128,7 +129,7 @@ object RenderableTooltips { RenderUtils.drawGradientRect( left = -3, top = -3, - right = tooltipTextWidth + 3, + right = tooltipTextWidth + 2, bottom = -3 + 1, startColor = borderColorStart, endColor = borderColorStart @@ -136,25 +137,24 @@ object RenderableTooltips { RenderUtils.drawGradientRect( left = -3, top = tooltipHeight + 2, - right = tooltipTextWidth + 3, + right = tooltipTextWidth + 2, bottom = tooltipHeight + 3, startColor = borderColorEnd, endColor = borderColorEnd ) - GlStateManager.disableDepth() - GlStateManager.translate(0f, 0f, -zLevel) + GlStateManager.translate(-1f, -1f, 0f) var yTranslateSum = 0 - for (line in tips) { + tips.forEachIndexed { index, line -> line.renderXAligned(tooltipX, tooltipY, tooltipTextWidth) - val yShift = line.height + var yShift = line.height + if (index == 0 && isSpacedTitle) yShift += 2 GlStateManager.translate(0f, yShift.toFloat(), 0f) yTranslateSum += yShift } - GlStateManager.translate(-tooltipX.toFloat(), -tooltipY.toFloat() + yTranslateSum.toFloat(), 0f) + GlStateManager.translate(-tooltipX.toFloat() + 1, -tooltipY.toFloat() + 1 + yTranslateSum.toFloat(), -zLevel) GlStateManager.enableLighting() - GlStateManager.enableDepth() RenderHelper.enableStandardItemLighting() GlStateManager.enableRescaleNormal() GlStateManager.disableLighting() @@ -164,13 +164,17 @@ object RenderableTooltips { private data class DeferredTooltip( val tips: List, val stack: ItemStack? = null, - val borderColor: LorenzColor? = null, + private val borderColor: LorenzColor? = null, val snapsToTopIfToLong: Boolean = true, + private val spacedTitle: Boolean = false, ) { - fun getBorderColor(): Int { - return Minecraft.getMinecraft().fontRendererObj.getColorCode( - borderColor?.chatColorCode ?: stack?.getLore()?.lastOrNull()?.take(4)?.get(1) ?: 'f' - ) + fun getBorderColor(): Int = + (borderColor?.chatColorCode ?: stack?.getLore()?.lastOrNull()?.take(4)?.get(1)) + ?.let { Minecraft.getMinecraft().fontRendererObj.getColorCode(it) } + ?: 0x505000FF + + fun isSpacedTitle(): Boolean { + return spacedTitle } } -- cgit