aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/util
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-11-03 01:24:24 +0100
committerLinnea Gräf <nea@nea.moe>2024-11-09 01:01:18 +0100
commit22f0cc59a2d3bc7900764e3916c670075ff9d35e (patch)
treeb503ff607cf818a539cbbaa403f6851ef979e03d /src/main/kotlin/util
parent646843ba3b960ac48f9866b3640438d3cc1dafc4 (diff)
downloadFirmament-22f0cc59a2d3bc7900764e3916c670075ff9d35e.tar.gz
Firmament-22f0cc59a2d3bc7900764e3916c670075ff9d35e.tar.bz2
Firmament-22f0cc59a2d3bc7900764e3916c670075ff9d35e.zip
1.21.3 WIP
Diffstat (limited to 'src/main/kotlin/util')
-rw-r--r--src/main/kotlin/util/ErrorUtil.kt25
-rw-r--r--src/main/kotlin/util/MC.kt28
-rw-r--r--src/main/kotlin/util/SBData.kt2
-rw-r--r--src/main/kotlin/util/SkyblockId.kt7
-rw-r--r--src/main/kotlin/util/data/IDataHolder.kt112
-rw-r--r--src/main/kotlin/util/render/DrawContextExt.kt71
-rw-r--r--src/main/kotlin/util/render/FacingThePlayerContext.kt7
-rw-r--r--src/main/kotlin/util/render/FirmamentShaders.kt31
-rw-r--r--src/main/kotlin/util/render/RenderCircleProgress.kt140
-rw-r--r--src/main/kotlin/util/render/RenderInWorldContext.kt550
10 files changed, 541 insertions, 432 deletions
diff --git a/src/main/kotlin/util/ErrorUtil.kt b/src/main/kotlin/util/ErrorUtil.kt
index afecf25..b06093b 100644
--- a/src/main/kotlin/util/ErrorUtil.kt
+++ b/src/main/kotlin/util/ErrorUtil.kt
@@ -1,25 +1,46 @@
+@file:OptIn(ExperimentalContracts::class)
+
package moe.nea.firmament.util
+import kotlin.contracts.ExperimentalContracts
+import kotlin.contracts.InvocationKind
+import kotlin.contracts.contract
import moe.nea.firmament.Firmament
+@Suppress("NOTHING_TO_INLINE") // Suppressed since i want the logger to not pick up the ErrorUtil stack-frame
object ErrorUtil {
var aggressiveErrors = run {
Thread.currentThread().stackTrace.any { it.className.startsWith("org.junit.") } || Firmament.DEBUG
+ || ErrorUtil::class.java.desiredAssertionStatus()
+ }
+
+ inline fun softCheck(message: String, check: Boolean) {
+ if (!check) softError(message)
}
- inline fun softCheck(message: String, func: () -> Boolean) {
+ inline fun lazyCheck(message: String, func: () -> Boolean) {
+ contract {
+ callsInPlace(func, InvocationKind.AT_MOST_ONCE)
+ }
if (!aggressiveErrors) return
if (func()) return
error(message)
}
- @Suppress("NOTHING_TO_INLINE") // Suppressed since i want the logger to not pick up the ErrorUtil stack-frame
+ inline fun softError(message: String, exception: Throwable) {
+ if (aggressiveErrors) throw IllegalStateException(message, exception)
+ else Firmament.logger.error(message, exception)
+ }
+
inline fun softError(message: String) {
if (aggressiveErrors) error(message)
else Firmament.logger.error(message)
}
inline fun <T : Any> notNullOr(nullable: T?, message: String, orElse: () -> T): T {
+ contract {
+ callsInPlace(orElse, InvocationKind.AT_MOST_ONCE)
+ }
if (nullable == null) {
softError(message)
return orElse()
diff --git a/src/main/kotlin/util/MC.kt b/src/main/kotlin/util/MC.kt
index fc42be9..1b7739f 100644
--- a/src/main/kotlin/util/MC.kt
+++ b/src/main/kotlin/util/MC.kt
@@ -3,9 +3,13 @@ package moe.nea.firmament.util
import io.github.moulberry.repo.data.Coordinate
import java.util.concurrent.ConcurrentLinkedQueue
import net.minecraft.client.MinecraftClient
+import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.screen.ingame.HandledScreen
-import net.minecraft.client.option.GameOptions
+import net.minecraft.client.network.ClientPlayerEntity
import net.minecraft.client.render.WorldRenderer
+import net.minecraft.client.render.item.ItemRenderer
+import net.minecraft.client.world.ClientWorld
+import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket
import net.minecraft.registry.BuiltinRegistries
@@ -14,7 +18,9 @@ import net.minecraft.registry.RegistryWrapper
import net.minecraft.resource.ReloadableResourceManagerImpl
import net.minecraft.text.Text
import net.minecraft.util.math.BlockPos
+import net.minecraft.world.World
import moe.nea.firmament.events.TickEvent
+import moe.nea.firmament.events.WorldReadyEvent
object MC {
@@ -29,6 +35,9 @@ object MC {
(nextTickTodos.poll() ?: break).invoke()
}
}
+ WorldReadyEvent.subscribe("MC:ready") {
+ this.lastWorld
+ }
}
fun sendChat(text: Text) {
@@ -69,6 +78,7 @@ object MC {
inline val resourceManager get() = (instance.resourceManager as ReloadableResourceManagerImpl)
+ inline val itemRenderer: ItemRenderer get() = instance.itemRenderer
inline val worldRenderer: WorldRenderer get() = instance.worldRenderer
inline val networkHandler get() = player?.networkHandler
inline val instance get() = MinecraftClient.getInstance()
@@ -79,11 +89,11 @@ object MC {
inline val inGameHud get() = instance.inGameHud
inline val font get() = instance.textRenderer
inline val soundManager get() = instance.soundManager
- inline val player get() = instance.player
- inline val camera get() = instance.cameraEntity
+ inline val player: ClientPlayerEntity? get() = instance.player
+ inline val camera: Entity? get() = instance.cameraEntity
inline val guiAtlasManager get() = instance.guiAtlasManager
- inline val world get() = instance.world
- inline var screen
+ inline val world: ClientWorld? get() = instance.world
+ inline var screen: Screen?
get() = instance.currentScreen
set(value) = instance.setScreen(value)
val screenName get() = screen?.title?.unformattedString?.trim()
@@ -92,7 +102,13 @@ object MC {
inline val currentRegistries: RegistryWrapper.WrapperLookup? get() = world?.registryManager
val defaultRegistries: RegistryWrapper.WrapperLookup = BuiltinRegistries.createWrapperLookup()
inline val currentOrDefaultRegistries get() = currentRegistries ?: defaultRegistries
- val defaultItems: RegistryWrapper.Impl<Item> = defaultRegistries.getWrapperOrThrow(RegistryKeys.ITEM)
+ val defaultItems: RegistryWrapper.Impl<Item> = defaultRegistries.getOrThrow(RegistryKeys.ITEM)
+ var lastWorld: World? = null
+ get() {
+ field = world ?: field
+ return field
+ }
+ private set
}
diff --git a/src/main/kotlin/util/SBData.kt b/src/main/kotlin/util/SBData.kt
index 0b2c404..051d070 100644
--- a/src/main/kotlin/util/SBData.kt
+++ b/src/main/kotlin/util/SBData.kt
@@ -37,7 +37,7 @@ object SBData {
it.serverType.getOrNull()?.name?.uppercase(),
it.mode.getOrNull(),
it.map.getOrNull())
- SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, null))
+ SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, locraw))
profileIdCommandDebounce = TimeMark.now()
}
}
diff --git a/src/main/kotlin/util/SkyblockId.kt b/src/main/kotlin/util/SkyblockId.kt
index 059e746..9c9287b 100644
--- a/src/main/kotlin/util/SkyblockId.kt
+++ b/src/main/kotlin/util/SkyblockId.kt
@@ -2,6 +2,7 @@
package moe.nea.firmament.util
+import com.mojang.serialization.Codec
import io.github.moulberry.repo.data.NEUIngredient
import io.github.moulberry.repo.data.NEUItem
import io.github.moulberry.repo.data.Rarity
@@ -16,6 +17,9 @@ import net.minecraft.component.type.NbtComponent
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.nbt.NbtCompound
+import net.minecraft.network.RegistryByteBuf
+import net.minecraft.network.codec.PacketCodec
+import net.minecraft.network.codec.PacketCodecs
import net.minecraft.util.Identifier
import moe.nea.firmament.repo.ItemCache.asItemStack
import moe.nea.firmament.repo.set
@@ -68,6 +72,9 @@ value class SkyblockId(val neuItem: String) {
val NULL: SkyblockId = SkyblockId("null")
val PET_NULL: SkyblockId = SkyblockId("null_pet")
private val illlegalPathRegex = "[^a-z0-9_.-/]".toRegex()
+ val CODEC = Codec.STRING.xmap({ SkyblockId(it) }, { it.neuItem })
+ val PACKET_CODEC: PacketCodec<in RegistryByteBuf, SkyblockId> =
+ PacketCodecs.STRING.xmap({ SkyblockId(it) }, { it.neuItem })
}
}
diff --git a/src/main/kotlin/util/data/IDataHolder.kt b/src/main/kotlin/util/data/IDataHolder.kt
index cc97b58..1e9ba98 100644
--- a/src/main/kotlin/util/data/IDataHolder.kt
+++ b/src/main/kotlin/util/data/IDataHolder.kt
@@ -1,77 +1,71 @@
-
-
package moe.nea.firmament.util.data
import java.util.concurrent.CopyOnWriteArrayList
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents
import kotlin.reflect.KClass
-import net.minecraft.client.MinecraftClient
-import net.minecraft.server.command.CommandOutput
import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.events.ScreenChangeEvent
+import moe.nea.firmament.util.MC
interface IDataHolder<T> {
- companion object {
- internal var badLoads: MutableList<String> = CopyOnWriteArrayList()
- private val allConfigs: MutableMap<KClass<out IDataHolder<*>>, IDataHolder<*>> = mutableMapOf()
- private val dirty: MutableSet<KClass<out IDataHolder<*>>> = mutableSetOf()
+ companion object {
+ internal var badLoads: MutableList<String> = CopyOnWriteArrayList()
+ private val allConfigs: MutableMap<KClass<out IDataHolder<*>>, IDataHolder<*>> = mutableMapOf()
+ private val dirty: MutableSet<KClass<out IDataHolder<*>>> = mutableSetOf()
- internal fun <T : IDataHolder<K>, K> putDataHolder(kClass: KClass<T>, inst: IDataHolder<K>) {
- allConfigs[kClass] = inst
- }
+ internal fun <T : IDataHolder<K>, K> putDataHolder(kClass: KClass<T>, inst: IDataHolder<K>) {
+ allConfigs[kClass] = inst
+ }
- fun <T : IDataHolder<K>, K> markDirty(kClass: KClass<T>) {
- if (kClass !in allConfigs) {
- Firmament.logger.error("Tried to markDirty '${kClass.qualifiedName}', which isn't registered as 'IConfigHolder'")
- return
- }
- dirty.add(kClass)
- }
+ fun <T : IDataHolder<K>, K> markDirty(kClass: KClass<T>) {
+ if (kClass !in allConfigs) {
+ Firmament.logger.error("Tried to markDirty '${kClass.qualifiedName}', which isn't registered as 'IConfigHolder'")
+ return
+ }
+ dirty.add(kClass)
+ }
- private fun performSaves() {
- val toSave = dirty.toList().also {
- dirty.clear()
- }
- for (it in toSave) {
- val obj = allConfigs[it]
- if (obj == null) {
- Firmament.logger.error("Tried to save '${it}', which isn't registered as 'ConfigHolder'")
- continue
- }
- obj.save()
- }
- }
+ private fun performSaves() {
+ val toSave = dirty.toList().also {
+ dirty.clear()
+ }
+ for (it in toSave) {
+ val obj = allConfigs[it]
+ if (obj == null) {
+ Firmament.logger.error("Tried to save '${it}', which isn't registered as 'ConfigHolder'")
+ continue
+ }
+ obj.save()
+ }
+ }
- private fun warnForResetConfigs(player: CommandOutput) {
- if (badLoads.isNotEmpty()) {
- player.sendMessage(
- Text.literal(
- "The following configs have been reset: ${badLoads.joinToString(", ")}. " +
- "This can be intentional, but probably isn't."
- )
- )
- badLoads.clear()
- }
- }
+ private fun warnForResetConfigs() {
+ if (badLoads.isNotEmpty()) {
+ MC.sendChat(
+ Text.literal(
+ "The following configs have been reset: ${badLoads.joinToString(", ")}. " +
+ "This can be intentional, but probably isn't."
+ )
+ )
+ badLoads.clear()
+ }
+ }
- fun registerEvents() {
- ScreenChangeEvent.subscribe("IDataHolder:saveOnScreenChange") { event ->
- performSaves()
- val p = MinecraftClient.getInstance().player
- if (p != null) {
- warnForResetConfigs(p)
- }
- }
- ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
- performSaves()
- })
- }
+ fun registerEvents() {
+ ScreenChangeEvent.subscribe("IDataHolder:saveOnScreenChange") { event ->
+ performSaves()
+ warnForResetConfigs()
+ }
+ ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
+ performSaves()
+ })
+ }
- }
+ }
- val data: T
- fun save()
- fun markDirty()
- fun load()
+ val data: T
+ fun save()
+ fun markDirty()
+ fun load()
}
diff --git a/src/main/kotlin/util/render/DrawContextExt.kt b/src/main/kotlin/util/render/DrawContextExt.kt
index fc38aa6..da0b0b0 100644
--- a/src/main/kotlin/util/render/DrawContextExt.kt
+++ b/src/main/kotlin/util/render/DrawContextExt.kt
@@ -4,12 +4,70 @@ import com.mojang.blaze3d.systems.RenderSystem
import me.shedaniel.math.Color
import org.joml.Matrix4f
import net.minecraft.client.gui.DrawContext
+import net.minecraft.client.render.RenderLayer
+import net.minecraft.client.render.RenderLayer.MultiPhaseParameters
+import net.minecraft.client.render.RenderPhase
+import net.minecraft.client.render.VertexFormat
+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.util.MC
fun DrawContext.isUntranslatedGuiDrawContext(): Boolean {
return (matrices.peek().positionMatrix.properties() and Matrix4f.PROPERTY_IDENTITY.toInt()) != 0
}
+object GuiRenderLayers {
+ val GUI_TEXTURED_NO_DEPTH = Util.memoize<Identifier, RenderLayer> { texture: Identifier ->
+ RenderLayer.of("firmament_gui_textured_no_depth",
+ VertexFormats.POSITION_TEXTURE_COLOR,
+ VertexFormat.DrawMode.QUADS,
+ RenderLayer.CUTOUT_BUFFER_SIZE,
+ MultiPhaseParameters.builder()
+ .texture(RenderPhase.Texture(texture, TriState.FALSE, false))
+ .program(RenderPhase.POSITION_TEXTURE_COLOR_PROGRAM)
+ .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY)
+ .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
+ .build(false))
+ }
+}
+
+@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)
+
+fun DrawContext.drawGuiTexture(
+ sprite: Identifier,
+ x: Int, y: Int, width: Int, height: Int
+) = this.drawGuiTexture(RenderLayer::getGuiTextured, sprite, x, y, width, height)
+
+fun DrawContext.drawTexture(
+ sprite: Identifier,
+ x: Int,
+ y: Int,
+ u: Float,
+ v: Float,
+ width: Int,
+ height: Int,
+ textureWidth: Int,
+ textureHeight: Int
+) {
+ this.drawTexture(RenderLayer::getGuiTextured,
+ 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
@@ -18,11 +76,12 @@ fun DrawContext.drawLine(fromX: Int, fromY: Int, toX: Int, toY: Int, color: Colo
return
}
RenderSystem.lineWidth(MC.window.scaleFactor.toFloat())
- val buf = this.vertexConsumers.getBuffer(RenderInWorldContext.RenderLayers.LINES)
- buf.vertex(fromX.toFloat(), fromY.toFloat(), 0F).color(color.color)
- .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F)
- buf.vertex(toX.toFloat(), toY.toFloat(), 0F).color(color.color)
- .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F)
- this.draw()
+ draw { vertexConsumers ->
+ val buf = vertexConsumers.getBuffer(RenderInWorldContext.RenderLayers.LINES)
+ buf.vertex(fromX.toFloat(), fromY.toFloat(), 0F).color(color.color)
+ .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F)
+ buf.vertex(toX.toFloat(), toY.toFloat(), 0F).color(color.color)
+ .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F)
+ }
}
diff --git a/src/main/kotlin/util/render/FacingThePlayerContext.kt b/src/main/kotlin/util/render/FacingThePlayerContext.kt
index eb37e35..daa8da9 100644
--- a/src/main/kotlin/util/render/FacingThePlayerContext.kt
+++ b/src/main/kotlin/util/render/FacingThePlayerContext.kt
@@ -76,13 +76,10 @@ class FacingThePlayerContext(val worldContext: RenderInWorldContext) {
u1: Float, v1: Float,
u2: Float, v2: Float,
) {
- RenderSystem.setShaderTexture(0, texture)
- RenderSystem.setShader(GameRenderer::getPositionTexColorProgram)
+ val buf = worldContext.vertexConsumers.getBuffer(RenderLayer.getGuiTexturedOverlay(texture))
val hw = width / 2F
val hh = height / 2F
val matrix4f: Matrix4f = worldContext.matrixStack.peek().positionMatrix
- val buf = Tessellator.getInstance()
- .begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR)
buf.vertex(matrix4f, -hw, -hh, 0F)
.color(-1)
.texture(u1, v1).next()
@@ -95,7 +92,7 @@ class FacingThePlayerContext(val worldContext: RenderInWorldContext) {
buf.vertex(matrix4f, +hw, -hh, 0F)
.color(-1)
.texture(u2, v1).next()
- BufferRenderer.drawWithGlobalProgram(buf.end())
+ worldContext.vertexConsumers.draw()
}
}
diff --git a/src/main/kotlin/util/render/FirmamentShaders.kt b/src/main/kotlin/util/render/FirmamentShaders.kt
index 1094bc2..ba67dbb 100644
--- a/src/main/kotlin/util/render/FirmamentShaders.kt
+++ b/src/main/kotlin/util/render/FirmamentShaders.kt
@@ -1,23 +1,30 @@
package moe.nea.firmament.util.render
-import net.minecraft.client.gl.ShaderProgram
+import net.minecraft.client.gl.Defines
+import net.minecraft.client.gl.ShaderProgramKey
import net.minecraft.client.render.RenderPhase
+import net.minecraft.client.render.VertexFormat
import net.minecraft.client.render.VertexFormats
+import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
-import moe.nea.firmament.events.RegisterCustomShadersEvent
+import moe.nea.firmament.events.DebugInstantiateEvent
+import moe.nea.firmament.util.MC
object FirmamentShaders {
+ val shaders = mutableListOf<ShaderProgramKey>()
+ private fun shader(name: String, format: VertexFormat, defines: Defines): ShaderProgramKey {
+ val key = ShaderProgramKey(Firmament.identifier(name), format, defines)
+ shaders.add(key)
+ return key
+ }
- private lateinit var _LINES: ShaderProgram
- val LINES = RenderPhase.ShaderProgram({ _LINES })
+ val LINES = RenderPhase.ShaderProgram(shader("core/rendertype_lines", VertexFormats.LINES, Defines.EMPTY))
- @Subscribe
- fun registerCustomShaders(event: RegisterCustomShadersEvent) {
- event.register(
- "firmament_rendertype_lines",
- VertexFormats.LINES,
- { _LINES = it },
- )
- }
+ @Subscribe
+ fun debugLoad(event: DebugInstantiateEvent) {
+ shaders.forEach {
+ MC.instance.shaderLoader.getOrCreateProgram(it)
+ }
+ }
}
diff --git a/src/main/kotlin/util/render/RenderCircleProgress.kt b/src/main/kotlin/util/render/RenderCircleProgress.kt
index a2f42b5..9cc383c 100644
--- a/src/main/kotlin/util/render/RenderCircleProgress.kt
+++ b/src/main/kotlin/util/render/RenderCircleProgress.kt
@@ -1,4 +1,3 @@
-
package moe.nea.firmament.util.render
import com.mojang.blaze3d.systems.RenderSystem
@@ -9,7 +8,8 @@ import kotlin.math.atan2
import kotlin.math.tan
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.render.BufferRenderer
-import net.minecraft.client.render.GameRenderer
+import net.minecraft.client.render.RenderLayer
+import net.minecraft.client.render.RenderPhase
import net.minecraft.client.render.Tessellator
import net.minecraft.client.render.VertexFormat.DrawMode
import net.minecraft.client.render.VertexFormats
@@ -17,79 +17,77 @@ import net.minecraft.util.Identifier
object RenderCircleProgress {
- fun renderCircle(
- drawContext: DrawContext,
- texture: Identifier,
- progress: Float,
- u1: Float,
- u2: Float,
- v1: Float,
- v2: Float,
- ) {
- RenderSystem.setShaderTexture(0, texture)
- RenderSystem.setShader(GameRenderer::getPositionTexColorProgram)
- RenderSystem.enableBlend()
- val matrix: Matrix4f = drawContext.matrices.peek().positionMatrix
- val bufferBuilder = Tessellator.getInstance().begin(DrawMode.TRIANGLES, VertexFormats.POSITION_TEXTURE_COLOR)
-
- val corners = listOf(
- Vector2f(0F, -1F),
- Vector2f(1F, -1F),
- Vector2f(1F, 0F),
- Vector2f(1F, 1F),
- Vector2f(0F, 1F),
- Vector2f(-1F, 1F),
- Vector2f(-1F, 0F),
- Vector2f(-1F, -1F),
- )
+ fun renderCircle(
+ drawContext: DrawContext,
+ texture: Identifier,
+ progress: Float,
+ u1: Float,
+ u2: Float,
+ v1: Float,
+ v2: Float,
+ ) {
+ RenderSystem.enableBlend()
+ drawContext.draw {
+ val bufferBuilder = it.getBuffer(RenderLayer.getGuiTexturedOverlay(texture))
+ val matrix: Matrix4f = drawContext.matrices.peek().positionMatrix
- for (i in (0 until 8)) {
- if (progress < i / 8F) {
- break
- }
- val second = corners[(i + 1) % 8]
- val first = corners[i]
- if (progress <= (i + 1) / 8F) {
- val internalProgress = 1 - (progress - i / 8F) * 8F
- val angle = lerpAngle(
- atan2(second.y, second.x),
- atan2(first.y, first.x),
- internalProgress
- )
- if (angle < tau / 8 || angle >= tau * 7 / 8) {
- second.set(1F, tan(angle))
- } else if (angle < tau * 3 / 8) {
- second.set(1 / tan(angle), 1F)
- } else if (angle < tau * 5 / 8) {
- second.set(-1F, -tan(angle))
- } else {
- second.set(-1 / tan(angle), -1F)
- }
- }
+ val corners = listOf(
+ Vector2f(0F, -1F),
+ Vector2f(1F, -1F),
+ Vector2f(1F, 0F),
+ Vector2f(1F, 1F),
+ Vector2f(0F, 1F),
+ Vector2f(-1F, 1F),
+ Vector2f(-1F, 0F),
+ Vector2f(-1F, -1F),
+ )
- fun ilerp(f: Float): Float =
- ilerp(-1f, 1f, f)
+ for (i in (0 until 8)) {
+ if (progress < i / 8F) {
+ break
+ }
+ val second = corners[(i + 1) % 8]
+ val first = corners[i]
+ if (progress <= (i + 1) / 8F) {
+ val internalProgress = 1 - (progress - i / 8F) * 8F
+ val angle = lerpAngle(
+ atan2(second.y, second.x),
+ atan2(first.y, first.x),
+ internalProgress
+ )
+ if (angle < tau / 8 || angle >= tau * 7 / 8) {
+ second.set(1F, tan(angle))
+ } else if (angle < tau * 3 / 8) {
+ second.set(1 / tan(angle), 1F)
+ } else if (angle < tau * 5 / 8) {
+ second.set(-1F, -tan(angle))
+ } else {
+ second.set(-1 / tan(angle), -1F)
+ }
+ }
- bufferBuilder
- .vertex(matrix, second.x, second.y, 0F)
- .texture(lerp(u1, u2, ilerp(second.x)), lerp(v1, v2, ilerp(second.y)))
- .color(-1)
- .next()
- bufferBuilder
- .vertex(matrix, first.x, first.y, 0F)
- .texture(lerp(u1, u2, ilerp(first.x)), lerp(v1, v2, ilerp(first.y)))
- .color(-1)
- .next()
- bufferBuilder
- .vertex(matrix, 0F, 0F, 0F)
- .texture(lerp(u1, u2, ilerp(0F)), lerp(v1, v2, ilerp(0F)))
- .color(-1)
- .next()
- }
- BufferRenderer.drawWithGlobalProgram(bufferBuilder.end())
- RenderSystem.disableBlend()
- }
+ fun ilerp(f: Float): Float =
+ ilerp(-1f, 1f, f)
+ bufferBuilder
+ .vertex(matrix, second.x, second.y, 0F)
+ .texture(lerp(u1, u2, ilerp(second.x)), lerp(v1, v2, ilerp(second.y)))
+ .color(-1)
+ .next()
+ bufferBuilder
+ .vertex(matrix, first.x, first.y, 0F)
+ .texture(lerp(u1, u2, ilerp(first.x)), lerp(v1, v2, ilerp(first.y)))
+ .color(-1)
+ .next()
+ bufferBuilder
+ .vertex(matrix, 0F, 0F, 0F)
+ .texture(lerp(u1, u2, ilerp(0F)), lerp(v1, v2, ilerp(0F)))
+ .color(-1)
+ .next()
+ }
+ }
+ RenderSystem.disableBlend()
+ }
}
diff --git a/src/main/kotlin/util/render/RenderInWorldContext.kt b/src/main/kotlin/util/render/RenderInWorldContext.kt
index b61b9aa..bb58200 100644
--- a/src/main/kotlin/util/render/RenderInWorldContext.kt
+++ b/src/main/kotlin/util/render/RenderInWorldContext.kt
@@ -1,5 +1,3 @@
-
-
package moe.nea.firmament.util.render
import com.mojang.blaze3d.systems.RenderSystem
@@ -8,14 +6,12 @@ import java.lang.Math.pow
import org.joml.Matrix4f
import org.joml.Vector3f
import net.minecraft.client.gl.VertexBuffer
-import net.minecraft.client.render.BufferBuilder
-import net.minecraft.client.render.BufferRenderer
import net.minecraft.client.render.Camera
-import net.minecraft.client.render.GameRenderer
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.RenderPhase
import net.minecraft.client.render.RenderTickCounter
import net.minecraft.client.render.Tessellator
+import net.minecraft.client.render.VertexConsumer
import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.VertexFormat
import net.minecraft.client.render.VertexFormats
@@ -31,273 +27,287 @@ import moe.nea.firmament.util.MC
@RenderContextDSL
class RenderInWorldContext private constructor(
- private val tesselator: Tessellator,
- val matrixStack: MatrixStack,
- private val camera: Camera,
- private val tickCounter: RenderTickCounter,
- val vertexConsumers: VertexConsumerProvider.Immediate,
+ private val tesselator: Tessellator,
+ val matrixStack: MatrixStack,
+ private val camera: Camera,
+ private val tickCounter: RenderTickCounter,
+ val vertexConsumers: VertexConsumerProvider.Immediate,
) {
- object RenderLayers {
- val TRANSLUCENT_TRIS = RenderLayer.of("firmament_translucent_tris",
- VertexFormats.POSITION_COLOR,
- VertexFormat.DrawMode.TRIANGLES,
- RenderLayer.DEFAULT_BUFFER_SIZE,
- false, true,
- RenderLayer.MultiPhaseParameters.builder()
- .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
- .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY)
- .program(RenderPhase.COLOR_PROGRAM)
- .build(false))
- val LINES = RenderLayer.of("firmament_rendertype_lines",
- VertexFormats.LINES,
- VertexFormat.DrawMode.LINES,
- RenderLayer.DEFAULT_BUFFER_SIZE,
- false, false, // do we need translucent? i dont think so
- RenderLayer.MultiPhaseParameters.builder()
- .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
- .program(FirmamentShaders.LINES)
- .build(false)
- )
- }
-
- fun color(color: me.shedaniel.math.Color) {
- color(color.red / 255F, color.green / 255f, color.blue / 255f, color.alpha / 255f)
- }
-
- fun color(red: Float, green: Float, blue: Float, alpha: Float) {
- RenderSystem.setShaderColor(red, green, blue, alpha)
- }
-
- fun block(blockPos: BlockPos) {
- matrixStack.push()
- matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat())
- buildCube(matrixStack.peek().positionMatrix, tesselator)
- matrixStack.pop()
- }
-
- enum class VerticalAlign {
- TOP, BOTTOM, CENTER;
-
- fun align(index: Int, count: Int): Float {
- return when (this) {
- CENTER -> (index - count / 2F) * (1 + MC.font.fontHeight.toFloat())
- BOTTOM -> (index - count) * (1 + MC.font.fontHeight.toFloat())
- TOP -> (index) * (1 + MC.font.fontHeight.toFloat())
- }
- }
- }
-
- fun waypoint(position: BlockPos, vararg label: Text) {
- text(
- position.toCenterPos(),
- *label,
- Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}"),
- background = 0xAA202020.toInt()
- )
- }
-
- fun withFacingThePlayer(position: Vec3d, block: FacingThePlayerContext.() -> Unit) {
- matrixStack.push()
- matrixStack.translate(position.x, position.y, position.z)
- val actualCameraDistance = position.distanceTo(camera.pos)
- val distanceToMoveTowardsCamera = if (actualCameraDistance < 10) 0.0 else -(actualCameraDistance - 10.0)
- val vec = position.subtract(camera.pos).multiply(distanceToMoveTowardsCamera / actualCameraDistance)
- matrixStack.translate(vec.x, vec.y, vec.z)
- matrixStack.multiply(camera.rotation)
- matrixStack.scale(0.025F, -0.025F, 1F)
-
- FacingThePlayerContext(this).run(block)
-
- matrixStack.pop()
- vertexConsumers.drawCurrentLayer()
- }
-
- fun sprite(position: Vec3d, sprite: Sprite, width: Int, height: Int) {
- texture(
- position, sprite.atlasId, width, height, sprite.minU, sprite.minV, sprite.maxU, sprite.maxV
- )
- }
-
- fun texture(
- position: Vec3d, texture: Identifier, width: Int, height: Int,
- u1: Float, v1: Float,
- u2: Float, v2: Float,
- ) {
- withFacingThePlayer(position) {
- texture(texture, width, height, u1, v1, u2, v2)
- }
- }
-
- fun text(position: Vec3d, vararg texts: Text, verticalAlign: VerticalAlign = VerticalAlign.CENTER, background: Int = 0x70808080) {
- withFacingThePlayer(position) {
- text(*texts, verticalAlign = verticalAlign, background = background)
- }
- }
-
- fun tinyBlock(vec3d: Vec3d, size: Float) {
- RenderSystem.setShader(GameRenderer::getPositionColorProgram)
- matrixStack.push()
- matrixStack.translate(vec3d.x, vec3d.y, vec3d.z)
- matrixStack.scale(size, size, size)
- matrixStack.translate(-.5, -.5, -.5)
- buildCube(matrixStack.peek().positionMatrix, tesselator)
- matrixStack.pop()
- }
-
- fun wireframeCube(blockPos: BlockPos, lineWidth: Float = 10F) {
- RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram)
- matrixStack.push()
- RenderSystem.lineWidth(lineWidth / pow(camera.pos.squaredDistanceTo(blockPos.toCenterPos()), 0.25).toFloat())
- matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat())
- buildWireFrameCube(matrixStack.peek(), tesselator)
- matrixStack.pop()
- }
-
- fun line(vararg points: Vec3d, lineWidth: Float = 10F) {
- line(points.toList(), lineWidth)
- }
-
- fun tracer(toWhere: Vec3d, lineWidth: Float = 3f) {
- val cameraForward = Vector3f(0f, 0f, -1f).rotate(camera.rotation)
- line(camera.pos.add(Vec3d(cameraForward)), toWhere, lineWidth = lineWidth)
- }
-
- fun line(points: List<Vec3d>, lineWidth: Float = 10F) {
- RenderSystem.lineWidth(lineWidth)
- val buffer = tesselator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES)
-
- val matrix = matrixStack.peek()
- var lastNormal: Vector3f? = null
- points.zipWithNext().forEach { (a, b) ->
- val normal = Vector3f(b.x.toFloat(), b.y.toFloat(), b.z.toFloat())
- .sub(a.x.toFloat(), a.y.toFloat(), a.z.toFloat())
- .normalize()
- val lastNormal0 = lastNormal ?: normal
- lastNormal = normal
- 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()
- }
-
- RenderLayers.LINES.draw(buffer.end())
- }
-
- companion object {
- private fun doLine(
- matrix: MatrixStack.Entry,
- buf: BufferBuilder,
- i: Float,
- j: Float,
- k: Float,
- x: Float,
- y: Float,
- z: Float
- ) {
- val normal = Vector3f(x, y, z)
- .sub(i, j, k)
- .normalize()
- 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()
- }
-
-
- private fun buildWireFrameCube(matrix: MatrixStack.Entry, tessellator: Tessellator) {
- val buf = tessellator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES)
-
- for (i in 0..1) {
- for (j in 0..1) {
- val i = i.toFloat()
- val j = j.toFloat()
- doLine(matrix, buf, 0F, i, j, 1F, i, j)
- doLine(matrix, buf, i, 0F, j, i, 1F, j)
- doLine(matrix, buf, i, j, 0F, i, j, 1F)
- }
- }
- BufferRenderer.drawWithGlobalProgram(buf.end())
- }
-
- private fun buildCube(matrix: Matrix4f, tessellator: Tessellator) {
- val buf = tessellator.begin(VertexFormat.DrawMode.TRIANGLES, VertexFormats.POSITION_COLOR)
- buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next()
- RenderLayers.TRANSLUCENT_TRIS.draw(buf.end())
- }
-
-
- fun renderInWorld(event: WorldRenderLastEvent, block: RenderInWorldContext. () -> Unit) {
- 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)
-
- val ctx = RenderInWorldContext(
- RenderSystem.renderThreadTesselator(),
- event.matrices,
- event.camera,
- event.tickCounter,
- event.vertexConsumers
- )
-
- block(ctx)
-
- event.matrices.pop()
-
- RenderSystem.setShaderColor(1F, 1F, 1F, 1F)
- VertexBuffer.unbind()
- RenderSystem.enableDepthTest()
- RenderSystem.enableCull()
- RenderSystem.disableBlend()
- }
- }
+ object RenderLayers {
+ val TRANSLUCENT_TRIS = RenderLayer.of("firmament_translucent_tris",
+ VertexFormats.POSITION_COLOR,
+ VertexFormat.DrawMode.TRIANGLES,
+ RenderLayer.CUTOUT_BUFFER_SIZE,
+ false, true,
+ RenderLayer.MultiPhaseParameters.builder()
+ .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
+ .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY)
+ .program(RenderPhase.POSITION_COLOR_PROGRAM)
+ .build(false))
+ val LINES = RenderLayer.of("firmament_rendertype_lines",
+ VertexFormats.LINES,
+ VertexFormat.DrawMode.LINES,
+ RenderLayer.CUTOUT_BUFFER_SIZE,
+ false, false, // do we need translucent? i dont think so
+ RenderLayer.MultiPhaseParameters.builder()
+ .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
+ .program(FirmamentShaders.LINES)
+ .build(false)
+ )
+ val COLORED_QUADS = RenderLayer.of(
+ "firmament_quads",
+ VertexFormats.POSITION_COLOR,
+ VertexFormat.DrawMode.QUADS,
+ RenderLayer.CUTOUT_BUFFER_SIZE,
+ false, true,
+ RenderLayer.MultiPhaseParameters.builder()
+ .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
+ .program(RenderPhase.POSITION_COLOR_PROGRAM)
+ .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY)
+ .build(false)
+ )
+ }
+
+ @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())
+ buildCube(matrixStack.peek().positionMatrix, vertexConsumers.getBuffer(RenderLayers.COLORED_QUADS), color)
+ matrixStack.pop()
+ }
+
+ enum class VerticalAlign {
+ TOP, BOTTOM, CENTER;
+
+ fun align(index: Int, count: Int): Float {
+ return when (this) {
+ CENTER -> (index - count / 2F) * (1 + MC.font.fontHeight.toFloat())
+ BOTTOM -> (index - count) * (1 + MC.font.fontHeight.toFloat())
+ TOP -> (index) * (1 + MC.font.fontHeight.toFloat())
+ }
+ }
+ }
+
+ fun waypoint(position: BlockPos, vararg label: Text) {
+ text(
+ position.toCenterPos(),
+ *label,
+ Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}"),
+ background = 0xAA202020.toInt()
+ )
+ }
+
+ fun withFacingThePlayer(position: Vec3d, block: FacingThePlayerContext.() -> Unit) {
+ matrixStack.push()
+ matrixStack.translate(position.x, position.y, position.z)
+ val actualCameraDistance = position.distanceTo(camera.pos)
+ val distanceToMoveTowardsCamera = if (actualCameraDistance < 10) 0.0 else -(actualCameraDistance - 10.0)
+ val vec = position.subtract(camera.pos).multiply(distanceToMoveTowardsCamera / actualCameraDistance)
+ matrixStack.translate(vec.x, vec.y, vec.z)
+ matrixStack.multiply(camera.rotation)
+ matrixStack.scale(0.025F, -0.025F, 1F)
+
+ FacingThePlayerContext(this).run(block)
+
+ matrixStack.pop()
+ vertexConsumers.drawCurrentLayer()
+ }
+
+ fun sprite(position: Vec3d, sprite: Sprite, width: Int, height: Int) {
+ texture(
+ position, sprite.atlasId, width, height, sprite.minU, sprite.minV, sprite.maxU, sprite.maxV
+ )
+ }
+
+ fun texture(
+ position: Vec3d, texture: Identifier, width: Int, height: Int,
+ u1: Float, v1: Float,
+ u2: Float, v2: Float,
+ ) {
+ withFacingThePlayer(position) {
+ texture(texture, width, height, u1, v1, u2, v2)
+ }
+ }
+
+ fun text(
+ position: Vec3d,
+ vararg texts: Text,
+ verticalAlign: VerticalAlign = VerticalAlign.CENTER,
+ background: Int = 0x70808080
+ ) {
+ withFacingThePlayer(position) {
+ text(*texts, verticalAlign = verticalAlign, background = background)
+ }
+ }
+
+ fun tinyBlock(vec3d: Vec3d, size: Float, color: Int) {
+ matrixStack.push()
+ matrixStack.translate(vec3d.x, vec3d.y, vec3d.z)
+ matrixStack.scale(size, size, size)
+ matrixStack.translate(-.5, -.5, -.5)
+ buildCube(matrixStack.peek().positionMatrix, vertexConsumers.getBuffer(RenderLayers.COLORED_QUADS), color)
+ matrixStack.pop()
+ vertexConsumers.draw()
+ }
+
+ fun wireframeCube(blockPos: BlockPos, lineWidth: Float = 10F) {
+ val buf = vertexConsumers.getBuffer(RenderLayer.LINES)
+ matrixStack.push()
+ // 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())
+ buildWireFrameCube(matrixStack.peek(), buf)
+ matrixStack.pop()
+ vertexConsumers.draw()
+ }
+
+ fun line(vararg points: Vec3d, lineWidth: Float = 10F) {
+ line(points.toList(), lineWidth)
+ }
+
+ fun tracer(toWhere: Vec3d, lineWidth: Float = 3f) {
+ val cameraForward = Vector3f(0f, 0f, -1f).rotate(camera.rotation)
+ line(camera.pos.add(Vec3d(cameraForward)), toWhere, lineWidth = lineWidth)
+ }
+
+ fun line(points: List<Vec3d>, lineWidth: Float = 10F) {
+ RenderSystem.lineWidth(lineWidth)
+ // TODO: replace with renderlayers
+ val buffer = tesselator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES)
+
+ val matrix = matrixStack.peek()
+ var lastNormal: Vector3f? = null
+ points.zipWithNext().forEach { (a, b) ->
+ val normal = Vector3f(b.x.toFloat(), b.y.toFloat(), b.z.toFloat())
+ .sub(a.x.toFloat(), a.y.toFloat(), a.z.toFloat())
+ .normalize()
+ val lastNormal0 = lastNormal ?: normal
+ lastNormal = normal
+ 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()
+ }
+
+ RenderLayers.LINES.draw(buffer.end())
+ }
+ // TODO: put the favourite icons in front of items again
+
+ companion object {
+ private fun doLine(
+ matrix: MatrixStack.Entry,
+ buf: VertexConsumer,
+ i: Float,
+ j: Float,
+ k: Float,
+ x: Float,
+ y: Float,
+ z: Float
+ ) {
+ val normal = Vector3f(x, y, z)
+ .sub(i, j, k)
+ .normalize()
+ 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()
+ }
+
+
+ private fun buildWireFrameCube(matrix: MatrixStack.Entry, buf: VertexConsumer) {
+ for (i in 0..1) {
+ for (j in 0..1) {
+ val i = i.toFloat()
+ val j = j.toFloat()
+ doLine(matrix, buf, 0F, i, j, 1F, i, j)
+ doLine(matrix, buf, i, 0F, j, i, 1F, j)
+ doLine(matrix, buf, i, j, 0F, i, j, 1F)
+ }
+ }
+ }
+
+ private fun buildCube(matrix: Matrix4f, buf: VertexConsumer, color: Int) {
+ // Y-
+ buf.vertex(matrix, 0F, 0F, 0F).color(color)
+ buf.vertex(matrix, 0F, 0F, 1F).color(color)
+ buf.vertex(matrix, 1F, 0F, 1F).color(color)
+ buf.vertex(matrix, 1F, 0F, 0F).color(color)
+ // Y+
+ buf.vertex(matrix, 0F, 1F, 0F).color(color)
+ buf.vertex(matrix, 1F, 1F, 0F).color(color)
+ buf.vertex(matrix, 1F, 1F, 1F).color(color)
+ buf.vertex(matrix, 0F, 1F, 1F).color(color)
+ // X-
+ buf.vertex(matrix, 0F, 0F, 0F).color(color)
+ buf.vertex(matrix, 0F, 0F, 1F).color(color)
+ buf.vertex(matrix, 0F, 1F, 1F).color(color)
+ buf.vertex(matrix, 0F, 1F, 0F).color(color)
+ // X+
+ buf.vertex(matrix, 1F, 0F, 0F).color(color)
+ buf.vertex(matrix, 1F, 1F, 0F).color(color)
+ buf.vertex(matrix, 1F, 1F, 1F).color(color)
+ buf.vertex(matrix, 1F, 0F, 1F).color(color)
+ // Z-
+ buf.vertex(matrix, 0F, 0F, 0F).color(color)
+ buf.vertex(matrix, 1F, 0F, 0F).color(color)
+ buf.vertex(matrix, 1F, 1F, 0F).color(color)
+ buf.vertex(matrix, 0F, 1F, 0F).color(color)
+ // Z+
+ buf.vertex(matrix, 0F, 0F, 1F).color(color)
+ buf.vertex(matrix, 0F, 1F, 1F).color(color)
+ buf.vertex(matrix, 1F, 1F, 1F).color(color)
+ buf.vertex(matrix, 1F, 0F, 1F).color(color)
+ }
+
+
+ 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)
+
+ val ctx = RenderInWorldContext(
+ RenderSystem.renderThreadTesselator(),
+ event.matrices,
+ event.camera,
+ event.tickCounter,
+ event.vertexConsumers
+ )
+
+ block(ctx)
+
+ event.matrices.pop()
+ event.vertexConsumers.draw()
+ RenderSystem.setShaderColor(1F, 1F, 1F, 1F)
+ VertexBuffer.unbind()
+ RenderSystem.enableDepthTest()
+ RenderSystem.enableCull()
+ RenderSystem.disableBlend()
+ }
+ }
}