diff --git a/korge-core/src/korlibs/graphics/shader/shaders.kt b/korge-core/src/korlibs/graphics/shader/shaders.kt index 31d1a42770..0ab82f4d77 100644 --- a/korge-core/src/korlibs/graphics/shader/shaders.kt +++ b/korge-core/src/korlibs/graphics/shader/shaders.kt @@ -490,63 +490,70 @@ 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 @@ -554,21 +561,22 @@ data class Program(val vertex: VertexShader, val fragment: FragmentShader, val n //@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")) @@ -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(val decl: FuncDecl) { operator fun getValue(thisRef: Any?, property: KProperty<*>): T = decl as T } diff --git a/korge-core/src/korlibs/korge/render/SDFShaders.kt b/korge-core/src/korlibs/korge/render/SDFShaders.kt index 12cd9e5f54..7dc65e6632 100644 --- a/korge-core/src/korlibs/korge/render/SDFShaders.kt +++ b/korge-core/src/korlibs/korge/render/SDFShaders.kt @@ -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)) } @@ -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)) } diff --git a/korge/src/korlibs/korge/render/RenderContext2DExt.kt b/korge/src/korlibs/korge/render/RenderContext2DExt.kt index aa87258075..ee7bca3cda 100644 --- a/korge/src/korlibs/korge/render/RenderContext2DExt.kt +++ b/korge/src/korlibs/korge/render/RenderContext2DExt.kt @@ -70,22 +70,18 @@ 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)) } @@ -93,9 +89,9 @@ object MaterialRender { // 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)) } diff --git a/korge/src/korlibs/korge/view/fast/FSprites.kt b/korge/src/korlibs/korge/view/fast/FSprites.kt index ea2d2bc481..1334538c9c 100644 --- a/korge/src/korlibs/korge/view/fast/FSprites.kt +++ b/korge/src/korlibs/korge/view/fast/FSprites.kt @@ -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) @@ -241,10 +239,8 @@ 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, @@ -252,6 +248,7 @@ open class FSprites(val maxSize: Int) { 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)) diff --git a/korge/src/korlibs/korge/view/filter/DitheringFilter.kt b/korge/src/korlibs/korge/view/filter/DitheringFilter.kt index 6470230afb..5777625b60 100644 --- a/korge/src/korlibs/korge/view/filter/DitheringFilter.kt +++ b/korge/src/korlibs/korge/view/filter/DitheringFilter.kt @@ -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) } @@ -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), )) } }