1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
package moe.nea.firmament.util.render
import com.mojang.blaze3d.vertex.VertexFormat
import util.render.CustomRenderLayers
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.navigation.ScreenRectangle
import com.mojang.blaze3d.vertex.BufferBuilder
import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.MultiBufferSource
import com.mojang.blaze3d.vertex.ByteBufferBuilder
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.resources.ResourceLocation
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: RenderType.CompositeRenderType,
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: ScreenRectangle?,
override val scissorArea: ScreenRectangle?,
) : MultiSpecialGuiRenderState() {
override fun createRenderer(vertexConsumers: MultiBufferSource.BufferSource): MultiSpecialGuiRenderer<out MultiSpecialGuiRenderState> {
return Renderer(vertexConsumers)
}
}
class Renderer(vertexConsumers: MultiBufferSource.BufferSource) :
MultiSpecialGuiRenderer<State>(vertexConsumers) {
override fun renderToTexture(
state: State,
matrices: PoseStack
) {
matrices.pushPose()
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.last().pose()
ByteBufferBuilder(state.layer.format().vertexSize * sections.size * 3).use { allocator ->
val bufferBuilder = BufferBuilder(allocator, VertexFormat.Mode.TRIANGLES, state.layer.format())
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
.addVertex(matrix, secondPoint.x, secondPoint.y, 0F)
.setUv(lerp(u1, u2, ilerp(secondPoint.x)), lerp(v1, v2, ilerp(secondPoint.y)))
.setColor(color)
bufferBuilder
.addVertex(matrix, firstPoint.x, firstPoint.y, 0F)
.setUv(lerp(u1, u2, ilerp(firstPoint.x)), lerp(v1, v2, ilerp(firstPoint.y)))
.setColor(color)
bufferBuilder
.addVertex(matrix, 0F, 0F, 0F)
.setUv(lerp(u1, u2, ilerp(0F)), lerp(v1, v2, ilerp(0F)))
.setColor(color)
}
bufferBuilder.buildOrThrow().use { buffer ->
if (state.innerCutoutRadius <= 0) {
state.layer.draw(buffer)
return
}
CustomRenderPassHelper(
{ "RenderCircleProgress" },
VertexFormat.Mode.TRIANGLES,
state.layer.format(),
MC.instance.mainRenderTarget,
false,
).use { renderPass ->
renderPass.uploadVertices(buffer)
renderPass.setAllDefaultUniforms()
renderPass.setPipeline(state.layer.renderPipeline)
renderPass.setUniform("CutoutRadius", 4) {
it.putFloat(state.innerCutoutRadius)
}
renderPass.draw()
}
}
}
matrices.popPose()
}
override fun getRenderStateClass(): Class<State> {
return State::class.java
}
override fun getTextureLabel(): String {
return "Firmament Circle"
}
}
fun renderCircularSlice(
drawContext: GuiGraphics,
layer: RenderType.CompositeRenderType,
u1: Float,
u2: Float,
v1: Float,
v2: Float,
angleRadians: ClosedFloatingPointRange<Float>,
color: Int = -1,
innerCutoutRadius: Float = 0F
) {
val screenRect = ScreenRectangle(-1, -1, 2, 2).transformAxisAligned(drawContext.pose())
drawContext.guiRenderState.submitPicturesInPictureState(
State(
screenRect.left(), screenRect.right(),
screenRect.top(), screenRect.bottom(),
layer,
u1, u2, v1, v2,
angleRadians,
color,
innerCutoutRadius,
screenRect.width / 2F,
screenRect,
null
)
)
}
fun renderCircle(
drawContext: GuiGraphics,
texture: ResourceLocation,
progress: Float,
u1: Float,
u2: Float,
v1: Float,
v2: Float,
color: Int = -1
) {
renderCircularSlice(
drawContext,
CustomRenderLayers.GUI_TEXTURED_NO_DEPTH_TRIS.apply(texture),
u1, u2, v1, v2,
(-τ / 4).toFloat()..(progress * τ - τ / 4).toFloat(),
color = color
)
}
}
|