diff options
Diffstat (limited to 'src/main/kotlin/util')
18 files changed, 659 insertions, 219 deletions
diff --git a/src/main/kotlin/util/FragmentGuiScreen.kt b/src/main/kotlin/util/FragmentGuiScreen.kt index 5e13d51..de53ac0 100644 --- a/src/main/kotlin/util/FragmentGuiScreen.kt +++ b/src/main/kotlin/util/FragmentGuiScreen.kt @@ -19,13 +19,9 @@ abstract class FragmentGuiScreen( popup = MoulConfigFragment(context, position) { popup = null } } - override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { - super.render(context, mouseX, mouseY, delta) - context.matrices.push() - context.matrices.translate(0f, 0f, 1000f) - popup?.render(context, mouseX, mouseY, delta) - context.matrices.pop() - } + fun renderPopup(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { + popup?.render(context, mouseX, mouseY, delta) + } private inline fun ifPopup(ifYes: (MoulConfigFragment) -> Unit): Boolean { val p = popup ?: return false @@ -65,7 +61,7 @@ abstract class FragmentGuiScreen( return ifPopup { if (!Rectangle( it.position, - Dimension(it.context.root.width, it.context.root.height) + Dimension(it.guiContext.root.width, it.guiContext.root.height) ).contains(Point(mouseX, mouseY)) && dismissOnOutOfBounds ) { diff --git a/src/main/kotlin/util/HoveredItemStack.kt b/src/main/kotlin/util/HoveredItemStack.kt index 526820a..1b54562 100644 --- a/src/main/kotlin/util/HoveredItemStack.kt +++ b/src/main/kotlin/util/HoveredItemStack.kt @@ -6,22 +6,33 @@ import net.minecraft.item.ItemStack import moe.nea.firmament.mixins.accessor.AccessorHandledScreen import moe.nea.firmament.util.compatloader.CompatLoader -interface HoveredItemStackProvider { +interface HoveredItemStackProvider : Comparable<HoveredItemStackProvider> { fun provideHoveredItemStack(screen: HandledScreen<*>): ItemStack? + override fun compareTo(other: HoveredItemStackProvider): Int { + return compareValues(this.prio, other.prio) + } + + val prio: Int get() = 0 - companion object : CompatLoader<HoveredItemStackProvider>(HoveredItemStackProvider::class) + companion object : CompatLoader<HoveredItemStackProvider>(HoveredItemStackProvider::class) { + val sorted = HoveredItemStackProvider.allValidInstances.sorted() + } } @AutoService(HoveredItemStackProvider::class) class VanillaScreenProvider : HoveredItemStackProvider { + override fun provideHoveredItemStack(screen: HandledScreen<*>): ItemStack? { screen as AccessorHandledScreen val vanillaSlot = screen.focusedSlot_Firmament?.stack return vanillaSlot } + + override val prio: Int + get() = -1 } val HandledScreen<*>.focusedItemStack: ItemStack? get() = - HoveredItemStackProvider.allValidInstances + HoveredItemStackProvider.sorted .firstNotNullOfOrNull { it.provideHoveredItemStack(this)?.takeIf { !it.isEmpty } } diff --git a/src/main/kotlin/util/MC.kt b/src/main/kotlin/util/MC.kt index e85b119..7ab0cbb 100644 --- a/src/main/kotlin/util/MC.kt +++ b/src/main/kotlin/util/MC.kt @@ -1,7 +1,7 @@ package moe.nea.firmament.util import io.github.moulberry.repo.data.Coordinate -import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper +import io.github.notenoughupdates.moulconfig.platform.MoulConfigScreenComponent import java.util.concurrent.ConcurrentLinkedQueue import kotlin.jvm.optionals.getOrNull import net.minecraft.client.MinecraftClient @@ -16,11 +16,13 @@ import net.minecraft.client.world.ClientWorld import net.minecraft.entity.Entity import net.minecraft.item.Item import net.minecraft.item.ItemStack +import net.minecraft.nbt.NbtOps import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket import net.minecraft.registry.BuiltinRegistries import net.minecraft.registry.Registry import net.minecraft.registry.RegistryKey import net.minecraft.registry.RegistryKeys +import net.minecraft.registry.RegistryOps import net.minecraft.registry.RegistryWrapper import net.minecraft.resource.ReloadableResourceManagerImpl import net.minecraft.text.Text @@ -74,7 +76,7 @@ object MC { fun sendCommand(command: String) { // TODO: add a queue to this and sendServerChat ErrorUtil.softCheck("Server commands have an implied /", !command.startsWith("/")) - player?.networkHandler?.sendCommand(command) + player?.networkHandler?.sendChatCommand(command) } fun onMainThread(block: () -> Unit) { @@ -117,6 +119,7 @@ object MC { inline val window get() = instance.window inline val currentRegistries: RegistryWrapper.WrapperLookup? get() = world?.registryManager val defaultRegistries: RegistryWrapper.WrapperLookup by lazy { BuiltinRegistries.createWrapperLookup() } + val defaultRegistryNbtOps by lazy { RegistryOps.of(NbtOps.INSTANCE, defaultRegistries) } inline val currentOrDefaultRegistries get() = currentRegistries ?: defaultRegistries val defaultItems: RegistryWrapper.Impl<Item> by lazy { defaultRegistries.getOrThrow(RegistryKeys.ITEM) } var currentTick = 0 @@ -128,7 +131,7 @@ object MC { private set val currentMoulConfigContext - get() = (screen as? GuiComponentWrapper)?.context + get() = (screen as? MoulConfigScreenComponent)?.guiContext fun openUrl(uri: String) { Util.getOperatingSystem().open(uri) diff --git a/src/main/kotlin/util/MoulConfigFragment.kt b/src/main/kotlin/util/MoulConfigFragment.kt index 28ccfd0..7e7f5db 100644 --- a/src/main/kotlin/util/MoulConfigFragment.kt +++ b/src/main/kotlin/util/MoulConfigFragment.kt @@ -1,44 +1,43 @@ - - package moe.nea.firmament.util -import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper import io.github.notenoughupdates.moulconfig.gui.GuiContext import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext +import io.github.notenoughupdates.moulconfig.platform.MoulConfigScreenComponent import me.shedaniel.math.Point import net.minecraft.client.gui.DrawContext +import net.minecraft.text.Text class MoulConfigFragment( - context: GuiContext, - val position: Point, - val dismiss: () -> Unit -) : GuiComponentWrapper(context) { - init { - this.init(MC.instance, MC.screen!!.width, MC.screen!!.height) - } - - override fun createContext(drawContext: DrawContext?): GuiImmediateContext { - val oldContext = super.createContext(drawContext) - return oldContext.translated( - position.x, - position.y, - context.root.width, - context.root.height, - ) - } - - - override fun render(drawContext: DrawContext?, i: Int, j: Int, f: Float) { - val ctx = createContext(drawContext) - val m = drawContext!!.matrices - m.push() - m.translate(position.x.toFloat(), position.y.toFloat(), 0F) - context.root.render(ctx) - m.pop() - ctx.renderContext.renderExtraLayers() - } - - override fun close() { - dismiss() - } + context: GuiContext, + val position: Point, + val dismiss: () -> Unit +) : MoulConfigScreenComponent(Text.empty(), context, null) { + init { + this.init(MC.instance, MC.screen!!.width, MC.screen!!.height) + } + + override fun createContext(drawContext: DrawContext?): GuiImmediateContext { + val oldContext = super.createContext(drawContext) + return oldContext.translated( + position.x, + position.y, + guiContext.root.width, + guiContext.root.height, + ) + } + + + override fun render(drawContext: DrawContext, i: Int, j: Int, f: Float) { + val ctx = createContext(drawContext) + val m = drawContext.matrices + m.pushMatrix() + m.translate(position.x.toFloat(), position.y.toFloat()) + guiContext.root.render(ctx) + m.popMatrix() + ctx.renderContext.renderExtraLayers() + } + + override fun close() { + dismiss() + } } diff --git a/src/main/kotlin/util/MoulConfigUtils.kt b/src/main/kotlin/util/MoulConfigUtils.kt index 51ff340..2f2fd5c 100644 --- a/src/main/kotlin/util/MoulConfigUtils.kt +++ b/src/main/kotlin/util/MoulConfigUtils.kt @@ -4,13 +4,14 @@ import io.github.notenoughupdates.moulconfig.common.IMinecraft import io.github.notenoughupdates.moulconfig.common.MyResourceLocation import io.github.notenoughupdates.moulconfig.gui.CloseEventListener import io.github.notenoughupdates.moulconfig.gui.GuiComponent -import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper import io.github.notenoughupdates.moulconfig.gui.GuiContext import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext import io.github.notenoughupdates.moulconfig.gui.KeyboardEvent import io.github.notenoughupdates.moulconfig.gui.MouseEvent import io.github.notenoughupdates.moulconfig.observer.GetSetter -import io.github.notenoughupdates.moulconfig.platform.ModernRenderContext +import io.github.notenoughupdates.moulconfig.platform.MoulConfigPlatform +import io.github.notenoughupdates.moulconfig.platform.MoulConfigRenderContext +import io.github.notenoughupdates.moulconfig.platform.MoulConfigScreenComponent import io.github.notenoughupdates.moulconfig.xml.ChildCount import io.github.notenoughupdates.moulconfig.xml.XMLContext import io.github.notenoughupdates.moulconfig.xml.XMLGuiLoader @@ -26,6 +27,7 @@ import kotlin.time.Duration.Companion.seconds import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.screen.Screen import net.minecraft.client.util.InputUtil +import net.minecraft.text.Text import moe.nea.firmament.gui.BarComponent import moe.nea.firmament.gui.FirmButtonComponent import moe.nea.firmament.gui.FirmHoverComponent @@ -226,9 +228,9 @@ object MoulConfigUtils { } fun wrapScreen(guiContext: GuiContext, parent: Screen?, onClose: () -> Unit = {}): Screen { - return object : GuiComponentWrapper(guiContext) { + return object : MoulConfigScreenComponent(Text.empty(), guiContext, null) { override fun close() { - if (context.onBeforeClose() == CloseEventListener.CloseAction.NO_OBJECTIONS_TO_CLOSE) { + if (guiContext.onBeforeClose() == CloseEventListener.CloseAction.NO_OBJECTIONS_TO_CLOSE) { client!!.setScreen(parent) onClose() } @@ -264,7 +266,7 @@ object MoulConfigUtils { h: Int, keyboardEvent: KeyboardEvent ): Boolean { - val immContext = createInPlaceFullContext(null, IMinecraft.instance.mouseX, IMinecraft.instance.mouseY) + val immContext = createInPlaceFullContext(null, IMinecraft.INSTANCE.mouseX, IMinecraft.INSTANCE.mouseY) if (component.keyboardEvent(keyboardEvent, immContext.translated(x, y, w, h))) return true if (component.context.getFocusedElement() != null) { @@ -292,9 +294,12 @@ object MoulConfigUtils { } fun createInPlaceFullContext(drawContext: DrawContext?, mouseX: Int, mouseY: Int): GuiImmediateContext { - assert(drawContext?.isUntranslatedGuiDrawContext() != false) - val context = drawContext?.let(::ModernRenderContext) - ?: IMinecraft.instance.provideTopLevelRenderContext() + ErrorUtil.softCheck( + "created moulconfig context with pre-existing translations.", + drawContext?.isUntranslatedGuiDrawContext() != false + ) + val context = drawContext?.let(::MoulConfigRenderContext) + ?: IMinecraft.INSTANCE.provideTopLevelRenderContext() val immContext = GuiImmediateContext( context, 0, 0, 0, 0, @@ -316,10 +321,10 @@ object MoulConfigUtils { mouseY: Int ) { val immContext = createInPlaceFullContext(this, mouseX, mouseY) - matrices.push() - matrices.translate(x.toFloat(), y.toFloat(), 0F) + matrices.pushMatrix() + matrices.translate(x.toFloat(), y.toFloat()) component.render(immContext.translated(x, y, w, h)) - matrices.pop() + matrices.popMatrix() } diff --git a/src/main/kotlin/util/SkyblockId.kt b/src/main/kotlin/util/SkyblockId.kt index 051ca86..03b8bf4 100644 --- a/src/main/kotlin/util/SkyblockId.kt +++ b/src/main/kotlin/util/SkyblockId.kt @@ -146,9 +146,9 @@ val ItemStack.skyblockUUIDString: String? private val timestampFormat = //"10/11/21 3:39 PM" DateTimeFormatterBuilder().apply { - appendValue(ChronoField.MONTH_OF_YEAR, 2) + appendValue(ChronoField.MONTH_OF_YEAR, 1, 2, SignStyle.NOT_NEGATIVE) appendLiteral("/") - appendValue(ChronoField.DAY_OF_MONTH, 2) + appendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE) appendLiteral("/") appendValueReduced(ChronoField.YEAR, 2, 2, 1950) appendLiteral(" ") diff --git a/src/main/kotlin/util/json/CodecSerializer.kt b/src/main/kotlin/util/json/CodecSerializer.kt new file mode 100644 index 0000000..9ea08ad --- /dev/null +++ b/src/main/kotlin/util/json/CodecSerializer.kt @@ -0,0 +1,26 @@ +package util.json + +import com.mojang.serialization.Codec +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonElement +import moe.nea.firmament.util.json.KJsonOps + +abstract class CodecSerializer<T>(val codec: Codec<T>) : KSerializer<T> { + override val descriptor: SerialDescriptor + get() = JsonElement.serializer().descriptor + + override fun serialize(encoder: Encoder, value: T) { + encoder.encodeSerializableValue( + JsonElement.serializer(), + codec.encodeStart(KJsonOps.INSTANCE, value).orThrow + ) + } + + override fun deserialize(decoder: Decoder): T { + return codec.decode(KJsonOps.INSTANCE, decoder.decodeSerializableValue(JsonElement.serializer())) + .orThrow.first + } +} diff --git a/src/main/kotlin/util/mc/CustomRenderPassHelper.kt b/src/main/kotlin/util/mc/CustomRenderPassHelper.kt new file mode 100644 index 0000000..295f727 --- /dev/null +++ b/src/main/kotlin/util/mc/CustomRenderPassHelper.kt @@ -0,0 +1,160 @@ +package moe.nea.firmament.util.mc + +import com.mojang.blaze3d.buffers.GpuBuffer +import com.mojang.blaze3d.buffers.GpuBufferSlice +import com.mojang.blaze3d.buffers.Std140Builder +import com.mojang.blaze3d.pipeline.RenderPipeline +import com.mojang.blaze3d.systems.RenderPass +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.vertex.VertexFormat +import java.nio.ByteBuffer +import java.nio.ByteOrder +import java.util.OptionalDouble +import java.util.OptionalInt +import org.joml.Vector4f +import net.minecraft.client.gl.Framebuffer +import net.minecraft.client.render.BufferBuilder +import net.minecraft.client.render.BuiltBuffer +import net.minecraft.client.texture.AbstractTexture +import net.minecraft.client.util.BufferAllocator +import net.minecraft.util.Identifier +import net.minecraft.util.math.MathHelper +import moe.nea.firmament.util.ErrorUtil +import moe.nea.firmament.util.MC + + +class CustomRenderPassHelper( + val labelSupplier: () -> String, + val drawMode: VertexFormat.DrawMode, + val vertexFormat: VertexFormat, + val frameBuffer: Framebuffer, + val hasDepth: Boolean, +) : AutoCloseable { + private val scope = mutableListOf<AutoCloseable>() + private val preparations = mutableListOf<(RenderPass) -> Unit>() + val device = RenderSystem.getDevice() + private var hasPipelineAction = false + private var hasSetDefaultUniforms = false + val commandEncoder = device.createCommandEncoder() + fun setPipeline(pipeline: RenderPipeline) { + ErrorUtil.softCheck("Already has a pipeline", !hasPipelineAction) + hasPipelineAction = true + queueAction { + it.setPipeline(pipeline) + } + } + + fun bindSampler(name: String, texture: Identifier) { + bindSampler(name, MC.textureManager.getTexture(texture)) + } + + fun bindSampler(name: String, texture: AbstractTexture) { + queueAction { it.bindSampler(name, texture.glTextureView) } + } + + + fun dontSetDefaultUniforms() { + hasSetDefaultUniforms = true + } + + fun setAllDefaultUniforms() { + hasSetDefaultUniforms = true + queueAction { + RenderSystem.bindDefaultUniforms(it) + } + setUniform( + "DynamicTransforms", RenderSystem.getDynamicUniforms() + .write( + RenderSystem.getModelViewMatrix(), + Vector4f(1.0F, 1.0F, 1.0F, 1.0F), + RenderSystem.getModelOffset(), + RenderSystem.getTextureMatrix(), + RenderSystem.getShaderLineWidth() + ) + ) + } + + fun setUniform(name: String, slice: GpuBufferSlice) = queueAction { it.setUniform(name, slice) } + fun setUniform(name: String, slice: GpuBuffer) = queueAction { it.setUniform(name, slice) } + + fun setUniform(name: String, size: Int, labelSupplier: () -> String = { name }, init: (Std140Builder) -> Unit) { + val buffer = createUniformBuffer(labelSupplier, allocateByteBuf(size, init)) + setUniform(name, buffer) + } + + var vertices: BuiltBuffer? = null + + fun uploadVertices(size: Int, init: (BufferBuilder) -> Unit) { + uploadVertices( + BufferBuilder(queueClose(BufferAllocator(size)), drawMode, vertexFormat) + .also(init) + .end() + ) + } + + fun uploadVertices(buffer: BuiltBuffer) { + queueClose(buffer) + ErrorUtil.softCheck("Vertices have already been uploaded", vertices == null) + vertices = buffer + val vertexBuffer = vertexFormat.uploadImmediateVertexBuffer(buffer.buffer) + val indexBufferConstructor = RenderSystem.getSequentialBuffer(drawMode) + val indexBuffer = indexBufferConstructor.getIndexBuffer(buffer.drawParameters.indexCount) + queueAction { + it.setIndexBuffer(indexBuffer, indexBufferConstructor.indexType) + it.setVertexBuffer(0, vertexBuffer) + } + } + + fun createUniformBuffer(labelSupplier: () -> String, buffer: ByteBuffer): GpuBuffer { + return queueClose( + device.createBuffer( + labelSupplier::invoke, + GpuBuffer.USAGE_UNIFORM or GpuBuffer.USAGE_MAP_READ, + buffer + ) + ) + } + + fun allocateByteBuf(size: Int, init: (Std140Builder) -> Unit): ByteBuffer { + return Std140Builder.intoBuffer( // TODO: i really dont know about this 16 align? but it seems to be generally correct. + ByteBuffer + .allocateDirect(MathHelper.roundUpToMultiple(size, 16)) + .order(ByteOrder.nativeOrder()) + ).also(init).get() + } + + fun queueAction(action: (RenderPass) -> Unit) { + preparations.add(action) + } + + fun <T : AutoCloseable> queueClose(t: T): T = t.also { scope.add(it) } + override fun close() { + scope.reversed().forEach { it.close() } + } + + object DrawToken + + fun draw(): DrawToken { + val vertexData = (ErrorUtil.notNullOr(vertices, "No vertex data uploaded") { return DrawToken }) + ErrorUtil.softCheck("Missing default uniforms", hasSetDefaultUniforms) + ErrorUtil.softCheck("Missing a pipeline", hasPipelineAction) + val renderPass = queueClose( + commandEncoder.createRenderPass( + labelSupplier::invoke, + RenderSystem.outputColorTextureOverride ?: frameBuffer.getColorAttachmentView(), + OptionalInt.empty(), + (RenderSystem.outputDepthTextureOverride + ?: frameBuffer.getDepthAttachmentView()).takeIf { frameBuffer.useDepthAttachment && hasDepth }, + OptionalDouble.empty() + ) + ) + preparations.forEach { it(renderPass) } + renderPass.drawIndexed( + 0, + 0, + vertexData.drawParameters.indexCount, + 1 + ) + return DrawToken + } +} diff --git a/src/main/kotlin/util/mc/ItemUtil.kt b/src/main/kotlin/util/mc/ItemUtil.kt index 13519cf..3cabb8e 100644 --- a/src/main/kotlin/util/mc/ItemUtil.kt +++ b/src/main/kotlin/util/mc/ItemUtil.kt @@ -1,20 +1,30 @@ package moe.nea.firmament.util.mc +import kotlin.jvm.optionals.getOrNull import net.minecraft.item.ItemStack +import net.minecraft.nbt.NbtCompound +import net.minecraft.nbt.NbtOps +import net.minecraft.registry.RegistryOps +import net.minecraft.registry.RegistryWrapper import net.minecraft.text.Text +import moe.nea.firmament.util.MC fun ItemStack.appendLore(args: List<Text>) { - if (args.isEmpty()) return - modifyLore { - val loreList = loreAccordingToNbt.toMutableList() - for (arg in args) { - loreList.add(arg) - } - loreList - } + if (args.isEmpty()) return + modifyLore { + val loreList = loreAccordingToNbt.toMutableList() + for (arg in args) { + loreList.add(arg) + } + loreList + } } fun ItemStack.modifyLore(update: (List<Text>) -> List<Text>) { - val loreList = loreAccordingToNbt - loreAccordingToNbt = update(loreList) + val loreList = loreAccordingToNbt + loreAccordingToNbt = update(loreList) +} + +fun loadItemFromNbt(nbt: NbtCompound, registries: RegistryWrapper.WrapperLookup = MC.defaultRegistries): ItemStack? { + return ItemStack.CODEC.decode(RegistryOps.of(NbtOps.INSTANCE, registries), nbt).result().getOrNull()?.first } diff --git a/src/main/kotlin/util/render/CustomRenderLayers.kt b/src/main/kotlin/util/render/CustomRenderLayers.kt index 2da1de7..d88a1e4 100644 --- a/src/main/kotlin/util/render/CustomRenderLayers.kt +++ b/src/main/kotlin/util/render/CustomRenderLayers.kt @@ -11,7 +11,6 @@ import net.minecraft.client.render.RenderLayer import net.minecraft.client.render.RenderPhase import net.minecraft.client.render.VertexFormats import net.minecraft.util.Identifier -import net.minecraft.util.TriState import net.minecraft.util.Util import moe.nea.firmament.Firmament @@ -31,7 +30,7 @@ object CustomRenderPipelines { .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) .build() val COLORED_OMNIPRESENT_QUADS = - RenderPipeline.builder(RenderPipelines.MATRICES_COLOR_SNIPPET)// TODO: split this up to support better transparent ordering. + RenderPipeline.builder(RenderPipelines.TRANSFORMS_AND_PROJECTION_SNIPPET)// TODO: split this up to support better transparent ordering. .withLocation(Firmament.identifier("colored_omnipresent_quads")) .withVertexShader("core/position_color") .withFragmentShader("core/position_color") @@ -46,9 +45,9 @@ object CustomRenderPipelines { RenderPipeline.builder(RenderPipelines.POSITION_TEX_COLOR_SNIPPET) .withVertexFormat(VertexFormats.POSITION_TEXTURE_COLOR, DrawMode.TRIANGLES) .withLocation(Firmament.identifier("gui_textured_overlay_tris_circle")) - .withUniform("InnerCutoutRadius", UniformType.FLOAT) + .withUniform("CutoutRadius", UniformType.UNIFORM_BUFFER) .withFragmentShader(Firmament.identifier("circle_discard_color")) - .withBlend(BlendFunction.TRANSLUCENT) +// .withBlend(BlendFunction.TRANSLUCENT) .build() val PARALLAX_CAPE_SHADER = RenderPipeline.builder(RenderPipelines.ENTITY_SNIPPET) @@ -57,12 +56,12 @@ object CustomRenderPipelines { .withSampler("Sampler0") .withSampler("Sampler1") .withSampler("Sampler3") - .withUniform("Animation", UniformType.FLOAT) + .withUniform("Animation", UniformType.UNIFORM_BUFFER) .build() } object CustomRenderLayers { - inline fun memoizeTextured(crossinline func: (Identifier) -> RenderLayer) = memoize(func) + inline fun memoizeTextured(crossinline func: (Identifier) -> RenderLayer.MultiPhase) = memoize(func) inline fun <T, R> memoize(crossinline func: (T) -> R): Function<T, R> { return Util.memoize { it: T -> func(it) } } @@ -73,7 +72,7 @@ object CustomRenderLayers { RenderLayer.DEFAULT_BUFFER_SIZE, CustomRenderPipelines.GUI_TEXTURED_NO_DEPTH_TRIS, RenderLayer.MultiPhaseParameters.builder().texture( - RenderPhase.Texture(texture, TriState.DEFAULT, false) + RenderPhase.Texture(texture, false) ) .build(false) ) diff --git a/src/main/kotlin/util/render/DrawContextExt.kt b/src/main/kotlin/util/render/DrawContextExt.kt index a833c86..e63bf5f 100644 --- a/src/main/kotlin/util/render/DrawContextExt.kt +++ b/src/main/kotlin/util/render/DrawContextExt.kt @@ -2,26 +2,31 @@ package moe.nea.firmament.util.render import com.mojang.blaze3d.systems.RenderSystem import me.shedaniel.math.Color -import org.joml.Matrix4f +import org.joml.Vector2f +import org.joml.Vector3f import util.render.CustomRenderLayers +import kotlin.math.abs +import net.minecraft.client.gl.RenderPipelines import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.RenderLayer +import net.minecraft.client.gui.ScreenRect +import net.minecraft.client.render.VertexConsumerProvider +import net.minecraft.client.util.math.MatrixStack import net.minecraft.util.Identifier import moe.nea.firmament.util.MC fun DrawContext.isUntranslatedGuiDrawContext(): Boolean { - return (matrices.peek().positionMatrix.properties() and Matrix4f.PROPERTY_IDENTITY.toInt()) != 0 + return matrices.m00 == 1F && matrices.m11 == 1f && matrices.m01 == 0F && matrices.m10 == 0F && matrices.m20 == 0F && matrices.m21 == 0F } @Deprecated("Use the other drawGuiTexture") fun DrawContext.drawGuiTexture( x: Int, y: Int, z: Int, width: Int, height: Int, sprite: Identifier -) = this.drawGuiTexture(RenderLayer::getGuiTextured, sprite, x, y, width, height) +) = this.drawGuiTexture(RenderPipelines.GUI_TEXTURED, sprite, x, y, width, height) fun DrawContext.drawGuiTexture( sprite: Identifier, x: Int, y: Int, width: Int, height: Int -) = this.drawGuiTexture(RenderLayer::getGuiTextured, sprite, x, y, width, height) +) = this.drawGuiTexture(RenderPipelines.GUI_TEXTURED, sprite, x, y, width, height) fun DrawContext.drawTexture( sprite: Identifier, @@ -34,35 +39,130 @@ fun DrawContext.drawTexture( textureWidth: Int, textureHeight: Int ) { - this.drawTexture(RenderLayer::getGuiTextured, - sprite, - x, - y, - u, - v, - width, - height, - width, - height, - textureWidth, - textureHeight) + this.drawTexture( + RenderPipelines.GUI_TEXTURED, + sprite, + x, + y, + u, + v, + width, + height, + width, + height, + textureWidth, + textureHeight + ) } -fun DrawContext.drawLine(fromX: Int, fromY: Int, toX: Int, toY: Int, color: Color) { - // TODO: push scissors - // TODO: use matrix translations and a different render layer +data class LineRenderState( + override val x1: Int, + override val x2: Int, + override val y1: Int, + override val y2: Int, + override val scale: Float, + override val bounds: ScreenRect, + val lineWidth: Float, + val w: Int, + val h: Int, + val color: Int, + val direction: LineDirection, +) : MultiSpecialGuiRenderState() { + enum class LineDirection { + TOP_LEFT_TO_BOTTOM_RIGHT, + BOTTOM_LEFT_TO_TOP_RIGHT, + } + + override fun createRenderer(vertexConsumers: VertexConsumerProvider.Immediate): MultiSpecialGuiRenderer<out MultiSpecialGuiRenderState> { + return LineRenderer(vertexConsumers) + } + + override val scissorArea = null +} + +class LineRenderer(vertexConsumers: VertexConsumerProvider.Immediate) : + MultiSpecialGuiRenderer<LineRenderState>(vertexConsumers) { + override fun getElementClass(): Class<LineRenderState> { + return LineRenderState::class.java + } + + override fun getYOffset(height: Int, windowScaleFactor: Int): Float { + return height / 2F + } + + override fun render( + state: LineRenderState, + matrices: MatrixStack + ) { + val gr = MC.instance.gameRenderer + val client = MC.instance + gr.globalSettings + .set( + state.bounds.width, + state.bounds.height, + client.options.glintStrength.getValue(), + client.world?.time ?: 0L, + client.renderTickCounter, + client.options.menuBackgroundBlurrinessValue + ) + + RenderSystem.lineWidth(state.lineWidth) + val buf = vertexConsumers.getBuffer(CustomRenderLayers.LINES) + val matrix = matrices.peek() + val wh = state.w / 2F + val hh = state.h / 2F + val lowX = -wh + val lowY = if (state.direction == LineRenderState.LineDirection.BOTTOM_LEFT_TO_TOP_RIGHT) hh else -hh + val highX = wh + val highY = -lowY + val norm = Vector3f(highX - lowX, highY - lowY, 0F).normalize() + buf.vertex(matrix, lowX, lowY, 0F).color(state.color) + .normal(matrix, norm) + buf.vertex(matrix, highX, highY, 0F).color(state.color) + .normal(matrix, norm) + vertexConsumers.draw() + gr.globalSettings + .set( + client.window.framebufferWidth, + client.window.framebufferHeight, + client.options.glintStrength.getValue(), + client.world?.getTime() ?: 0L, + client.renderTickCounter, + client.options.menuBackgroundBlurrinessValue + ) + + } + + override fun getName(): String? { + return "Firmament Line Renderer" + } +} + + +fun DrawContext.drawLine(fromX: Int, fromY: Int, toX: Int, toY: Int, color: Color, lineWidth: Float = 1F) { if (toY < fromY) { drawLine(toX, toY, fromX, fromY, color) return } - RenderSystem.lineWidth(MC.window.scaleFactor.toFloat()) - draw { vertexConsumers -> - val buf = vertexConsumers.getBuffer(CustomRenderLayers.LINES) - val matrix = this.matrices.peek() - buf.vertex(matrix, fromX.toFloat(), fromY.toFloat(), 0F).color(color.color) - .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F) - buf.vertex(matrix, toX.toFloat(), toY.toFloat(), 0F).color(color.color) - .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F) - } + val originalRect = ScreenRect( + minOf(fromX, toX), minOf(toY, fromY), + abs(toX - fromX), abs(toY - fromY) + ).transform(matrices) + val expansionFactor = 3 + val rect = ScreenRect( + originalRect.left - expansionFactor, + originalRect.top - expansionFactor, + originalRect.width + expansionFactor * 2, + originalRect.height + expansionFactor * 2 + ) + // TODO: expand the bounds so that the thickness of the line can be used + // TODO: fix this up to work with scissorarea + state.addSpecialElement( + LineRenderState( + rect.left, rect.right, rect.top, rect.bottom, 1F, rect, lineWidth, + originalRect.width, originalRect.height, color.color, + if (fromX < toX) LineRenderState.LineDirection.TOP_LEFT_TO_BOTTOM_RIGHT else LineRenderState.LineDirection.BOTTOM_LEFT_TO_TOP_RIGHT + ) + ) } diff --git a/src/main/kotlin/util/render/DumpTexture.kt b/src/main/kotlin/util/render/DumpTexture.kt new file mode 100644 index 0000000..a7b4e78 --- /dev/null +++ b/src/main/kotlin/util/render/DumpTexture.kt @@ -0,0 +1,34 @@ +package moe.nea.firmament.util.render + +import com.mojang.blaze3d.buffers.GpuBuffer +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.textures.GpuTexture +import java.io.File +import net.minecraft.client.texture.NativeImage + +fun dumpTexture(gpuTexture: GpuTexture, name: String) { + val w = gpuTexture.getWidth(0) + val h = gpuTexture.getHeight(0) + val buffer = RenderSystem.getDevice() + .createBuffer( + { "Dump Buffer" }, + GpuBuffer.USAGE_COPY_DST or GpuBuffer.USAGE_MAP_READ, + w * h * gpuTexture.getFormat().pixelSize() + ) + val commandEncoder = RenderSystem.getDevice().createCommandEncoder() + commandEncoder.copyTextureToBuffer( + gpuTexture, buffer, 0, { + val nativeImage = NativeImage(w, h, false) + commandEncoder.mapBuffer(buffer, true, false).use { mappedView -> + for (i in 0..<w) { + for (j in 0..<h) { + val color = mappedView.data().getInt((j + i * w) * gpuTexture.format.pixelSize()) + nativeImage.setColor(j, h - i - 1, color) + } + } + } + buffer.close() + nativeImage.writeTo(File("$name.png")) + }, 0 + ) +} diff --git a/src/main/kotlin/util/render/FacingThePlayerContext.kt b/src/main/kotlin/util/render/FacingThePlayerContext.kt index 670beb6..76270c5 100644 --- a/src/main/kotlin/util/render/FacingThePlayerContext.kt +++ b/src/main/kotlin/util/render/FacingThePlayerContext.kt @@ -1,11 +1,13 @@ package moe.nea.firmament.util.render -import io.github.notenoughupdates.moulconfig.platform.next import org.joml.Matrix4f +import util.render.CustomRenderLayers import net.minecraft.client.font.TextRenderer import net.minecraft.client.render.LightmapTextureManager import net.minecraft.client.render.RenderLayer +import net.minecraft.client.render.RenderLayers +import net.minecraft.client.render.TexturedRenderLayers import net.minecraft.client.render.VertexConsumer import net.minecraft.text.Text import net.minecraft.util.Identifier @@ -38,14 +40,14 @@ class FacingThePlayerContext(val worldContext: RenderInWorldContext) { worldContext.vertexConsumers.getBuffer(RenderLayer.getTextBackgroundSeeThrough()) val matrix4f = worldContext.matrixStack.peek().positionMatrix vertexConsumer.vertex(matrix4f, -1.0f, -1.0f, 0.0f).color(background) - .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() + .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE) vertexConsumer.vertex(matrix4f, -1.0f, MC.font.fontHeight.toFloat(), 0.0f).color(background) - .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() + .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE) vertexConsumer.vertex(matrix4f, width.toFloat(), MC.font.fontHeight.toFloat(), 0.0f) .color(background) - .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() + .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE) vertexConsumer.vertex(matrix4f, width.toFloat(), -1.0f, 0.0f).color(background) - .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() + .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE) worldContext.matrixStack.translate(0F, 0F, 0.01F) MC.font.draw( @@ -70,22 +72,22 @@ class FacingThePlayerContext(val worldContext: RenderInWorldContext) { u1: Float, v1: Float, u2: Float, v2: Float, ) { - val buf = worldContext.vertexConsumers.getBuffer(RenderLayer.getGuiTexturedOverlay(texture)) + val buf = worldContext.vertexConsumers.getBuffer(CustomRenderLayers.GUI_TEXTURED_NO_DEPTH_TRIS.apply(texture)) // TODO: this is strictly an incorrect render layer val hw = width / 2F val hh = height / 2F val matrix4f: Matrix4f = worldContext.matrixStack.peek().positionMatrix buf.vertex(matrix4f, -hw, -hh, 0F) .color(-1) - .texture(u1, v1).next() + .texture(u1, v1) buf.vertex(matrix4f, -hw, +hh, 0F) .color(-1) - .texture(u1, v2).next() + .texture(u1, v2) buf.vertex(matrix4f, +hw, +hh, 0F) .color(-1) - .texture(u2, v2).next() + .texture(u2, v2) buf.vertex(matrix4f, +hw, -hh, 0F) .color(-1) - .texture(u2, v1).next() + .texture(u2, v1) worldContext.vertexConsumers.draw() } diff --git a/src/main/kotlin/util/render/MultiSpecialGuiRenderState.kt b/src/main/kotlin/util/render/MultiSpecialGuiRenderState.kt new file mode 100644 index 0000000..ce56df3 --- /dev/null +++ b/src/main/kotlin/util/render/MultiSpecialGuiRenderState.kt @@ -0,0 +1,48 @@ +package moe.nea.firmament.util.render + +import org.joml.Matrix3x2f +import net.minecraft.client.gui.ScreenRect +import net.minecraft.client.gui.render.SpecialGuiElementRenderer +import net.minecraft.client.gui.render.state.GuiRenderState +import net.minecraft.client.gui.render.state.special.SpecialGuiElementRenderState +import net.minecraft.client.render.VertexConsumerProvider + +abstract class MultiSpecialGuiRenderState : SpecialGuiElementRenderState { + // I wish i had manifolds @Self type here... Maybe i should switch to java after all :( + abstract fun createRenderer(vertexConsumers: VertexConsumerProvider.Immediate): MultiSpecialGuiRenderer<out MultiSpecialGuiRenderState> + abstract val x1: Int + abstract val x2: Int + abstract val y1: Int + abstract val y2: Int + abstract val scale: Float + abstract val bounds: ScreenRect? + abstract val scissorArea: ScreenRect? + override fun x1(): Int = x1 + + override fun x2(): Int = x2 + + override fun y1(): Int = y1 + + override fun y2(): Int = y2 + + override fun scale(): Float = scale + + override fun scissorArea(): ScreenRect? = scissorArea + + override fun bounds(): ScreenRect? = bounds + +} + +abstract class MultiSpecialGuiRenderer<T : MultiSpecialGuiRenderState>( + vertexConsumers: VertexConsumerProvider.Immediate +) : SpecialGuiElementRenderer<T>(vertexConsumers) { + var wasUsedThisFrame = false + fun consumeRender(): Boolean { + return wasUsedThisFrame.also { wasUsedThisFrame = false } + } + + override fun renderElement(element: T, state: GuiRenderState) { + wasUsedThisFrame = true + super.renderElement(element, state) + } +} diff --git a/src/main/kotlin/util/render/RenderCircleProgress.kt b/src/main/kotlin/util/render/RenderCircleProgress.kt index 81dde6f..301eec4 100644 --- a/src/main/kotlin/util/render/RenderCircleProgress.kt +++ b/src/main/kotlin/util/render/RenderCircleProgress.kt @@ -1,25 +1,126 @@ package moe.nea.firmament.util.render -import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.vertex.VertexFormat -import io.github.notenoughupdates.moulconfig.platform.next -import java.util.OptionalInt -import org.joml.Matrix4f +import org.joml.Matrix3x2f import util.render.CustomRenderLayers import net.minecraft.client.gui.DrawContext +import net.minecraft.client.gui.ScreenRect import net.minecraft.client.render.BufferBuilder import net.minecraft.client.render.RenderLayer +import net.minecraft.client.render.VertexConsumerProvider import net.minecraft.client.util.BufferAllocator +import net.minecraft.client.util.math.MatrixStack import net.minecraft.util.Identifier import moe.nea.firmament.util.MC import moe.nea.firmament.util.collections.nonNegligibleSubSectionsAlignedWith import moe.nea.firmament.util.math.Projections +import moe.nea.firmament.util.mc.CustomRenderPassHelper object RenderCircleProgress { + + data class State( + override val x1: Int, + override val x2: Int, + override val y1: Int, + override val y2: Int, + val layer: RenderLayer.MultiPhase, + val u1: Float, + val u2: Float, + val v1: Float, + val v2: Float, + val angleRadians: ClosedFloatingPointRange<Float>, + val color: Int, + val innerCutoutRadius: Float, + override val scale: Float, + override val bounds: ScreenRect?, + override val scissorArea: ScreenRect?, + ) : MultiSpecialGuiRenderState() { + override fun createRenderer(vertexConsumers: VertexConsumerProvider.Immediate): MultiSpecialGuiRenderer<out MultiSpecialGuiRenderState> { + return Renderer(vertexConsumers) + } + } + + class Renderer(vertexConsumers: VertexConsumerProvider.Immediate) : + MultiSpecialGuiRenderer<State>(vertexConsumers) { + override fun render( + state: State, + matrices: MatrixStack + ) { + matrices.push() + matrices.translate(0F, -1F, 0F) + val sections = state.angleRadians.nonNegligibleSubSectionsAlignedWith((τ / 8f).toFloat()) + .zipWithNext().toList() + val u1 = state.u1 + val u2 = state.u2 + val v1 = state.v1 + val v2 = state.v2 + val color = state.color + val matrix = matrices.peek().positionMatrix + BufferAllocator(state.layer.vertexFormat.vertexSize * sections.size * 3).use { allocator -> + + val bufferBuilder = BufferBuilder(allocator, VertexFormat.DrawMode.TRIANGLES, state.layer.vertexFormat) + + for ((sectionStart, sectionEnd) in sections) { + val firstPoint = Projections.Two.projectAngleOntoUnitBox(sectionStart.toDouble()) + val secondPoint = Projections.Two.projectAngleOntoUnitBox(sectionEnd.toDouble()) + fun ilerp(f: Float): Float = + ilerp(-1f, 1f, f) + + bufferBuilder + .vertex(matrix, secondPoint.x, secondPoint.y, 0F) + .texture(lerp(u1, u2, ilerp(secondPoint.x)), lerp(v1, v2, ilerp(secondPoint.y))) + .color(color) + + bufferBuilder + .vertex(matrix, firstPoint.x, firstPoint.y, 0F) + .texture(lerp(u1, u2, ilerp(firstPoint.x)), lerp(v1, v2, ilerp(firstPoint.y))) + .color(color) + + bufferBuilder + .vertex(matrix, 0F, 0F, 0F) + .texture(lerp(u1, u2, ilerp(0F)), lerp(v1, v2, ilerp(0F))) + .color(color) + + } + + bufferBuilder.end().use { buffer -> + if (state.innerCutoutRadius <= 0) { + state.layer.draw(buffer) + return + } + CustomRenderPassHelper( + { "RenderCircleProgress" }, + VertexFormat.DrawMode.TRIANGLES, + state.layer.vertexFormat, + MC.instance.framebuffer, + false, + ).use { renderPass -> + renderPass.uploadVertices(buffer) + renderPass.setAllDefaultUniforms() + renderPass.setPipeline(state.layer.pipeline) + renderPass.setUniform("CutoutRadius", 4) { + it.putFloat(state.innerCutoutRadius) + } + renderPass.draw() + } + } + } + matrices.pop() + } + + override fun getElementClass(): Class<State> { + return State::class.java + } + + override fun getName(): String { + return "Firmament Circle" + } + } + fun renderCircularSlice( drawContext: DrawContext, - layer: RenderLayer, + layer: RenderLayer.MultiPhase, u1: Float, u2: Float, v1: Float, @@ -28,58 +129,21 @@ object RenderCircleProgress { color: Int = -1, innerCutoutRadius: Float = 0F ) { - drawContext.draw() - val sections = angleRadians.nonNegligibleSubSectionsAlignedWith((τ / 8f).toFloat()) - .zipWithNext().toList() - BufferAllocator(layer.vertexFormat.vertexSize * sections.size * 3).use { allocator -> - - val bufferBuilder = BufferBuilder(allocator, VertexFormat.DrawMode.TRIANGLES, layer.vertexFormat) - val matrix: Matrix4f = drawContext.matrices.peek().positionMatrix - - for ((sectionStart, sectionEnd) in sections) { - val firstPoint = Projections.Two.projectAngleOntoUnitBox(sectionStart.toDouble()) - val secondPoint = Projections.Two.projectAngleOntoUnitBox(sectionEnd.toDouble()) - fun ilerp(f: Float): Float = - ilerp(-1f, 1f, f) - - bufferBuilder - .vertex(matrix, secondPoint.x, secondPoint.y, 0F) - .texture(lerp(u1, u2, ilerp(secondPoint.x)), lerp(v1, v2, ilerp(secondPoint.y))) - .color(color) - .next() - bufferBuilder - .vertex(matrix, firstPoint.x, firstPoint.y, 0F) - .texture(lerp(u1, u2, ilerp(firstPoint.x)), lerp(v1, v2, ilerp(firstPoint.y))) - .color(color) - .next() - bufferBuilder - .vertex(matrix, 0F, 0F, 0F) - .texture(lerp(u1, u2, ilerp(0F)), lerp(v1, v2, ilerp(0F))) - .color(color) - .next() - } - - bufferBuilder.end().use { buffer -> - // TODO: write a better utility to pass uniforms :sob: ill even take a mixin at this point - if (innerCutoutRadius <= 0) { - layer.draw(buffer) - return - } - val vertexBuffer = layer.vertexFormat.uploadImmediateVertexBuffer(buffer.buffer) - val indexBufferConstructor = RenderSystem.getSequentialBuffer(VertexFormat.DrawMode.TRIANGLES) - val indexBuffer = indexBufferConstructor.getIndexBuffer(buffer.drawParameters.indexCount) - RenderSystem.getDevice().createCommandEncoder().createRenderPass( - MC.instance.framebuffer.colorAttachment, - OptionalInt.empty(), - ).use { renderPass -> - renderPass.setPipeline(layer.pipeline) - renderPass.setUniform("InnerCutoutRadius", innerCutoutRadius) - renderPass.setIndexBuffer(indexBuffer, indexBufferConstructor.indexType) - renderPass.setVertexBuffer(0, vertexBuffer) - renderPass.drawIndexed(0, buffer.drawParameters.indexCount) - } - } - } + val screenRect = ScreenRect(-1, -1, 2, 2).transform(drawContext.matrices) + drawContext.state.addSpecialElement( + State( + screenRect.left, screenRect.right, + screenRect.top, screenRect.bottom, + layer, + u1, u2, v1, v2, + angleRadians, + color, + innerCutoutRadius, + screenRect.width / 2F, + screenRect, + null + ) + ) } fun renderCircle( diff --git a/src/main/kotlin/util/render/RenderInWorldContext.kt b/src/main/kotlin/util/render/RenderInWorldContext.kt index c30ee19..0898190 100644 --- a/src/main/kotlin/util/render/RenderInWorldContext.kt +++ b/src/main/kotlin/util/render/RenderInWorldContext.kt @@ -1,7 +1,6 @@ package moe.nea.firmament.util.render import com.mojang.blaze3d.systems.RenderSystem -import io.github.notenoughupdates.moulconfig.platform.next import java.lang.Math.pow import org.joml.Matrix4f import org.joml.Vector3f @@ -28,18 +27,6 @@ class RenderInWorldContext private constructor( private val tickCounter: RenderTickCounter, val vertexConsumers: VertexConsumerProvider.Immediate, ) { - - - @Deprecated("stateful color management is no longer a thing") - fun color(color: me.shedaniel.math.Color) { - color(color.red / 255F, color.green / 255f, color.blue / 255f, color.alpha / 255f) - } - - @Deprecated("stateful color management is no longer a thing") - fun color(red: Float, green: Float, blue: Float, alpha: Float) { - RenderSystem.setShaderColor(red, green, blue, alpha) - } - fun block(blockPos: BlockPos, color: Int) { matrixStack.push() matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat()) @@ -156,6 +143,7 @@ class RenderInWorldContext private constructor( fun wireframeCube(blockPos: BlockPos, lineWidth: Float = 10F) { val buf = vertexConsumers.getBuffer(RenderLayer.LINES) matrixStack.push() + // TODO: add color arg to this // TODO: this does not render through blocks (or water layers) anymore RenderSystem.lineWidth(lineWidth / pow(camera.pos.squaredDistanceTo(blockPos.toCenterPos()), 0.25).toFloat()) matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat()) @@ -164,16 +152,16 @@ class RenderInWorldContext private constructor( vertexConsumers.draw() } - fun line(vararg points: Vec3d, lineWidth: Float = 10F) { - line(points.toList(), lineWidth) + fun line(vararg points: Vec3d, color: Int, lineWidth: Float = 10F) { + line(points.toList(), color, lineWidth) } - fun tracer(toWhere: Vec3d, lineWidth: Float = 3f) { + fun tracer(toWhere: Vec3d, color: Int, lineWidth: Float = 3f) { val cameraForward = Vector3f(0f, 0f, -1f).rotate(camera.rotation) - line(camera.pos.add(Vec3d(cameraForward)), toWhere, lineWidth = lineWidth) + line(camera.pos.add(Vec3d(cameraForward)), toWhere, color = color, lineWidth = lineWidth) } - fun line(points: List<Vec3d>, lineWidth: Float = 10F) { + fun line(points: List<Vec3d>, color: Int, lineWidth: Float = 10F) { RenderSystem.lineWidth(lineWidth) val buffer = vertexConsumers.getBuffer(CustomRenderLayers.LINES) @@ -188,11 +176,11 @@ class RenderInWorldContext private constructor( buffer.vertex(matrix.positionMatrix, a.x.toFloat(), a.y.toFloat(), a.z.toFloat()) .color(-1) .normal(matrix, lastNormal0.x, lastNormal0.y, lastNormal0.z) - .next() + buffer.vertex(matrix.positionMatrix, b.x.toFloat(), b.y.toFloat(), b.z.toFloat()) .color(-1) .normal(matrix, normal.x, normal.y, normal.z) - .next() + } } @@ -215,11 +203,11 @@ class RenderInWorldContext private constructor( buf.vertex(matrix.positionMatrix, i, j, k) .normal(matrix, normal.x, normal.y, normal.z) .color(-1) - .next() + buf.vertex(matrix.positionMatrix, x, y, z) .normal(matrix, normal.x, normal.y, normal.z) .color(-1) - .next() + } @@ -287,12 +275,6 @@ class RenderInWorldContext private constructor( } fun renderInWorld(event: WorldRenderLastEvent, block: RenderInWorldContext. () -> Unit) { - // TODO: there should be *no more global state*. the only thing we should be doing is render layers. that includes settings like culling, blending, shader color, and depth testing - // For now i will let these functions remain, but this needs to go before i do a full (non-beta) release -// RenderSystem.disableDepthTest() -// RenderSystem.enableBlend() -// RenderSystem.defaultBlendFunc() -// RenderSystem.disableCull() event.matrices.push() event.matrices.translate(-event.camera.pos.x, -event.camera.pos.y, -event.camera.pos.z) @@ -308,7 +290,6 @@ class RenderInWorldContext private constructor( event.matrices.pop() event.vertexConsumers.draw() - RenderSystem.setShaderColor(1F, 1F, 1F, 1F) } } } diff --git a/src/main/kotlin/util/render/TranslatedScissors.kt b/src/main/kotlin/util/render/TranslatedScissors.kt index 8f8bdcf..a091648 100644 --- a/src/main/kotlin/util/render/TranslatedScissors.kt +++ b/src/main/kotlin/util/render/TranslatedScissors.kt @@ -1,26 +1,27 @@ - package moe.nea.firmament.util.render -import org.joml.Matrix4f +import org.joml.Matrix3x2f +import org.joml.Vector3f import org.joml.Vector4f import net.minecraft.client.gui.DrawContext fun DrawContext.enableScissorWithTranslation(x1: Float, y1: Float, x2: Float, y2: Float) { - enableScissor(x1.toInt(), y1.toInt(), x2.toInt(), y2.toInt()) + enableScissor(x1.toInt(), y1.toInt(), x2.toInt(), y2.toInt()) } + fun DrawContext.enableScissorWithoutTranslation(x1: Float, y1: Float, x2: Float, y2: Float) { - val pMat = matrices.peek().positionMatrix.invert(Matrix4f()) - val target = Vector4f() + val pMat = Matrix3x2f(matrices).invert() + var target = Vector3f() - target.set(x1, y1, 0f, 1f) - target.mul(pMat) - val scissorX1 = target.x - val scissorY1 = target.y + target.set(x1, y1, 1F) + target.mul(pMat) + val scissorX1 = target.x + val scissorY1 = target.y - target.set(x2, y2, 0f, 1f) - target.mul(pMat) - val scissorX2 = target.x - val scissorY2 = target.y + target.set(x2, y2, 1F) + target.mul(pMat) + val scissorX2 = target.x + val scissorY2 = target.y - enableScissor(scissorX1.toInt(), scissorY1.toInt(), scissorX2.toInt(), scissorY2.toInt()) + enableScissor(scissorX1.toInt(), scissorY1.toInt(), scissorX2.toInt(), scissorY2.toInt()) } diff --git a/src/main/kotlin/util/textutil.kt b/src/main/kotlin/util/textutil.kt index cfda2e9..177b0af 100644 --- a/src/main/kotlin/util/textutil.kt +++ b/src/main/kotlin/util/textutil.kt @@ -179,10 +179,11 @@ fun Text.transformEachRecursively(function: (Text) -> Text): Text { val c = this.content if (c is TranslatableTextContent) { return Text.translatableWithFallback(c.key, c.fallback, *c.args.map { - (if (it is Text) it else Text.literal(it.toString())).transformEachRecursively(function) + (it as? Text ?: Text.literal(it.toString())).transformEachRecursively(function) }.toTypedArray()).also { new -> new.style = this.style new.siblings.clear() + val new = function(new) this.siblings.forEach { child -> new.siblings.add(child.transformEachRecursively(function)) } |
