Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 60 additions & 46 deletions korge-core/src/korlibs/graphics/shader/shaders.kt
Original file line number Diff line number Diff line change
Expand Up @@ -490,85 +490,93 @@ data class Program(val vertex: VertexShader, val fragment: FragmentShader, val n
val out: Output get() = Output
//fun out(to: Operand) = Stm.Set(if (type == ShaderType.VERTEX) out_Position else out_FragColor, to)

fun sin(arg: Operand): Operand = Func("sin", arg)
fun cos(arg: Operand): Operand = Func("cos", arg)
fun tan(arg: Operand): Operand = Func("tan", arg)

fun asin(arg: Operand): Operand = Func("asin", arg)
fun acos(arg: Operand): Operand = Func("acos", arg)
fun atan(y_over_x: Operand): Operand = Func("atan", y_over_x)
fun atan(y: Operand, x: Operand): Operand = Func("atan", y, x)
fun sin(angle: Operand): Operand = Func("sin", angle, type = angle.type)
fun cos(angle: Operand): Operand = Func("cos", angle, type = angle.type)
fun tan(angle: Operand): Operand = Func("tan", angle, type = angle.type)

fun asin(x: Operand): Operand = Func("asin", x, type = x.type)
fun acos(x: Operand): Operand = Func("acos", x, type = x.type)
fun atan(yOverX: Operand): Operand = Func("atan", yOverX, type = yOverX.type)
fun atan(y: Operand, x: Operand): Operand = Func("atan", y, x, type = y.type)

fun sinh(x: Operand): Operand = Func("sinh", x, type = x.type)
fun cosh(x: Operand): Operand = Func("cosh", x, type = x.type)
fun tanh(x: Operand): Operand = Func("tanh", x, type = x.type)
fun asinh(x: Operand): Operand = Func("asinh", x, type = x.type)
fun acosh(x: Operand): Operand = Func("acosh", x, type = x.type)
fun atanh(x: Operand): Operand = Func("atanh", x, type = x.type)

// @TODO: https://en.wikipedia.org/wiki/Atan2#Definition_and_computation (IF chain)
//fun atan2(a: Operand, b: Operand): Operand = atan(a / b) * 2f.lit

fun radians(arg: Operand): Operand = Func("radians", arg)
fun degrees(arg: Operand): Operand = Func("degrees", arg)
fun radians(degrees: Operand): Operand = Func("radians", degrees, type = degrees.type)
fun degrees(radians: Operand): Operand = Func("degrees", radians, type = radians.type)

// Sampling
fun texture2D(sampler: Operand, coord: Operand): Operand = Func("texture2D", sampler, coord, type = VarType.Float4)
fun texture(sampler: Operand, P: Operand): Operand = Func("texture", sampler, P)
fun texture(sampler: Operand, P: Operand): Operand = Func("texture", sampler, P, type = VarType.Float4) // @TODO: calculate correct result type based on operand types

fun func(name: String, vararg args: Operand): Operand = Func(name, *args.map { it }.toTypedArray())
fun func(name: String, vararg args: Operand, type: VarType = VarType.Float1): Operand = Func(name, *args.map { it }.toTypedArray(), type = type)

fun TERNARY(cond: Operand, otrue: Operand, ofalse: Operand): Operand = Ternary(cond, otrue, ofalse)

// CAST
fun int(v: Operand): Operand = Func("int", v)
fun float(v: Operand): Operand = Func("float", v)

fun pow(b: Operand, e: Operand): Operand = Func("pow", b, e)
fun exp(v: Operand): Operand = Func("exp", v)
fun exp2(v: Operand): Operand = Func("exp2", v)
fun log(v: Operand): Operand = Func("log", v)
fun log2(v: Operand): Operand = Func("log2", v)
fun sqrt(v: Operand): Operand = Func("sqrt", v)
fun inversesqrt(v: Operand): Operand = Func("inversesqrt", v)

fun abs(v: Operand): Operand = Func("abs", v)
fun sign(v: Operand): Operand = Func("sign", v)
fun ceil(v: Operand): Operand = Func("ceil", v)
fun floor(v: Operand): Operand = Func("floor", v)
fun int(v: Operand): Operand = Func("int", v, type = VarType.Int1)
fun float(v: Operand): Operand = Func("float", v, type = VarType.Float1)

fun pow(b: Operand, e: Operand): Operand = Func("pow", b, e, type = b.type)
fun exp(v: Operand): Operand = Func("exp", v, type = v.type)
fun exp2(v: Operand): Operand = Func("exp2", v, type = v.type)
fun log(v: Operand): Operand = Func("log", v, type = v.type)
fun log2(v: Operand): Operand = Func("log2", v, type = v.type)
fun sqrt(v: Operand): Operand = Func("sqrt", v, type = v.type)
fun inversesqrt(v: Operand): Operand = Func("inversesqrt", v, type = v.type)

fun abs(v: Operand): Operand = Func("abs", v, type = v.type)
fun sign(v: Operand): Operand = Func("sign", v, type = v.type)
fun ceil(v: Operand): Operand = Func("ceil", v, type = v.type)
fun floor(v: Operand): Operand = Func("floor", v, type = v.type)

/** The fractional part of v. This is calculated as v - floor(v). */
fun fract(v: Operand): Operand = Func("fract", v)
fun fract(v: Operand): Operand = Func("fract", v, type = v.type)

fun clamp01(v: Operand): Operand = clamp(v, 0f.lit, 1f.lit)
fun clamp(v: Operand, min: Operand, max: Operand): Operand = Func("clamp", v, min, max)
fun min(a: Operand, b: Operand): Operand = Func("min", a, b)
fun max(a: Operand, b: Operand): Operand = Func("max", a, b)
fun mod(a: Operand, b: Operand): Operand = Func("mod", a, b)
fun clamp(v: Operand, min: Operand, max: Operand): Operand = Func("clamp", v, min, max, type = v.type)
fun min(a: Operand, b: Operand): Operand = Func("min", a, b, type = a.type)
fun max(a: Operand, b: Operand): Operand = Func("max", a, b, type = a.type)
fun mod(a: Operand, b: Operand): Operand = Func("mod", a, b, type = a.type)

//fun lerp(a: Operand, b: Operand, c: Operand): Operand = Func("lerp", a, b, c)

// https://learnwebgl.brown37.net/12_shader_language/documents/webgl-reference-card-1_0.pdf
// #extension GL_OES_standard_derivatives : enable
// https://stackoverflow.com/questions/68573364/enable-extension-and-fwidth-in-glsl
fun fwidth(a: Operand): Operand = Func("fwidth", a)
fun dFdx(a: Operand): Operand = Func("dFdx", a)
fun dFdy(a: Operand): Operand = Func("dFdy", a)
fun fwidth(a: Operand): Operand = Func("fwidth", a, type = a.type)
fun dFdx(a: Operand): Operand = Func("dFdx", a, type = a.type)
fun dFdy(a: Operand): Operand = Func("dFdy", a, type = a.type)

//lessThan


//@JvmName("modInfix") infix fun Operand.mod(that: Operand): Operand = mod(this, that)

fun mix(a: Operand, b: Operand, step: Operand): Operand =
Func("mix", a, b, step)
fun step(a: Operand, b: Operand): Operand = Func("step", a, b)
Func("mix", a, b, step, type = a.type)
fun step(a: Operand, b: Operand): Operand = Func("step", a, b, type = a.type)
fun smoothstep(a: Operand, b: Operand, c: Operand): Operand =
Func("smoothstep", a, b, c)
Func("smoothstep", a, b, c, type = a.type)

fun length(a: Operand): Operand = Func("length", a)
fun distance(a: Operand, b: Operand): Operand = Func("distance", a, b)
fun dot(a: Operand, b: Operand): Operand = Func("dot", a, b)
fun cross(a: Operand, b: Operand): Operand = Func("cross", a, b)
fun normalize(a: Operand): Operand = Func("normalize", a)
fun length(a: Operand): Operand = Func("length", a, type = VarType.Float1)
fun distance(a: Operand, b: Operand): Operand = Func("distance", a, b, type = VarType.Float1)
fun dot(a: Operand, b: Operand): Operand = Func("dot", a, b, type = VarType.Float1)
fun cross(a: Operand, b: Operand): Operand = Func("cross", a, b, type = VarType.Float3)
fun normalize(a: Operand): Operand = Func("normalize", a, type = a.type)
fun faceforward(a: Operand, b: Operand, c: Operand): Operand =
Func("faceforward", a, b, c)
fun reflect(a: Operand, b: Operand): Operand = Func("reflect", a, b)
Func("faceforward", a, b, c, type = a.type)
fun reflect(a: Operand, b: Operand): Operand =
Func("reflect", a, b, type = a.type)
fun refract(a: Operand, b: Operand, c: Operand): Operand =
Func("refract", a, b, c)
Func("refract", a, b, c, type = a.type)

val Int.lit: IntLiteral get() = IntLiteral(this)
@Deprecated("", ReplaceWith("this.toFloat().lit"))
Expand Down Expand Up @@ -759,6 +767,12 @@ data class Program(val vertex: VertexShader, val fragment: FragmentShader, val n

fun TEMP(type: VarType): Temp = Temp(context.tempLastId++, type)

fun TEMP(initialValue: Operand): Temp {
val temp = TEMP(initialValue.type)
SET(temp, initialValue)
return temp
}

class FuncDeclGetter<T : FuncRef>(val decl: FuncDecl) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T = decl as T
}
Expand Down
15 changes: 5 additions & 10 deletions korge-core/src/korlibs/korge/render/SDFShaders.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,15 @@ object SDFShaders : Program.Builder() {
RETURN(clamp(d / fwidth(d) + 0.5f, 0f.lit, 1f.lit))
}
val opSmoothUnion by FUNC(Float1, Float1, Float1, returns = Float1) { d1, d2, k ->
val h = TEMP(Float1)
SET(h, clamp(.5f + .5f * (d2 - d1) / k, 0f.lit, 1f.lit))
val h = TEMP(clamp(.5f + .5f * (d2 - d1) / k, 0f.lit, 1f.lit))
RETURN(mix(d2, d1, h) - k * h * (1f - h))
}
val opSmoothSubtraction by FUNC(Float1, Float1, Float1, returns = Float1) { d1, d2, k ->
val h = TEMP(Float1)
SET(h, clamp(.5f - .5f * (d2 + d1) / k, 0f.lit, 1f.lit))
val h = TEMP(clamp(.5f - .5f * (d2 + d1) / k, 0f.lit, 1f.lit))
RETURN(mix(d2, -d1, h) + k * h * (1f - h))
}
val opSmoothIntersection by FUNC(Float1, Float1, Float1, returns = Float1) { d1, d2, k ->
val h = TEMP(Float1)
SET(h, clamp(.5f - .5f * (d2 - d1) / k, 0f.lit, 1f.lit))
val h = TEMP(clamp(.5f - .5f * (d2 - d1) / k, 0f.lit, 1f.lit))
RETURN(mix(d2, d1, h) + k * h * (1f - h))
}

Expand All @@ -65,15 +62,13 @@ object SDFShaders : Program.Builder() {
RETURN(length(p) - r)
}
val roundedBox by FUNC(Float2, Float2, Float4, returns = Float1) { p, b, r ->
val q = TEMP(Float2)
SET(r["xy"], TERNARY(p.x gt 0f, r["xy"], r["zw"]))
SET(r.x, TERNARY(p.y gt 0f, r.x, r.y))
SET(q, abs(p) - b + r.x)
val q = TEMP(abs(p) - b + r.x)
RETURN(min(max(q.x, q.y), 0f.lit) + length(max(q, 0f.lit)) - r.x)
}
val box by FUNC(Float2, Float2, returns = Float1) { p, b ->
val d = TEMP(Float2)
SET(d, abs(p) - b)
val d = TEMP(abs(p) - b)
RETURN(length(max(d, 0f.lit)) + min(max(d.x, d.y), 0f.lit))
}

Expand Down
18 changes: 7 additions & 11 deletions korge/src/korlibs/korge/render/RenderContext2DExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,32 +70,28 @@ object MaterialRender {
}

val PROGRAM = ShadedView.buildShader {
val roundedDist = TEMP(Float1)
val borderDist = TEMP(Float1)
val highlightDist = TEMP(Float1)
val borderAlpha = TEMP(Float1)
val highlightAlpha = TEMP(Float1)

// The pixel space scale of the rectangle.
val size = u_Size

SET(roundedDist, SDFShaders.roundedBox(v_Tex - (size / 2f), size / 2f, u_Radius))
val roundedDist = TEMP(SDFShaders.roundedBox(v_Tex - (size / 2f), size / 2f, u_Radius))

SET(out, u_BackgroundColor * SDFShaders.opAA(roundedDist))

// Render circle highlight
IF(u_HighlightRadius gt 0f) {
SET(highlightDist, SDFShaders.opIntersect(roundedDist, SDFShaders.circle(v_Tex - u_HighlightPos, u_HighlightRadius)))
SET(highlightAlpha, SDFShaders.opAA(highlightDist))
val highlightDist = SDFShaders.opIntersect(roundedDist, SDFShaders.circle(v_Tex - u_HighlightPos, u_HighlightRadius))
val highlightAlpha = TEMP(SDFShaders.opAA(highlightDist))

IF(highlightAlpha gt 0f) {
SET(out, SDFShaders.opCombinePremultipliedColors(out, u_HighlightColor * highlightAlpha))
}
}

// Render border
IF(u_BorderSizeHalf gt 0f) {
SET(borderDist, SDFShaders.opBorderInner(roundedDist, u_BorderSizeHalf * 2f))
val borderDist = SDFShaders.opBorderInner(roundedDist, u_BorderSizeHalf * 2f)
//SET(borderDist, SDFShaders.opBorder(roundedDist, u_BorderSizeHalf))
SET(borderAlpha, SDFShaders.opAA(borderDist))
val borderAlpha = TEMP(SDFShaders.opAA(borderDist))
IF(borderAlpha gt 0f) {
SET(out, SDFShaders.opCombinePremultipliedColors(out, u_BorderColor * borderAlpha))
}
Expand Down
9 changes: 3 additions & 6 deletions korge/src/korlibs/korge/view/fast/FSprites.kt
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,7 @@ open class FSprites(val maxSize: Int) {
return Program(VertexShaderDefault {
//SET(out, (u_ProjMat * u_ViewMat) * vec4(vec2(a_x, a_y), 0f.lit, 1f.lit))
//SET(v_color, texture2D(u_Tex, vec2(vec1(id) / 4f.lit, 0f.lit)))
val baseSize = TEMP(VarType.Float2)
val texSize = TEMP(VarType.Float2)
SET(baseSize, a_uv1 - a_uv0)
SET(v_Col, vec4(a_colMul["rgb"] * a_colMul["a"], a_colMul["a"])) // Pre-multiply color here
SET(v_TexId, a_texId)

Expand All @@ -241,17 +239,16 @@ open class FSprites(val maxSize: Int) {
mix(a_uv0.y, a_uv1.y, a_xy.y),
) * texSize)

val cos = TEMP(VarType.Float1)
val sin = TEMP(VarType.Float1)
SET(cos, cos(a_angle))
SET(sin, sin(a_angle))
val cos = TEMP(cos(a_angle))
val sin = TEMP(sin(a_angle))
SET(t_TempMat2, mat2(
cos, -sin,
sin, cos,
))
val size = t_Temp0["zw"]
val localPos = t_Temp0["xy"]

val baseSize = a_uv1 - a_uv0
SET(size, baseSize * a_scale)
SET(localPos, t_TempMat2 * ((a_xy - a_anchor) * size))
SET(out, (u_ProjMat * u_ViewMat) * vec4(localPos + vec2(a_pos.x, a_pos.y), 0f.lit, 1f.lit))
Expand Down
38 changes: 17 additions & 21 deletions korge/src/korlibs/korge/view/filter/DitheringFilter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,12 @@ class DitheringFilter(
63, 31, 55, 23, 61, 29, 53, 21
)
val indexValue by FUNC(Float2, returns = Float1) { coords ->
val index = TEMP(Float1)
val matrix = indexMatrix8x8
//val matrix = indexMatrix4x4
val width = kotlin.math.sqrt(matrix.size.toDouble()).toInt()
val x = int(mod(coords.x, width.toFloat().lit))
val y = int(mod(coords.y, width.toFloat().lit))
SET(index, float(x + y * width.lit))
val index = TEMP(float(x + y * width.lit))
IF_ELSE_BINARY_LOOKUP(index, 0, matrix.size - 1) {
RETURN((matrix[it].toFloat() / matrix.size.toFloat()).lit)
}
Expand All @@ -48,26 +47,23 @@ class DitheringFilter(
}

override val fragment: FragmentShader = FragmentShaderDefault {
val COL = TEMP(Float4)
val COL1 = TEMP(Float4)
val COL2 = TEMP(Float4)
val DIST1 = TEMP(Float4)
val DIST3 = TEMP(Float4)
val INDEX1 = TEMP(Float1)
val STEPS = DitherUB.u_Levels
val hueDiff = TEMP(Float4)
SET(COL, tex(fragmentCoords))
SET(COL1, vec4(floor(COL * STEPS)) / STEPS)
SET(COL2, vec4(ceil(COL * STEPS)) / STEPS)
SET(DIST1, abs(COL1 - COL))
SET(DIST3, abs(COL2 - COL1))
SET(INDEX1, DitheringTools.indexValue(fragmentCoords))
SET(hueDiff , DIST1 / DIST3)
val steps = DitherUB.u_Levels

val col = TEMP(tex(fragmentCoords))
val col1 = TEMP(vec4(floor(col * steps)) / steps)
val col2 = TEMP(vec4(ceil(col * steps)) / steps)

val dist1 = TEMP(abs(col1 - col))
val dist3 = TEMP(abs(col2 - col1))

val index1 = TEMP(DitheringTools.indexValue(fragmentCoords))
val hueDiff = TEMP(dist1 / dist3)

SET(out, vec4(
TERNARY(hueDiff.x lt INDEX1, COL1.x, COL2.x),
TERNARY(hueDiff.y lt INDEX1, COL1.y, COL2.y),
TERNARY(hueDiff.z lt INDEX1, COL1.z, COL2.z),
TERNARY(hueDiff.w lt INDEX1, COL1.w, COL2.w),
TERNARY(hueDiff.x lt index1, col1.x, col2.x),
TERNARY(hueDiff.y lt index1, col1.y, col2.y),
TERNARY(hueDiff.z lt index1, col1.z, col2.z),
TERNARY(hueDiff.w lt index1, col1.w, col2.w),
))
}
}
Expand Down
Loading