-
Notifications
You must be signed in to change notification settings - Fork 30
/
GradientComponent.kt
145 lines (129 loc) · 5.46 KB
/
GradientComponent.kt
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
package gg.essential.elementa.components
import gg.essential.elementa.state.BasicState
import gg.essential.elementa.state.MappedState
import gg.essential.elementa.state.State
import gg.essential.universal.UGraphics
import gg.essential.universal.UMatrixStack
import org.lwjgl.opengl.GL11
import java.awt.Color
/**
* Variant of [UIBlock] with two colours that fade into each other in a
* gradient pattern.
*/
open class GradientComponent constructor(
startColor: State<Color>,
endColor: State<Color>,
direction: State<GradientDirection>
) : UIBlock(Color(0, 0, 0, 0)) {
@JvmOverloads constructor(
startColor: Color = Color.WHITE,
endColor: Color = Color.WHITE,
direction: GradientDirection = GradientDirection.TOP_TO_BOTTOM
): this(BasicState(startColor), BasicState(endColor), BasicState(direction))
private val startColorState: MappedState<Color, Color> = startColor.map { it }
private val endColorState: MappedState<Color, Color> = endColor.map{ it }
private val directionState: MappedState<GradientDirection, GradientDirection> = direction.map { it }
fun getStartColor(): Color = startColorState.get()
fun setStartColor(startColor: Color) = apply {
startColorState.set(startColor)
}
fun bindStartColor(newStartColorState: State<Color>) = apply {
startColorState.rebind(newStartColorState)
}
fun getEndColor(): Color = endColorState.get()
fun setEndColor(endColor: Color) = apply {
endColorState.set(endColor)
}
fun bindEndColor(newEndColorState: State<Color>) = apply {
endColorState.rebind(newEndColorState)
}
fun getDirection(): GradientDirection = directionState.get()
fun setDirection(direction: GradientDirection) = apply {
directionState.set(direction)
}
fun bindDirection(newDirectionState: State<GradientDirection>) = apply {
directionState.rebind(newDirectionState)
}
override fun drawBlock(matrixStack: UMatrixStack, x: Double, y: Double, x2: Double, y2: Double) {
drawGradientBlock(
matrixStack,
x,
y,
x2,
y2,
startColorState.get(),
endColorState.get(),
directionState.get()
)
}
enum class GradientDirection {
TOP_TO_BOTTOM,
BOTTOM_TO_TOP,
LEFT_TO_RIGHT,
RIGHT_TO_LEFT;
fun getGradientColors(startColor: Color, endColor: Color): GradientColors = when (this) {
TOP_TO_BOTTOM -> GradientColors(startColor, startColor, endColor, endColor)
BOTTOM_TO_TOP -> GradientColors(endColor, endColor, startColor, startColor)
LEFT_TO_RIGHT -> GradientColors(startColor, endColor, startColor, endColor)
RIGHT_TO_LEFT -> GradientColors(endColor, startColor, endColor, startColor)
}
}
data class GradientColors(val topLeft: Color, val topRight: Color, val bottomLeft: Color, val bottomRight: Color)
companion object {
@Deprecated(
"This method does not allow for gradients to be rendered at sub-pixel positions. Use the Double variant instead and do not cast to Int.",
ReplaceWith("drawGradientBlock(x1.toDouble(), y1.toDouble(), x2.toDouble(), y2.toDouble(), startColor, endColor, direction)")
)
fun drawGradientBlock(
x1: Int,
y1: Int,
x2: Int,
y2: Int,
startColor: Color,
endColor: Color,
direction: GradientDirection
): Unit = drawGradientBlock(x1.toDouble(), y1.toDouble(), x2.toDouble(), y2.toDouble(), startColor, endColor, direction)
@Deprecated(
UMatrixStack.Compat.DEPRECATED,
ReplaceWith("drawGradientBlock(matrixStack, x1, y1, x2, y2, startColor, endColor, direction)"),
)
fun drawGradientBlock(
x1: Double,
y1: Double,
x2: Double,
y2: Double,
startColor: Color,
endColor: Color,
direction: GradientDirection
) = drawGradientBlock(UMatrixStack(), x1, y1, x2, y2, startColor, endColor, direction)
/**
* Draw a rectangle with a gradient effect.
*/
fun drawGradientBlock(
matrixStack: UMatrixStack,
x1: Double,
y1: Double,
x2: Double,
y2: Double,
startColor: Color,
endColor: Color,
direction: GradientDirection
) {
UGraphics.enableBlend()
UGraphics.disableAlpha()
UGraphics.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO)
UGraphics.shadeModel(GL11.GL_SMOOTH)
val colours = direction.getGradientColors(startColor, endColor)
val tessellator = UGraphics.getFromTessellator()
tessellator.beginWithDefaultShader(UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_COLOR)
tessellator.pos(matrixStack, x2, y1, 0.0).color(colours.topRight).endVertex()
tessellator.pos(matrixStack, x1, y1, 0.0).color(colours.topLeft).endVertex()
tessellator.pos(matrixStack, x1, y2, 0.0).color(colours.bottomLeft).endVertex()
tessellator.pos(matrixStack, x2, y2, 0.0).color(colours.bottomRight).endVertex()
tessellator.drawDirect()
UGraphics.shadeModel(GL11.GL_FLAT)
UGraphics.disableBlend()
UGraphics.enableAlpha()
}
}
}