Scissor stack fix

This commit is contained in:
DBotThePony 2024-01-12 20:57:12 +07:00
parent 0dffe511fd
commit 71f13f70bf
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -3,13 +3,11 @@ package ru.dbotthepony.mc.otm.client.render
import com.mojang.blaze3d.platform.GlStateManager import com.mojang.blaze3d.platform.GlStateManager
import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.* import com.mojang.blaze3d.vertex.*
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.renderer.GameRenderer import net.minecraft.client.renderer.GameRenderer
import net.minecraft.client.renderer.RenderStateShard import net.minecraft.client.renderer.RenderStateShard
import net.minecraft.client.renderer.RenderStateShard.LineStateShard import net.minecraft.client.renderer.RenderStateShard.LineStateShard
import net.minecraft.client.renderer.RenderType import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.ShaderInstance import net.minecraft.client.renderer.ShaderInstance
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.packs.resources.ResourceProvider import net.minecraft.server.packs.resources.ResourceProvider
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
@ -294,9 +292,15 @@ fun drawLine(
tess.end() tess.end()
} }
data class ScissorRect(val x: Int, val y: Int, val width: Int, val height: Int, val lock: Boolean = false) { data class ScissorRect(val xStart: Int, val yStart: Int, val xEnd: Int, val yEnd: Int, val lock: Boolean = false) {
val width: Int
get() = (xEnd - xStart).coerceAtLeast(0)
val height: Int
get() = (yEnd - yStart).coerceAtLeast(0)
fun withinBounds(x: Int, y: Int): Boolean { fun withinBounds(x: Int, y: Int): Boolean {
return (x in this.x .. this.x + width) && (y in this.y .. this.y + height) return (x in this.xStart .. xEnd) && (y in this.yStart .. yEnd)
} }
fun cross(x: Int, y: Int, width: Int, height: Int): Boolean { fun cross(x: Int, y: Int, width: Int, height: Int): Boolean {
@ -306,18 +310,18 @@ data class ScissorRect(val x: Int, val y: Int, val width: Int, val height: Int,
} }
// crossing at least one line // crossing at least one line
if (y in this.y .. this.y + height) { if (y in this.yStart .. this.yStart + height) {
if (x < this.x && x + width > this.x + this.width) { if (x < this.xStart && x + width > this.xEnd) {
return true return true
} }
} else if (x in this.x .. this.x + width) { } else if (x in this.xStart .. this.xStart + width) {
if (y < this.y && y + height > this.y + this.height) { if (y < this.yStart && y + height > this.yEnd) {
return true return true
} }
} }
// final test: check if scissor rect is completely inside provided rect // final test: check if scissor rect is completely inside provided rect
return this.x in x .. x + width && this.y in y .. y + height return this.xStart in x .. x + width && this.yStart in y .. y + height
} }
fun crossScaled(x: Float, y: Float, width: Float, height: Float): Boolean { fun crossScaled(x: Float, y: Float, width: Float, height: Float): Boolean {
@ -329,17 +333,20 @@ data class ScissorRect(val x: Int, val y: Int, val width: Int, val height: Int,
val scale = minecraft.window.guiScale val scale = minecraft.window.guiScale
return cross((x * scale).roundToInt(), (y * scale).roundToInt(), (width * scale).roundToInt(), (height * scale).roundToInt()) return cross((x * scale).roundToInt(), (y * scale).roundToInt(), (width * scale).roundToInt(), (height * scale).roundToInt())
} }
fun apply() {
RenderSystem.enableScissor(xStart, minecraft.window.height - yStart - height, width, height)
}
} }
private val scissorStack = ArrayDeque<ScissorRect>() private val scissorStack = ArrayDeque<ScissorRect>()
@Suppress("NAME_SHADOWING")
@JvmOverloads @JvmOverloads
fun pushScissorRect(x: Int, y: Int, width: Int, height: Int, lock: Boolean = false) { fun pushScissorRect(x: Int, y: Int, width: Int, height: Int, lock: Boolean = false) {
var x = x var xStart = x
var y = y var yStart = y
var width = width var xEnd = x + width
var height = height var yEnd = y + height
val peek = scissorStack.lastOrNull() val peek = scissorStack.lastOrNull()
@ -349,34 +356,31 @@ fun pushScissorRect(x: Int, y: Int, width: Int, height: Int, lock: Boolean = fal
return return
} }
x = x.coerceAtLeast(peek.x) xStart = xStart.coerceAtLeast(peek.xStart)
y = y.coerceAtLeast(peek.y) yStart = yStart.coerceAtLeast(peek.yStart)
width = width.coerceAtMost(peek.width) xEnd = xEnd.coerceAtMost(peek.xEnd)
height = height.coerceAtMost(peek.height) yEnd = yEnd.coerceAtMost(peek.yEnd)
if (peek.x == x && peek.y == y && peek.width == width && peek.height == height) { if (peek.xStart == xStart && peek.yStart == yStart && peek.xEnd == xEnd && peek.yEnd == yEnd) {
scissorStack.add(peek) scissorStack.add(peek)
return return
} }
} }
scissorStack.add(ScissorRect(x, y, width, height, lock)) val new = ScissorRect(xStart, yStart, xEnd, yEnd, lock)
y = minecraft.window.height - y - height scissorStack.add(new)
RenderSystem.enableScissor(x, y, width, height) new.apply()
} }
fun popScissorRect() { fun popScissorRect() {
scissorStack.removeLast() scissorStack.removeLast()
val peek = scissorStack.lastOrNull() val peek = scissorStack.lastOrNull()
if (peek == null) { if (peek == null) {
RenderSystem.disableScissor() RenderSystem.disableScissor()
return } else {
peek.apply()
} }
val y = minecraft.window.height - peek.y - peek.height
RenderSystem.enableScissor(peek.x, y, peek.width, peek.height)
} }
val currentScissorRect get() = scissorStack.lastOrNull() val currentScissorRect get() = scissorStack.lastOrNull()