feat: Add macro wheels
This commit is contained in:
40
src/main/kotlin/util/collections/RangeUtil.kt
Normal file
40
src/main/kotlin/util/collections/RangeUtil.kt
Normal file
@@ -0,0 +1,40 @@
|
||||
package moe.nea.firmament.util.collections
|
||||
|
||||
import kotlin.math.floor
|
||||
|
||||
val ClosedFloatingPointRange<Float>.centre get() = (endInclusive + start) / 2
|
||||
|
||||
fun ClosedFloatingPointRange<Float>.nonNegligibleSubSectionsAlignedWith(
|
||||
interval: Float
|
||||
): Iterable<Float> {
|
||||
require(interval.isFinite())
|
||||
val range = this
|
||||
return object : Iterable<Float> {
|
||||
override fun iterator(): Iterator<Float> {
|
||||
return object : FloatIterator() {
|
||||
var polledValue: Float = range.start
|
||||
var lastValue: Float = polledValue
|
||||
|
||||
override fun nextFloat(): Float {
|
||||
if (!hasNext()) throw NoSuchElementException()
|
||||
lastValue = polledValue
|
||||
polledValue = Float.NaN
|
||||
return lastValue
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
if (!polledValue.isNaN()) {
|
||||
return true
|
||||
}
|
||||
if (lastValue == range.endInclusive)
|
||||
return false
|
||||
polledValue = (floor(lastValue / interval) + 1) * interval
|
||||
if (polledValue > range.endInclusive) {
|
||||
polledValue = range.endInclusive
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
46
src/main/kotlin/util/math/Projections.kt
Normal file
46
src/main/kotlin/util/math/Projections.kt
Normal file
@@ -0,0 +1,46 @@
|
||||
package moe.nea.firmament.util.math
|
||||
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
import net.minecraft.util.math.Vec2f
|
||||
import moe.nea.firmament.util.render.wrapAngle
|
||||
|
||||
object Projections {
|
||||
object Two {
|
||||
val ε = 1e-6
|
||||
val π = moe.nea.firmament.util.render.π
|
||||
val τ = 2 * π
|
||||
|
||||
fun isNullish(float: Float) = float.absoluteValue < ε
|
||||
|
||||
fun xInterceptOfLine(origin: Vec2f, direction: Vec2f): Vec2f? {
|
||||
if (isNullish(direction.x))
|
||||
return Vec2f(origin.x, 0F)
|
||||
if (isNullish(direction.y))
|
||||
return null
|
||||
|
||||
val slope = direction.y / direction.x
|
||||
return Vec2f(origin.x - origin.y / slope, 0F)
|
||||
}
|
||||
|
||||
fun interceptAlongCardinal(distanceFromAxis: Float, slope: Float): Float? {
|
||||
if (isNullish(slope))
|
||||
return null
|
||||
return -distanceFromAxis / slope
|
||||
}
|
||||
|
||||
fun projectAngleOntoUnitBox(angleRadians: Double): Vec2f {
|
||||
val angleRadians = wrapAngle(angleRadians)
|
||||
val cx = cos(angleRadians)
|
||||
val cy = sin(angleRadians)
|
||||
|
||||
val ex = 1 / cx.absoluteValue
|
||||
val ey = 1 / cy.absoluteValue
|
||||
|
||||
val e = minOf(ex, ey)
|
||||
|
||||
return Vec2f((cx * e).toFloat(), (cy * e).toFloat())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
package util.render
|
||||
|
||||
import com.mojang.blaze3d.pipeline.BlendFunction
|
||||
import com.mojang.blaze3d.pipeline.RenderPipeline
|
||||
import com.mojang.blaze3d.platform.DepthTestFunction
|
||||
import com.mojang.blaze3d.vertex.VertexFormat.DrawMode
|
||||
import java.util.function.Function
|
||||
import net.minecraft.client.gl.RenderPipelines
|
||||
import net.minecraft.client.gl.UniformType
|
||||
import net.minecraft.client.render.RenderLayer
|
||||
import net.minecraft.client.render.RenderPhase
|
||||
import net.minecraft.client.render.VertexFormats
|
||||
@@ -38,23 +40,33 @@ object CustomRenderPipelines {
|
||||
.withCull(false)
|
||||
.withDepthWrite(false)
|
||||
.build()
|
||||
|
||||
val CIRCLE_FILTER_TRANSLUCENT_GUI_TRIS =
|
||||
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)
|
||||
.withFragmentShader(Firmament.identifier("circle_discard_color"))
|
||||
.withBlend(BlendFunction.TRANSLUCENT)
|
||||
.build()
|
||||
}
|
||||
|
||||
object CustomRenderLayers {
|
||||
|
||||
|
||||
inline fun memoizeTextured(crossinline func: (Identifier) -> RenderLayer) = memoize(func)
|
||||
inline fun <T, R> memoize(crossinline func: (T) -> R): Function<T, R> {
|
||||
return Util.memoize { it: T -> func(it) }
|
||||
}
|
||||
|
||||
val GUI_TEXTURED_NO_DEPTH_TRIS = memoizeTextured { texture ->
|
||||
RenderLayer.of("firmament_gui_textured_overlay_tris",
|
||||
RenderLayer.DEFAULT_BUFFER_SIZE,
|
||||
CustomRenderPipelines.GUI_TEXTURED_NO_DEPTH_TRIS,
|
||||
RenderLayer.MultiPhaseParameters.builder().texture(
|
||||
RenderPhase.Texture(texture, TriState.DEFAULT, false))
|
||||
.build(false))
|
||||
RenderLayer.of(
|
||||
"firmament_gui_textured_overlay_tris",
|
||||
RenderLayer.DEFAULT_BUFFER_SIZE,
|
||||
CustomRenderPipelines.GUI_TEXTURED_NO_DEPTH_TRIS,
|
||||
RenderLayer.MultiPhaseParameters.builder().texture(
|
||||
RenderPhase.Texture(texture, TriState.DEFAULT, false)
|
||||
)
|
||||
.build(false)
|
||||
)
|
||||
}
|
||||
val LINES = RenderLayer.of(
|
||||
"firmament_lines",
|
||||
@@ -71,4 +83,13 @@ object CustomRenderLayers {
|
||||
.lightmap(RenderPhase.DISABLE_LIGHTMAP)
|
||||
.build(false)
|
||||
)
|
||||
|
||||
val TRANSLUCENT_CIRCLE_GUI =
|
||||
RenderLayer.of(
|
||||
"firmament_circle_gui",
|
||||
RenderLayer.DEFAULT_BUFFER_SIZE,
|
||||
CustomRenderPipelines.CIRCLE_FILTER_TRANSLUCENT_GUI_TRIS,
|
||||
RenderLayer.MultiPhaseParameters.builder()
|
||||
.build(false)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
package moe.nea.firmament.util.render
|
||||
|
||||
import com.mojang.blaze3d.pipeline.RenderPipeline
|
||||
import com.mojang.blaze3d.platform.DepthTestFunction
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.VertexFormat.DrawMode
|
||||
import me.shedaniel.math.Color
|
||||
import org.joml.Matrix4f
|
||||
import util.render.CustomRenderLayers
|
||||
import net.minecraft.client.gl.RenderPipelines
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.render.RenderLayer
|
||||
import net.minecraft.client.render.VertexFormats
|
||||
import net.minecraft.util.Identifier
|
||||
import moe.nea.firmament.Firmament
|
||||
import moe.nea.firmament.util.MC
|
||||
|
||||
fun DrawContext.isUntranslatedGuiDrawContext(): Boolean {
|
||||
@@ -64,9 +58,10 @@ fun DrawContext.drawLine(fromX: Int, fromY: Int, toX: Int, toY: Int, color: Colo
|
||||
RenderSystem.lineWidth(MC.window.scaleFactor.toFloat())
|
||||
draw { vertexConsumers ->
|
||||
val buf = vertexConsumers.getBuffer(CustomRenderLayers.LINES)
|
||||
buf.vertex(fromX.toFloat(), fromY.toFloat(), 0F).color(color.color)
|
||||
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(toX.toFloat(), toY.toFloat(), 0F).color(color.color)
|
||||
buf.vertex(matrix, toX.toFloat(), toY.toFloat(), 0F).color(color.color)
|
||||
.normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,36 @@
|
||||
|
||||
package moe.nea.firmament.util.render
|
||||
|
||||
import me.shedaniel.math.Color
|
||||
|
||||
val pi = Math.PI
|
||||
val tau = Math.PI * 2
|
||||
fun lerpAngle(a: Float, b: Float, progress: Float): Float {
|
||||
// TODO: there is at least 10 mods to many in here lol
|
||||
val shortestAngle = ((((b.mod(tau) - a.mod(tau)).mod(tau)) + tau + pi).mod(tau)) - pi
|
||||
return ((a + (shortestAngle) * progress).mod(tau)).toFloat()
|
||||
val π = Math.PI
|
||||
val τ = Math.PI * 2
|
||||
fun lerpAngle(a: Float, b: Float, progress: Float): Float {
|
||||
// TODO: there is at least 10 mods to many in here lol
|
||||
val shortestAngle = ((((b.mod(τ) - a.mod(τ)).mod(τ)) + τ + π).mod(τ)) - π
|
||||
return ((a + (shortestAngle) * progress).mod(τ)).toFloat()
|
||||
}
|
||||
|
||||
fun wrapAngle(angle: Float): Float = (angle.mod(τ) + τ).mod(τ).toFloat()
|
||||
fun wrapAngle(angle: Double): Double = (angle.mod(τ) + τ).mod(τ)
|
||||
|
||||
fun lerp(a: Float, b: Float, progress: Float): Float {
|
||||
return a + (b - a) * progress
|
||||
return a + (b - a) * progress
|
||||
}
|
||||
|
||||
fun lerp(a: Int, b: Int, progress: Float): Int {
|
||||
return (a + (b - a) * progress).toInt()
|
||||
return (a + (b - a) * progress).toInt()
|
||||
}
|
||||
|
||||
fun ilerp(a: Float, b: Float, value: Float): Float {
|
||||
return (value - a) / (b - a)
|
||||
return (value - a) / (b - a)
|
||||
}
|
||||
|
||||
fun lerp(a: Color, b: Color, progress: Float): Color {
|
||||
return Color.ofRGBA(
|
||||
lerp(a.red, b.red, progress),
|
||||
lerp(a.green, b.green, progress),
|
||||
lerp(a.blue, b.blue, progress),
|
||||
lerp(a.alpha, b.alpha, progress),
|
||||
)
|
||||
return Color.ofRGBA(
|
||||
lerp(a.red, b.red, progress),
|
||||
lerp(a.green, b.green, progress),
|
||||
lerp(a.blue, b.blue, progress),
|
||||
lerp(a.alpha, b.alpha, progress),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,87 @@
|
||||
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.Vector2f
|
||||
import util.render.CustomRenderLayers
|
||||
import kotlin.math.atan2
|
||||
import kotlin.math.tan
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.render.BufferBuilder
|
||||
import net.minecraft.client.render.RenderLayer
|
||||
import net.minecraft.client.util.BufferAllocator
|
||||
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
|
||||
|
||||
object RenderCircleProgress {
|
||||
|
||||
fun renderCircularSlice(
|
||||
drawContext: DrawContext,
|
||||
layer: RenderLayer,
|
||||
u1: Float,
|
||||
u2: Float,
|
||||
v1: Float,
|
||||
v2: Float,
|
||||
angleRadians: ClosedFloatingPointRange<Float>,
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun renderCircle(
|
||||
drawContext: DrawContext,
|
||||
texture: Identifier,
|
||||
@@ -20,66 +91,11 @@ object RenderCircleProgress {
|
||||
v1: Float,
|
||||
v2: Float,
|
||||
) {
|
||||
drawContext.draw {
|
||||
val bufferBuilder = it.getBuffer(CustomRenderLayers.GUI_TEXTURED_NO_DEPTH_TRIS.apply(texture))
|
||||
val matrix: Matrix4f = drawContext.matrices.peek().positionMatrix
|
||||
|
||||
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),
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
renderCircularSlice(
|
||||
drawContext,
|
||||
CustomRenderLayers.GUI_TEXTURED_NO_DEPTH_TRIS.apply(texture),
|
||||
u1, u2, v1, v2,
|
||||
(-τ / 4).toFloat()..(progress * τ - τ / 4).toFloat()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user