From 29838ba5efe87fe116d182bcf3a9f17d30eda04f Mon Sep 17 00:00:00 2001 From: Carlos Ballesteros Velasco Date: Wed, 4 Oct 2023 22:57:17 +0200 Subject: [PATCH] Missing View-related ratio updates (#1913) --- e2e/e2e-test/src/commonMain/kotlin/RefMain.kt | 5 ++-- .../korlibs/math/_Math_interpolation.kt | 4 +++ .../src/commonMain/kotlin/samples/MainBlur.kt | 9 ++++--- .../commonMain/kotlin/samples/MainClipping.kt | 3 ++- .../commonMain/kotlin/samples/MainFilters.kt | 8 +++--- .../samples/MainFiltersRenderToBitmap.kt | 3 ++- .../kotlin/samples/MainFiltersSample.kt | 8 +++--- .../kotlin/samples/MainTransition.kt | 3 ++- .../kotlin/samples/MainTransitionFilter.kt | 7 +++--- .../src/commonMain/kotlin/samples/MainUI.kt | 4 +-- .../korlibs/graphics/shader/UniformBlock.kt | 2 ++ .../korlibs/korge/scene/SceneContainer.kt | 4 +-- .../common/korlibs/korge/scene/Transition.kt | 25 +++++++++++-------- .../common/korlibs/korge/tween/tweenbase.kt | 3 +++ .../common/korlibs/korge/ui/UIOldScrollBar.kt | 21 +++++++++++----- .../common/korlibs/korge/ui/UIProgressBar.kt | 14 ++++++++--- korge/src/common/korlibs/korge/view/View.kt | 8 +----- .../korlibs/korge/view/filter/PageFilter.kt | 15 +++++------ .../korge/view/filter/TransitionFilter.kt | 9 ++++--- .../korlibs/korge/awt/ObservableProperty.kt | 4 +++ .../jvm/korlibs/korge/awt/UiEditProperties.kt | 2 ++ .../korlibs/korge/scene/SceneContainerTest.kt | 5 ++-- .../korlibs/korge/view/TransitionViewTest.kt | 7 +++--- 23 files changed, 107 insertions(+), 66 deletions(-) diff --git a/e2e/e2e-test/src/commonMain/kotlin/RefMain.kt b/e2e/e2e-test/src/commonMain/kotlin/RefMain.kt index 69fa595ae4..b2dacee0db 100644 --- a/e2e/e2e-test/src/commonMain/kotlin/RefMain.kt +++ b/e2e/e2e-test/src/commonMain/kotlin/RefMain.kt @@ -11,6 +11,7 @@ import korlibs.io.file.std.* import korlibs.io.lang.* import korlibs.io.serialization.json.Json import korlibs.math.geom.* +import korlibs.math.interpolation.* suspend fun main() = Korge(windowSize = Size(768, 512), backgroundColor = Colors["#2b2b2b"]) { //println("StandardPaths.cwd=${korlibs.io.file.std.StandardPaths.cwd}") @@ -101,8 +102,8 @@ object FiltersE2ETestCase : E2ETestCase() { println("PREPARING VIEWS...") image(bitmap).scale(.5).position(0, 0).addFilter(WaveFilter(time = 0.5.seconds, crestDistance = Vector2D(256, 128))) image(bitmap).scale(.5).position(256, 0).addFilter(BlurFilter(radius = 6.0)) - image(bitmap).scale(.5).position(512, 0).addFilter(TransitionFilter(TransitionFilter.Transition.SWEEP, reversed = false, spread = 1.0, ratio = 0.5)) - image(bitmap2).scale(.5).position(0, 256).addFilter(PageFilter(hratio = 0.5, hamplitude1 = 20.0)) + image(bitmap).scale(.5).position(512, 0).addFilter(TransitionFilter(TransitionFilter.Transition.SWEEP, reversed = false, spread = 1.0, ratio = Ratio.HALF)) + image(bitmap2).scale(.5).position(0, 256).addFilter(PageFilter(hratio = Ratio.HALF, hamplitude1 = 20.0)) image(bitmap2).scale(.5).position(256, 256).addFilter(Convolute3Filter(Convolute3Filter.KERNEL_SHARPEN)) image(bitmap2).scale(.5).position(512, 256).addFilter(SwizzleColorsFilter("bgga")) println("VIEWS PREPARED") diff --git a/korge-foundation/src/common/korlibs/math/_Math_interpolation.kt b/korge-foundation/src/common/korlibs/math/_Math_interpolation.kt index 71ca8020b3..881b2abe6a 100644 --- a/korge-foundation/src/common/korlibs/math/_Math_interpolation.kt +++ b/korge-foundation/src/common/korlibs/math/_Math_interpolation.kt @@ -19,6 +19,7 @@ private const val HALF_PI = PI.toFloat() / 2f fun interface Easing { operator fun invoke(it: Float): Float operator fun invoke(it: Double): Double = invoke(it.toFloat()).toDouble() + operator fun invoke(it: Ratio): Ratio = Ratio(invoke(it.toFloat()).toDouble()) companion object { operator fun invoke(name: () -> String, block: (Float) -> Float): Easing { @@ -418,12 +419,15 @@ inline operator fun Ratio.div(value: Double): Double = this.value / value @Deprecated("", ReplaceWith("this")) fun Ratio.toRatio(): Ratio = this +inline fun Number.toRatio(): Ratio = Ratio(this.toDouble()) fun Float.toRatio(): Ratio = Ratio(this) fun Double.toRatio(): Ratio = Ratio(this) +inline fun Number.toRatio(max: Number): Ratio = Ratio(this.toDouble(), max.toDouble()) fun Float.toRatio(max: Float): Ratio = Ratio(this, max) fun Double.toRatio(max: Double): Ratio = Ratio(this, max) +inline fun Number.toRatioClamped(): Ratio = Ratio(this.toDouble().clamp01()) fun Float.toRatioClamped(): Ratio = Ratio(this.clamp01()) fun Double.toRatioClamped(): Ratio = Ratio(this.clamp01()) diff --git a/korge-sandbox/src/commonMain/kotlin/samples/MainBlur.kt b/korge-sandbox/src/commonMain/kotlin/samples/MainBlur.kt index ee0518d22b..8fbd6c0bd8 100644 --- a/korge-sandbox/src/commonMain/kotlin/samples/MainBlur.kt +++ b/korge-sandbox/src/commonMain/kotlin/samples/MainBlur.kt @@ -11,6 +11,7 @@ import korlibs.korge.view.* import korlibs.korge.view.filter.* import korlibs.math.geom.Anchor import korlibs.math.geom.degrees +import korlibs.math.interpolation.* import korlibs.time.* import kotlin.reflect.* @@ -73,7 +74,7 @@ class MainBlur : Scene() { val colorMatrixFilter = ColorMatrixFilter(ColorMatrixFilter.SEPIA_MATRIX, blendRatio = 0.5) image(bitmap).xy(500, 250).filters(colorMatrixFilter).bindScale() - val transitionFilter = TransitionFilter(TransitionFilter.Transition.CIRCULAR, reversed = false, ratio = 0.5, spread = 0.2) + val transitionFilter = TransitionFilter(TransitionFilter.Transition.CIRCULAR, reversed = false, ratio = Ratio.HALF, spread = 0.2) image(bitmap).xy(370, 250).filters(transitionFilter).bindScale() val pageFilter = PageFilter() @@ -129,11 +130,11 @@ class MainBlur : Scene() { } uiHorizontalFill { uiText("Blend").styles { textColor = Colors.BLACK } - uiSlider(value = transitionFilter.ratio, min = 0.0, max = 1.0, step = 0.0, decimalPlaces = 2).changed { + uiSlider(value = transitionFilter.ratio.toDouble(), min = 0.0, max = 1.0, step = 0.0, decimalPlaces = 2).changed { colorMatrixFilter.blendRatio = it pageFilter.hamplitude0 = it - transitionFilter.ratio = it - pageFilter.hratio = it + transitionFilter.ratio = it.toRatio() + pageFilter.hratio = it.toRatio() waveFilter.time = it.seconds flagFilter.time = it.seconds } diff --git a/korge-sandbox/src/commonMain/kotlin/samples/MainClipping.kt b/korge-sandbox/src/commonMain/kotlin/samples/MainClipping.kt index 558b597772..850cbc2229 100644 --- a/korge-sandbox/src/commonMain/kotlin/samples/MainClipping.kt +++ b/korge-sandbox/src/commonMain/kotlin/samples/MainClipping.kt @@ -8,6 +8,7 @@ import korlibs.korge.view.* import korlibs.korge.view.filter.* import korlibs.korge.view.vector.* import korlibs.math.geom.* +import korlibs.math.interpolation.* class MainClipping : Scene() { override suspend fun SContainer.sceneMain() { @@ -38,7 +39,7 @@ class MainClipping : Scene() { solidRect(512, 512, Colors.BLUE) } }, MaskTransition(TransitionFilter.Transition.CIRCULAR)) - tv.ratio = 0.5 + tv.ratio = Ratio.HALF addChild(tv) gpuShapeView({ diff --git a/korge-sandbox/src/commonMain/kotlin/samples/MainFilters.kt b/korge-sandbox/src/commonMain/kotlin/samples/MainFilters.kt index c08ac6710c..e17052347f 100644 --- a/korge-sandbox/src/commonMain/kotlin/samples/MainFilters.kt +++ b/korge-sandbox/src/commonMain/kotlin/samples/MainFilters.kt @@ -73,12 +73,12 @@ class MainFilters : ScaledScene(768, 512) { sequence(looped = true) { //tween(color::blendRatio[0], time = 1.seconds, easing = Easing.EASE_IN_OUT) //tween(color::blendRatio[1], time = 1.seconds, easing = Easing.EASE_IN_OUT) - tween(color::ratio[0], time = 1.seconds, easing = Easing.EASE_IN_OUT) - tween(color::ratio[1], time = 1.seconds, easing = Easing.EASE_IN_OUT) + tween(color::ratio[Ratio.ZERO], time = 1.seconds, easing = Easing.EASE_IN_OUT) + tween(color::ratio[Ratio.ONE], time = 1.seconds, easing = Easing.EASE_IN_OUT) } sequence(looped = true) { - tween(page::hratio[0], time = 1.seconds, easing = Easing.EASE_IN_OUT) - tween(page::hratio[1], time = 1.seconds, easing = Easing.EASE_IN_OUT) + tween(page::hratio[Ratio.ZERO], time = 1.seconds, easing = Easing.EASE_IN_OUT) + tween(page::hratio[Ratio.ONE], time = 1.seconds, easing = Easing.EASE_IN_OUT) } sequence(looped = true) { block { conImg.filter = Convolute3Filter(Convolute3Filter.KERNEL_SHARPEN) } diff --git a/korge-sandbox/src/commonMain/kotlin/samples/MainFiltersRenderToBitmap.kt b/korge-sandbox/src/commonMain/kotlin/samples/MainFiltersRenderToBitmap.kt index bbfc35e8bd..5fb4bab948 100644 --- a/korge-sandbox/src/commonMain/kotlin/samples/MainFiltersRenderToBitmap.kt +++ b/korge-sandbox/src/commonMain/kotlin/samples/MainFiltersRenderToBitmap.kt @@ -6,6 +6,7 @@ import korlibs.korge.scene.* import korlibs.korge.view.* import korlibs.korge.view.filter.* import korlibs.math.geom.* +import korlibs.math.interpolation.* import korlibs.time.* class MainFiltersRenderToBitmap : Scene() { @@ -18,7 +19,7 @@ class MainFiltersRenderToBitmap : Scene() { image(bitmap).scale(.5).position(0, 0).addFilter(WaveFilter(time = 0.5.seconds)) //image(bitmap).scale(.5).position(256, 0).addFilter(DirectionalBlurFilter(radius = 32.0)) image(bitmap).scale(.5).position(256, 0).addFilter(BlurFilter(radius = 32.0)) - image(bitmap).scale(.5).position(512, 0).addFilter(TransitionFilter(TransitionFilter.Transition.SWEEP, reversed = false, spread = 1.0, ratio = 0.5)) + image(bitmap).scale(.5).position(512, 0).addFilter(TransitionFilter(TransitionFilter.Transition.SWEEP, reversed = false, spread = 1.0, ratio = Ratio.HALF)) image(bitmap).scale(.5).position(0, 256).addFilter(PageFilter(hratio = 0.5, hamplitude1 = 20.0)) image(bitmap).scale(.5).position(256, 256).addFilter(Convolute3Filter(Convolute3Filter.KERNEL_SHARPEN)) image(bitmap).scale(.5).position(512, 256).addFilter(SwizzleColorsFilter("bgga")) diff --git a/korge-sandbox/src/commonMain/kotlin/samples/MainFiltersSample.kt b/korge-sandbox/src/commonMain/kotlin/samples/MainFiltersSample.kt index 3b99b346fa..5e738d2668 100644 --- a/korge-sandbox/src/commonMain/kotlin/samples/MainFiltersSample.kt +++ b/korge-sandbox/src/commonMain/kotlin/samples/MainFiltersSample.kt @@ -73,12 +73,12 @@ class MainFiltersSample : Scene() { sequence(looped = true) { //tween(color::blendRatio[0], time = 1.seconds, easing = Easing.EASE_IN_OUT) //tween(color::blendRatio[1], time = 1.seconds, easing = Easing.EASE_IN_OUT) - tween(color::ratio[0], time = 1.seconds, easing = Easing.EASE_IN_OUT) - tween(color::ratio[1], time = 1.seconds, easing = Easing.EASE_IN_OUT) + tween(color::ratio[Ratio.ZERO], time = 1.seconds, easing = Easing.EASE_IN_OUT) + tween(color::ratio[Ratio.ONE], time = 1.seconds, easing = Easing.EASE_IN_OUT) } sequence(looped = true) { - tween(page::hratio[0], time = 1.seconds, easing = Easing.EASE_IN_OUT) - tween(page::hratio[1], time = 1.seconds, easing = Easing.EASE_IN_OUT) + tween(page::hratio[Ratio.ZERO], time = 1.seconds, easing = Easing.EASE_IN_OUT) + tween(page::hratio[Ratio.ONE], time = 1.seconds, easing = Easing.EASE_IN_OUT) } sequence(looped = true) { block { conImg.filter = Convolute3Filter(Convolute3Filter.KERNEL_SHARPEN) } diff --git a/korge-sandbox/src/commonMain/kotlin/samples/MainTransition.kt b/korge-sandbox/src/commonMain/kotlin/samples/MainTransition.kt index 9d2b4cf388..555abe5c0b 100644 --- a/korge-sandbox/src/commonMain/kotlin/samples/MainTransition.kt +++ b/korge-sandbox/src/commonMain/kotlin/samples/MainTransition.kt @@ -5,6 +5,7 @@ import korlibs.korge.scene.* import korlibs.korge.ui.* import korlibs.korge.view.* import korlibs.korge.view.filter.* +import korlibs.math.interpolation.* class MainTransition : Scene() { override suspend fun SContainer.sceneMain() { @@ -13,7 +14,7 @@ class MainTransition : Scene() { transition.startNewTransition(SolidRect(100, 100, Colors.BLUE), MaskTransition( TransitionFilter.Transition.CIRCULAR )) - transition.ratio = 0.5 + transition.ratio = Ratio.HALF transition.filters(DropshadowFilter(shadowColor = Colors.PURPLE)) solidRect(100, 100, Colors.GREEN).filters(DropshadowFilter(shadowColor = Colors.PURPLE)) diff --git a/korge-sandbox/src/commonMain/kotlin/samples/MainTransitionFilter.kt b/korge-sandbox/src/commonMain/kotlin/samples/MainTransitionFilter.kt index 6d55d5eb25..a858c92681 100644 --- a/korge-sandbox/src/commonMain/kotlin/samples/MainTransitionFilter.kt +++ b/korge-sandbox/src/commonMain/kotlin/samples/MainTransitionFilter.kt @@ -7,12 +7,13 @@ import korlibs.korge.scene.* import korlibs.korge.tween.* import korlibs.korge.view.* import korlibs.korge.view.filter.* +import korlibs.math.interpolation.* import korlibs.time.* class MainTransitionFilter : ScaledScene(768, 512) { override suspend fun SContainer.sceneMain() { val bitmap = resourcesVfs["korge.png"].readBitmap() - val transition = TransitionFilter(TransitionFilter.Transition.SWEEP, reversed = false, spread = 1.0, ratio = 0.5) + val transition = TransitionFilter(TransitionFilter.Transition.SWEEP, reversed = false, spread = 1.0, ratio = Ratio.HALF) image(transition.transition.bmp) @@ -24,8 +25,8 @@ class MainTransitionFilter : ScaledScene(768, 512) { launchImmediately { while (true) { - tween(transition::ratio[1.0], time = 0.5.seconds) - tween(transition::ratio[0.0], time = 0.5.seconds) + tween(transition::ratio[Ratio.ONE], time = 0.5.seconds) + tween(transition::ratio[Ratio.ZERO], time = 0.5.seconds) } } } diff --git a/korge-sandbox/src/commonMain/kotlin/samples/MainUI.kt b/korge-sandbox/src/commonMain/kotlin/samples/MainUI.kt index 5578e2f0cd..e2145875c7 100644 --- a/korge-sandbox/src/commonMain/kotlin/samples/MainUI.kt +++ b/korge-sandbox/src/commonMain/kotlin/samples/MainUI.kt @@ -105,8 +105,8 @@ class MainUI : Scene() { } val job = launchImmediately { while (true) { - tween(progress::ratio[1.0], time = 1.seconds, easing = Easing.EASE_IN_OUT) - tween(progress::ratio[1.0, 0.0], time = 1.seconds, easing = Easing.EASE_IN_OUT) + tween(progress::ratio[Ratio.ONE], time = 1.seconds, easing = Easing.EASE_IN_OUT) + tween(progress::ratio[Ratio.ONE, Ratio.ZERO], time = 1.seconds, easing = Easing.EASE_IN_OUT) } } uiButton("Stop Progress").position(Point(64 + progress.width, 32.0)).mouse { onClick { job.cancel() } } diff --git a/korge/src/common/korlibs/graphics/shader/UniformBlock.kt b/korge/src/common/korlibs/graphics/shader/UniformBlock.kt index cc0cc03c46..79651becd6 100644 --- a/korge/src/common/korlibs/graphics/shader/UniformBlock.kt +++ b/korge/src/common/korlibs/graphics/shader/UniformBlock.kt @@ -4,6 +4,7 @@ import korlibs.graphics.* import korlibs.image.color.* import korlibs.io.lang.* import korlibs.math.geom.* +import korlibs.math.interpolation.* import korlibs.math.nextMultipleOf import korlibs.memory.* import kotlin.reflect.* @@ -167,6 +168,7 @@ class UniformsRef( } operator fun set(uniform: TypedUniform, value: Boolean) = set(uniform, if (value) 1f else 0f) operator fun set(uniform: TypedUniform, value: Double) = set(uniform, value.toFloat()) + operator fun set(uniform: TypedUniform, value: Ratio) = set(uniform, value.toFloat()) operator fun set(uniform: TypedUniform, value: Vector2F) = set(uniform, value.x, value.y) operator fun set(uniform: TypedUniform, value: Point) = set(uniform, value.x.toFloat(), value.y.toFloat()) operator fun set(uniform: TypedUniform, value: Size) = set(uniform, value.width.toFloat(), value.height.toFloat()) diff --git a/korge/src/common/korlibs/korge/scene/SceneContainer.kt b/korge/src/common/korlibs/korge/scene/SceneContainer.kt index a62b14850e..46de6da265 100644 --- a/korge/src/common/korlibs/korge/scene/SceneContainer.kt +++ b/korge/src/common/korlibs/korge/scene/SceneContainer.kt @@ -305,9 +305,9 @@ class SceneContainer( } if (time > 0.seconds) { - transitionView.tween(transitionView::ratio[0.0, 1.0], time = time) + transitionView.tween(transitionView::ratio[Ratio.ZERO, Ratio.ONE], time = time) } else { - transitionView.ratio = 1.0 + transitionView.ratio = Ratio.ONE } transitionView.endTransition() diff --git a/korge/src/common/korlibs/korge/scene/Transition.kt b/korge/src/common/korlibs/korge/scene/Transition.kt index 25d2d3daf2..3baea8cc2f 100644 --- a/korge/src/common/korlibs/korge/scene/Transition.kt +++ b/korge/src/common/korlibs/korge/scene/Transition.kt @@ -5,6 +5,7 @@ import korlibs.korge.render.* import korlibs.korge.tween.* import korlibs.korge.view.* import korlibs.korge.view.filter.* +import korlibs.korge.view.property.* import korlibs.math.interpolation.* import kotlin.native.concurrent.* @@ -19,6 +20,9 @@ class TransitionView() : Container() { dummyView() } + @ViewProperty(min = 0.0, max = 1.0, clampMin = false, clampMax = false) + var ratio: Ratio = Ratio.ZERO + /** [Transition] that will be used to render [prev] and [next] */ internal var transition: Transition = AlphaTransition private set @@ -29,7 +33,7 @@ class TransitionView() : Container() { /** Moves [next] to [prev], sets [next] and starts the [ratio] to 0.0 to start the transition. */ fun startNewTransition(next: View, transition: Transition = this.transition) { this.transition = transition - this.ratio = 0.0 + this.ratio = Ratio.ZERO this.transitionProcess = transition.create() setViews(this.next, next) this.transitionProcess.start(this.prev, this.next) @@ -38,7 +42,8 @@ class TransitionView() : Container() { override fun toString(): String = super.toString() + ":ratio=$ratio:transition=$transition" fun endTransition() { - this.ratio = 1.0 + this.ratio = Ratio.ONE + this.transitionProcess.end(this.prev, this.next) setViews(dummyView(), next) } @@ -52,8 +57,8 @@ class TransitionView() : Container() { override fun renderInternal(ctx: RenderContext) { when { - ratio <= 0.0 -> prev.render(ctx) - ratio >= 1.0 -> next.render(ctx) + ratio <= Ratio.ZERO -> prev.render(ctx) + ratio >= Ratio.ONE -> next.render(ctx) else -> this.transitionProcess.render(ctx, prev, next, ratio) } } @@ -62,23 +67,23 @@ class TransitionView() : Container() { interface TransitionProcess { fun start(prev: View, next: View) = Unit fun end(prev: View, next: View) = Unit - fun render(ctx: RenderContext, prev: View, next: View, ratio: Double) = Unit + fun render(ctx: RenderContext, prev: View, next: View, ratio: Ratio) = Unit } interface Transition { fun create(): TransitionProcess } -fun TransitionProcess(name: String = "Transition", render: (ctx: RenderContext, prev: View, next: View, ratio: Double) -> Unit): TransitionProcess = +fun TransitionProcess(name: String = "Transition", render: (ctx: RenderContext, prev: View, next: View, ratio: Ratio) -> Unit): TransitionProcess = object : TransitionProcess { - override fun render(ctx: RenderContext, prev: View, next: View, ratio: Double) = render(ctx, prev, next, ratio) + override fun render(ctx: RenderContext, prev: View, next: View, ratio: Ratio) = render(ctx, prev, next, ratio) override fun toString(): String = name } -fun Transition(name: String = "Transition", render: (ctx: RenderContext, prev: View, next: View, ratio: Double) -> Unit): Transition { +fun Transition(name: String = "Transition", render: (ctx: RenderContext, prev: View, next: View, ratio: Ratio) -> Unit): Transition { return object : Transition, TransitionProcess { override fun create(): TransitionProcess = this - override fun render(ctx: RenderContext, prev: View, next: View, ratio: Double) = render(ctx, prev, next, ratio) + override fun render(ctx: RenderContext, prev: View, next: View, ratio: Ratio) = render(ctx, prev, next, ratio) override fun toString(): String = name } } @@ -106,7 +111,7 @@ fun Transition.withEasing(easing: Easing) = object : Transition { return object : TransitionProcess { override fun start(prev: View, next: View) = process.start(prev, next) override fun end(prev: View, next: View) = process.end(prev, next) - override fun render(ctx: RenderContext, prev: View, next: View, ratio: Double) = + override fun render(ctx: RenderContext, prev: View, next: View, ratio: Ratio) = process.render(ctx, prev, next, easing(ratio)) } } diff --git a/korge/src/common/korlibs/korge/tween/tweenbase.kt b/korge/src/common/korlibs/korge/tween/tweenbase.kt index cd6941fb8a..617847172b 100644 --- a/korge/src/common/korlibs/korge/tween/tweenbase.kt +++ b/korge/src/common/korlibs/korge/tween/tweenbase.kt @@ -130,6 +130,7 @@ operator fun > KMutableProperty0.get(initial: V, end: V) @PublishedApi internal fun _interpolate(ratio: Ratio, l: Double, r: Double): Double = ratio.interpolate(l, r) @PublishedApi internal fun _interpolateInt(ratio: Ratio, l: Int, r: Int): Int = ratio.interpolate(l, r) @PublishedApi internal fun > _interpolateInterpolable(ratio: Ratio, l: V, r: V): V = ratio.interpolate(l, r) +@PublishedApi internal fun _interpolateRatio(ratio: Ratio, l: Ratio, r: Ratio): Ratio = ratio.interpolate(l, r) @PublishedApi internal fun _interpolateMatrix(ratio: Ratio, l: Matrix, r: Matrix): Matrix = ratio.interpolate(l, r) @PublishedApi internal fun _interpolatePoint(ratio: Ratio, l: Point, r: Point): Point = ratio.interpolate(l, r) @PublishedApi internal fun _interpolateSize(ratio: Ratio, l: Size, r: Size): Size = ratio.interpolate(l, r) @@ -217,6 +218,8 @@ inline operator fun KMutableProperty0.get(range: PointList): V2 { @JvmName("getFloat") inline operator fun KMutableProperty0.get(initial: Long, end: Long) = get(initial.toFloat(), end.toFloat()) @JvmName("getFloat") inline operator fun KMutableProperty0.get(initial: Number, end: Number) = get(initial.toFloat(), end.toFloat()) +inline operator fun KMutableProperty0.get(end: Ratio) = V2(this, this.get(), end, ::_interpolateRatio, includeStart = false) +inline operator fun KMutableProperty0.get(initial: Ratio, end: Ratio) = V2(this, initial, end, ::_interpolateRatio, true) inline operator fun KMutableProperty0.get(end: Double) = V2(this, this.get(), end, ::_interpolate, includeStart = false) inline operator fun KMutableProperty0.get(end: Int) = get(end.toDouble()) diff --git a/korge/src/common/korlibs/korge/ui/UIOldScrollBar.kt b/korge/src/common/korlibs/korge/ui/UIOldScrollBar.kt index 8186b7f1c3..54828ece4f 100644 --- a/korge/src/common/korlibs/korge/ui/UIOldScrollBar.kt +++ b/korge/src/common/korlibs/korge/ui/UIOldScrollBar.kt @@ -8,9 +8,11 @@ import korlibs.korge.render.* import korlibs.korge.style.* import korlibs.korge.ui.UIOldScrollBar.* import korlibs.korge.view.* +import korlibs.korge.view.property.* import korlibs.math.* import korlibs.math.geom.* import korlibs.math.geom.slice.* +import korlibs.math.interpolation.* import kotlin.math.* @Deprecated("Use UINewScrollable") @@ -71,10 +73,12 @@ open class UIOldScrollBar( val onChange = Signal() - override var ratio: Double - get() = (current / (totalSize - pageSize)).clamp01() + /** Property used for interpolable views like morph shapes, progress bars etc. */ + @ViewProperty(min = 0.0, max = 1.0, clampMin = false, clampMax = false) + var ratio: Ratio + get() = Ratio(current, (totalSize - pageSize)).clamped set(value) { - current = value.clamp01() * (totalSize - pageSize) + current = value.clamped * (totalSize - pageSize) } protected val background = solidRect(100, 100, styles.buttonBackColor) @@ -108,13 +112,13 @@ open class UIOldScrollBar( changeCurrent(pos.sign * 0.8f * this.pageSize) } - var initRatio = 0.0 - var startRatio = 0.0 + var initRatio = Ratio.ZERO + var startRatio = Ratio.ZERO thumb.onMouseDrag { val lmouse = background.localMousePos(views) val curPosition = if (isHorizontal) lmouse.x else lmouse.y val size = if (isHorizontal) background.width - thumb.width else background.height - thumb.height - val curRatio = curPosition / size + val curRatio = Ratio(curPosition, size) if (it.start) { initRatio = ratio startRatio = curRatio @@ -151,6 +155,11 @@ open class UIOldScrollBar( } onChange(this) } + + override fun copyPropsFrom(source: View) { + super.copyPropsFrom(source) + this.ratio = (source as? UIOldScrollBar?)?.ratio ?: Ratio.ZERO + } } var ViewStyles.iconLeft: RectSlice by ViewStyle(Bitmap32(16, 16, Colors.WHITE.premultipliedFast).slice()) diff --git a/korge/src/common/korlibs/korge/ui/UIProgressBar.kt b/korge/src/common/korlibs/korge/ui/UIProgressBar.kt index 48058d36d8..2c8695d78c 100644 --- a/korge/src/common/korlibs/korge/ui/UIProgressBar.kt +++ b/korge/src/common/korlibs/korge/ui/UIProgressBar.kt @@ -4,8 +4,8 @@ import korlibs.korge.render.* import korlibs.korge.style.* import korlibs.korge.view.* import korlibs.korge.view.property.* -import korlibs.math.* import korlibs.math.geom.* +import korlibs.math.interpolation.* inline fun Container.uiProgressBar( size: Size = Size(256, 24), @@ -24,12 +24,20 @@ open class UIProgressBar( @ViewProperty(min = 0.0, max = 100.0) var maximum: Double by uiObservable(maximum) { updateState() } - override var ratio: Double + /** Property used for interpolable views like morph shapes, progress bars etc. */ + @ViewProperty(min = 0.0, max = 1.0, clampMin = false, clampMax = false) + var ratio: Ratio set(value) { current = value * maximum } - get() = (current / maximum).clamp01() + get() = Ratio(current, maximum).clamped override fun renderInternal(ctx: RenderContext) { styles.uiProgressBarRenderer.render(ctx) super.renderInternal(ctx) } + + override fun copyPropsFrom(source: View) { + super.copyPropsFrom(source) + this.ratio = (source as? UIProgressBar?)?.ratio ?: Ratio.ZERO + } + } diff --git a/korge/src/common/korlibs/korge/view/View.kt b/korge/src/common/korlibs/korge/view/View.kt index d16cb4266c..1a3f6af001 100644 --- a/korge/src/common/korlibs/korge/view/View.kt +++ b/korge/src/common/korlibs/korge/view/View.kt @@ -187,11 +187,6 @@ abstract class View internal constructor( } } - /** Property used for interpolable views like morph shapes, progress bars etc. */ - @ViewProperty(min = 0.0, max = 1.0, clampMin = false, clampMax = false) - // @TODO: Convert Float -> Ratio - open var ratio: Double = 0.0 - @PublishedApi internal var _index: Int = 0 @PublishedApi internal var _parent: Container? = null @@ -1318,7 +1313,7 @@ abstract class View internal constructor( throw MustOverrideException("Must Override ${this::class}.createInstance()") /** - * Allows to copy the basic properties (transform [localMatrix], [visible], [colorTransform], [ratio], [speed], [name]...) + * Allows to copy the basic properties (transform [localMatrix], [visible], [colorMul], [speed], [name]...) * from [source] into [this] */ open fun copyPropsFrom(source: View) { @@ -1326,7 +1321,6 @@ abstract class View internal constructor( this.colorMul = source.colorMul this.setMatrix(source.localMatrix) this.visible = source.visible - this.ratio = source.ratio this.speed = source.speed this.blendMode = source.blendMode } diff --git a/korge/src/common/korlibs/korge/view/filter/PageFilter.kt b/korge/src/common/korlibs/korge/view/filter/PageFilter.kt index ee55f0ba14..7530113e7d 100644 --- a/korge/src/common/korlibs/korge/view/filter/PageFilter.kt +++ b/korge/src/common/korlibs/korge/view/filter/PageFilter.kt @@ -6,18 +6,19 @@ import korlibs.korge.render.* import korlibs.korge.view.property.* import korlibs.math.* import korlibs.math.geom.* +import korlibs.math.interpolation.* import kotlin.math.* /** * A filter that simulates a page of a book. */ class PageFilter( - hratio: Double = 0.0, + hratio: Ratio = Ratio.ZERO, hamplitude0: Double = 0.0, hamplitude1: Double = 10.0, hamplitude2: Double = 0.0, - vratio: Double = 0.5, + vratio: Ratio = Ratio.HALF, vamplitude0: Double = 0.0, vamplitude1: Double = 0.0, vamplitude2: Double = 0.0, @@ -39,8 +40,8 @@ class PageFilter( vamplitude1: Number = 0.0, vamplitude2: Number = 0.0, ): PageFilter = PageFilter( - hratio.toDouble(), hamplitude0.toDouble(), - hamplitude1.toDouble(), hamplitude2.toDouble(), vratio.toDouble(), + hratio.toRatio(), hamplitude0.toDouble(), + hamplitude1.toDouble(), hamplitude2.toDouble(), vratio.toRatio(), vamplitude0.toDouble(), vamplitude1.toDouble(), vamplitude2.toDouble() ) @@ -67,7 +68,7 @@ class PageFilter( } @ViewProperty - var hratio: Double = hratio.toDouble() + var hratio: Ratio = hratio @ViewProperty var hamplitude0: Double = hamplitude0.toDouble() @ViewProperty @@ -76,7 +77,7 @@ class PageFilter( var hamplitude2: Double = hamplitude2.toDouble() @ViewProperty - var vratio: Double = vratio.toDouble() + var vratio: Ratio = vratio @ViewProperty var vamplitude0: Double = vamplitude0.toDouble() @ViewProperty @@ -94,7 +95,7 @@ class PageFilter( super.updateUniforms(ctx, filterScale) ctx[PageUB].push { - it[u_Offset] = Point(hratio, vratio) + it.set(u_Offset, hratio.toFloat(), vratio.toFloat()) it.set(u_HAmplitude, hamplitude0.toFloat(), hamplitude1.toFloat(), hamplitude2.toFloat(), 0f) it.set(u_VAmplitude, vamplitude0.toFloat(), vamplitude1.toFloat(), vamplitude2.toFloat(), 0f) } diff --git a/korge/src/common/korlibs/korge/view/filter/TransitionFilter.kt b/korge/src/common/korlibs/korge/view/filter/TransitionFilter.kt index 26b3518c0c..1362d5a5b5 100644 --- a/korge/src/common/korlibs/korge/view/filter/TransitionFilter.kt +++ b/korge/src/common/korlibs/korge/view/filter/TransitionFilter.kt @@ -8,12 +8,13 @@ import korlibs.image.color.* import korlibs.image.paint.* import korlibs.korge.render.* import korlibs.korge.view.property.* +import korlibs.math.interpolation.* class TransitionFilter( var transition: Transition = Transition.CIRCULAR, reversed: Boolean = false, spread: Double = 1.0, - ratio: Double = 1.0, + ratio: Ratio = Ratio.ONE, filtering: Boolean = false, ) : ShaderFilter() { class Transition(val bmp: Bitmap) { @@ -52,9 +53,9 @@ class TransitionFilter( transition: Transition = Transition.CIRCULAR, reversed: Boolean = false, spread: Number = 1.0, - ratio: Number = 1.0, + ratio: Ratio = Ratio.ONE, filtering: Boolean = false, - ): TransitionFilter = TransitionFilter(transition, reversed, spread.toDouble(), ratio.toDouble(), filtering) + ): TransitionFilter = TransitionFilter(transition, reversed, spread.toDouble(), ratio, filtering) private val u_Mask = DefaultShaders.u_TexEx @@ -87,7 +88,7 @@ class TransitionFilter( @ViewProperty var spread: Double = spread.toDouble() @ViewProperty - var ratio: Double = ratio.toDouble() + var ratio: Ratio = ratio override fun updateUniforms(ctx: RenderContext, filterScale: Double) { ctx[TransitionUB].push { diff --git a/korge/src/jvm/korlibs/korge/awt/ObservableProperty.kt b/korge/src/jvm/korlibs/korge/awt/ObservableProperty.kt index 15b99fa620..b1208894c7 100644 --- a/korge/src/jvm/korlibs/korge/awt/ObservableProperty.kt +++ b/korge/src/jvm/korlibs/korge/awt/ObservableProperty.kt @@ -1,11 +1,15 @@ package korlibs.korge.view.property import korlibs.io.async.* +import korlibs.math.interpolation.* fun ObservableProperty.transform(convert: (T) -> R, rconvert: (R) -> T): ObservableProperty { return ObservableProperty(name, internalSet = { this.value = rconvert(it) }, internalGet = { convert(this.value) }) } +@JvmName("ObservablePropertyRatio_toDouble") +fun ObservableProperty.toDouble(): ObservableProperty = transform({ it.toDouble() }, { it.toRatio() }) +@JvmName("ObservablePropertyFloat_toDouble") fun ObservableProperty.toDouble(): ObservableProperty = transform({ it.toDouble() }, { it.toFloat() }) class ObservableProperty( diff --git a/korge/src/jvm/korlibs/korge/awt/UiEditProperties.kt b/korge/src/jvm/korlibs/korge/awt/UiEditProperties.kt index 99a7fd4a05..1fca17b1e1 100644 --- a/korge/src/jvm/korlibs/korge/awt/UiEditProperties.kt +++ b/korge/src/jvm/korlibs/korge/awt/UiEditProperties.kt @@ -15,6 +15,7 @@ import korlibs.korge.view.property.ObservableProperty import korlibs.math.* import korlibs.math.geom.* import korlibs.math.geom.Point +import korlibs.math.interpolation.* import korlibs.template.* import java.awt.* import javax.swing.* @@ -280,6 +281,7 @@ internal class UiEditProperties(app: UiApplication, view: View?, val views: View } type.isSubtypeOf(RectCorners::class.starProjectedType) -> createQuad({ RectCorners(it.x, it.y, it.z, it.w) }, { Four(it.topLeft.toDouble(), it.topRight.toDouble(), it.bottomRight.toDouble(), it.bottomLeft.toDouble()) }, instance, prop, viewProp) type.isSubtypeOf(Margin::class.starProjectedType) -> createQuad({ Margin(it.x.toFloat(), it.y.toFloat(), it.z.toFloat(), it.w.toFloat()) }, { Four(it.top.toDouble(), it.right.toDouble(), it.bottom.toDouble(), it.left.toDouble()) }, instance, prop, viewProp) + type.isSubtypeOf(Ratio::class.starProjectedType) -> UiNumberEditableValue(app, (obs as ObservableProperty).toDouble(), viewProp.min, viewProp.max, viewProp.clampMin, viewProp.clampMax, viewProp.decimalPlaces) type.isSubtypeOf(Double::class.starProjectedType) -> UiNumberEditableValue(app, obs as ObservableProperty, viewProp.min, viewProp.max, viewProp.clampMin, viewProp.clampMax, viewProp.decimalPlaces) type.isSubtypeOf(Float::class.starProjectedType) -> UiNumberEditableValue(app, (obs as ObservableProperty).toDouble(), viewProp.min, viewProp.max, viewProp.clampMin, viewProp.clampMax, viewProp.decimalPlaces) type.isSubtypeOf(Int::class.starProjectedType) -> { diff --git a/korge/test/common/korlibs/korge/scene/SceneContainerTest.kt b/korge/test/common/korlibs/korge/scene/SceneContainerTest.kt index 9583cb0a44..f693b07bef 100644 --- a/korge/test/common/korlibs/korge/scene/SceneContainerTest.kt +++ b/korge/test/common/korlibs/korge/scene/SceneContainerTest.kt @@ -4,6 +4,7 @@ import korlibs.image.color.* import korlibs.korge.tests.* import korlibs.korge.view.* import korlibs.korge.view.filter.* +import korlibs.math.interpolation.* import korlibs.time.* import kotlin.test.* @@ -74,7 +75,7 @@ class SceneContainerTest : ViewsForTesting() { sceneContainer.changeTo({ EmptyScene() }, time = 0.5.seconds, transition = MaskTransition(TransitionFilter.Transition.HORIZONTAL)) val transitionView = sceneContainer.firstChild as TransitionView assertEquals("MaskTransition", transitionView.transition.toString()) - assertEquals(1.0, transitionView.ratio) + assertEquals(Ratio.ONE, transitionView.ratio) val endTime = time assertTrue { endTime - startTime in 0.5.seconds..0.75.seconds } } @@ -90,7 +91,7 @@ class SceneContainerTest : ViewsForTesting() { sceneContainer.changeTo(time = 0.5.seconds, transition = MaskTransition(TransitionFilter.Transition.HORIZONTAL)) val transitionView = sceneContainer.firstChild as TransitionView assertEquals("MaskTransition", transitionView.transition.toString()) - assertEquals(1.0, transitionView.ratio) + assertEquals(Ratio.ONE, transitionView.ratio) val endTime = time assertTrue { endTime - startTime in 0.5.seconds..0.75.seconds } } diff --git a/korge/test/jvm/korlibs/korge/view/TransitionViewTest.kt b/korge/test/jvm/korlibs/korge/view/TransitionViewTest.kt index a2ffe8d6bb..491e8d53ce 100644 --- a/korge/test/jvm/korlibs/korge/view/TransitionViewTest.kt +++ b/korge/test/jvm/korlibs/korge/view/TransitionViewTest.kt @@ -5,6 +5,7 @@ import korlibs.korge.scene.* import korlibs.korge.testing.* import korlibs.korge.view.filter.* import korlibs.math.geom.* +import korlibs.math.interpolation.* import kotlin.test.* class TransitionViewTest { @@ -17,13 +18,13 @@ class TransitionViewTest { solidRect(50, 50, Colors.BLUE) } }, MaskTransition(TransitionFilter.Transition.CIRCULAR)) - tv.ratio = 0.5 + tv.ratio = Ratio.HALF addChild(tv) assertScreenshot(posterize = 5) - tv.ratio = 0.9 + tv.ratio = 0.9.toRatio() assertScreenshot(posterize = 5) - tv.ratio = 1.0 + tv.ratio = 1.0.toRatio() assertScreenshot(posterize = 5) }