diff --git a/README.md b/README.md index 7eda1af4..937c9047 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,9 @@ A growing library of assorted data structures, algorithms and utilities. - [`orx-camera`](orx-camera/README.md), 3d camera and controls - [`orx-compositor`](orx-compositor/README.md), a simple toolkit to make composite (layered) images -- [`orx-filter-extension`](orx-filter-extension/README.md), Program extension method that provides Filter based `extend()` +- [`orx-easing`](orx-easing/README.md), a collection of easing functions. +- [`orx-file-watcher`](orx-file-watcher/README.md), `Program` extension method that allows monitoring and hot loading from files. +- [`orx-filter-extension`](orx-filter-extension/README.md), `Program` extension method that provides Filter based `extend()` - [`orx-integral-image`](orx-integral-image/README.md), CPU-based and GPU-based implementation for integral images (summed area tables) - `orx-jumpflood`, a filter/shader based implementation of the jump flood algorithm for finding fast approximate (directional) distance fields - `orx-kdtree`, a kd-tree implementation for fast nearest point searches @@ -16,7 +18,7 @@ A growing library of assorted data structures, algorithms and utilities. - [`orx-obj-loader`](orx-obj-loader/README.md), simple Wavefront .obj mesh loader ## Usage -ORX 0.0.20 is built against OPENRNDR 0.3.32, make sure you use this version in your project. Because OPENRNDR's API is pre 1.0 it tends to change from time to time. +ORX 0.0.23 is built against OPENRNDR 0.3.33-rc1, make sure you use this version in your project. Because OPENRNDR's API is pre 1.0 it tends to change from time to time. The easiest way to add ORX to your project is through the use of Jitpack. [Jitpack](http://jitpack.io) is a service that pulls Gradle based libraries from Github, builds them and serves the jar files. @@ -30,13 +32,13 @@ repositories { You can then add any of the ORX artifacts to your `dependencies {}`: ``` dependencies { - compile 'com.github.openrndr.orx::v0.0.20' + compile 'com.github.openrndr.orx::v0.0.23' } ``` For example if you want to use the `orx-no-clear` artifact one would use: ``` dependencies { - compile 'com.github.openrndr.orx:orx-no-clear:v0.0.20' + compile 'com.github.openrndr.orx:orx-no-clear:v0.0.23' } ``` \ No newline at end of file diff --git a/build.gradle b/build.gradle index 2722b0f5..ce8f9e16 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { allprojects { group 'org.openrndr.extra' - version '0.0.22' + version '0.0.23' } repositories { @@ -40,7 +40,6 @@ subprojects { publications { mavenJava(MavenPublication) { from components.java - artifact sourceJar } } @@ -50,9 +49,6 @@ subprojects { classifier = 'sources' from sourceSets.main.kotlin } - - - } dependencies { diff --git a/orx-easing/README.md b/orx-easing/README.md new file mode 100644 index 00000000..029a3ccb --- /dev/null +++ b/orx-easing/README.md @@ -0,0 +1,31 @@ +# orx-easing + +A collection of easing functions similar to those on https://easings.net + + - `easeLinear` + - `easeBackIn`, `easeBackInOut`, `easeBackOut` + - `easeBounceIn`, `easeBounceInOut`, `easeBounceOut` + - `easeCircIn`, `easeCircInOut`, `easeCircOut` + - `easeCubicIn`, `easeCubicInOut` `easeCubicOut` + - `easeElasticIn`, `easeElasticInOut`, `easeElasticOut` + - `easeExpoIn`, `easeExpoInOut`, `easeExpoOut` + - `easeQuadIn`, `easeQuadInOut`, `easeQuadOut` + - `easeQuartIn`, `easeQuartInOut`, `easeQuartOut` + - `easeQuintIn`, `easeQuintInOut`, `easeQuintOut` + - `easeSineIn`, `easeSineInOut`, `easeSineOut` + +## usage + +`fun easeX(time: Double, bias: Double = 0.0, scale: Double = 1.0, duration : Double = 1.0)` + +```kotlin +// -- when t is in [0, 1] +val et = easeQuadIn(t) +val et = easeQuadIn(t, 0.0, 1.0, 10.0) +``` + +Using the `Easing` enumeration + +```kotlin +val et = Easing.QuadIn.function(t, 0.0, 1.0, 1.0) +``` \ No newline at end of file diff --git a/orx-easing/src/main/kotlin/Easing.kt b/orx-easing/src/main/kotlin/Easing.kt new file mode 100644 index 00000000..a855032f --- /dev/null +++ b/orx-easing/src/main/kotlin/Easing.kt @@ -0,0 +1,321 @@ +package org.openrndr.extras.easing + +typealias EasingFunction = (Double, Double, Double, Double) -> Double + +fun easeLinear(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0) = c * (t / d) + b + +// -- constant + +fun easeZero(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0) = b +fun easeOne(t: Double, b: Double = 0.0, c: Double = 1.0, d : Double = 1.0) = b + c + +// -- back + +fun easeBackIn(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double { + val s = 1.70158 + val td = t / d + return c * (td) * td * ((s + 1) * td - s) + b +} + +fun easeBackInOut(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double { + val s = 1.70158 * 1.525 + val s2 = s * 1.525 + val td2 = t / (d / 2) + val td22 = td2 - 2 + return if (td2 < 1) c / 2 * (t * t * ((s + 1) * t - s)) + b else c / 2 * ((td22) * td22 * (((s2) + 1) * t + s2) + 2) + b +} + +fun easeBackOut(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double { + val s = 1.70158 + val td1 = t / d - 1 + return c * (td1 * td1 * ((s + 1) * t + s) + 1) + b +} + +// -- bounce + +fun easeBounceIn(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double { + var t1 = d - t + val result: Double + t1 /= d + if (t1 < 1 / 2.75) { + result = c * (7.5625 * t1 * t1) + 0.toDouble() + } else if (t1 < 2 / 2.75f) { + t1 -= (1.5 / 2.75) + result = c * (7.5625 * (t1 * t1 + .75f)) + } else if (t1 < 2.5 / 2.75) { + t1 -= 2.25 / 2.75 + result = c * (7.5625 * (t1 * t1 + .9375f)) + } else { + t1 -= (2.625 / 2.75) + result = c * (7.5625 * (t1) * t1 + .984375f) + } + return c - result + b +} + +fun easeBounceInOut(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double { + var t1 = d - t * 2 + val result: Double + t1 /= d + if (t1 < 1 / 2.75f) { + result = c * (7.5625 * t1 * t1) + 0.toDouble() + } else if (t1 < 2 / 2.75f) { + t1 -= 1.5 / 2.75 + result = c * (7.5625 * (t1) * t1 + .75f) + 0.toDouble() + } else if (t1 < 2.5 / 2.75) { + t1 -= 2.25 / 2.75 + result = c * (7.5625 * (t1) * t1 + .9375f) + 0.toDouble() + } else { + t1 -= 2.625 / 2.75 + result = c * (7.5625 * (t1) * t1 + .984375f) + 0.toDouble() + //return c * (7.5625 * pow((t/d) -(2.625 / 2.75),2) + .984375) + b; + + } + var t2 = t * 2 - d + val result1: Double + t2 /= d + if (t2 < 1 / 2.75f) result1 = c * (7.5625 * t2 * t2) + 0.toDouble() else if (t2 < 2 / 2.75f) { + t2 -= 1.5 / 2.75 + result1 = c * (7.5625 * t2 * t2 + .75f) + } else if (t2 < 2.5 / 2.75) { + t2 -= 2.25 / 2.75 + result1 = c * (7.5625 * t2 * t2 + .9375f) + } else { + t2 -= 2.626 / 2.75 + result1 = c * (7.5625 * t2 * t2 + .984375f) + } + return if (t < d / 2) + (c - result) * .5 + b + else + result1 * .5 + c * .5 + b + +} + +fun easeBounceOut(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double { + + var td = t / d + + return if (td < (1 / 2.75f)) { + c * (7.5625f * td * td) + b + } else if (t < (2 / 2.75f)) { + td -= 1.5 / 2.75 + c * (7.5625f * td * td + .75f) + b + } else if (t < (2.5 / 2.75)) { + td -= 2.25 / 2.75 + c * (7.5625f * td * td + .9375f) + b + } else { + td -= 2.625 / 2.75 + c * (7.5625f * td * td + .984375f) + b + } +} + +// -- circ + +fun easeCircIn(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double { + val td = t / d + return -c * (Math.sqrt(1 - td * td) - 1) + b +} + +fun easeCircInOut(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double { + var td2 = t / (d / 2.0) + if (td2 < 1) + return -c / 2 * (Math.sqrt(1 - td2 * td2) - 1) + b + td2 -= 2 + return c / 2 * (Math.sqrt(1 - td2 * td2) + 1) + b +} + +fun easeCircOut(t: Double, b: Double, c: Double, d: Double): Double { + val td = t / d - 1 + return c * Math.sqrt(1 - td * td) + b +} + +// -- cubic + +fun easeCubicIn(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double { + val td = t / d + return c * td * td * td + b +} + +fun easeCubicOut(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double { + val td = t / d - 1.0 + return c * (td * td * td + 1) + b +} + +fun easeCubicInOut(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double { + val td = t / (d / 2) + val td2 = td - 2.0 + return if (td < 1) c / 2 * td * td * td + b else c / 2 * (td2 * td2 * td2 + 2) + b +} + +// -- elastic + +fun easeElasticIn(t: Double, b: Double, c: Double, d: Double): Double { + if (t == 0.0) { + return b + } else if (t / d == 1.0) { + return b + c + } else { + var td = t / d + val p = d * .3f + val s = p / 4 + td -= 1.0 + return -(c * Math.pow(2.0, 10 * (td)) * Math.sin((td * d - s) * (2 * Math.PI) / p)) + b + } +} + +fun easeElasticInOut(t: Double, b: Double, c: Double, d: Double): Double { + var td2 = t / (d / 2) + + if (t == 0.0) + return b + if (td2 == 2.0) + return b + c + val p = d * (.3f * 1.5f) + val s = p / 4 + td2 -= 1.0 + val td3 = td2 - 1.0 + return if (t < 1) -.5f * (c * Math.pow(2.0, 10 * (td2)) * Math.sin((td2 * d - s) * (2 * Math.PI) / p)) + b else c * Math.pow(2.0, -10 * (td3) * Math.sin(td3 * d - s) * (2 * Math.PI) / p) * .5f + c + b + +} + +fun easeElasticOut(t: Double, b: Double, c: Double, d: Double): Double { + val td = t / d + if (t == 0.0) + return b + if (td == 1.0) + return b + c + val p = d * .3f + val s = p / 4 + return c * Math.pow(2.0, -10 * td) * Math.sin((td * d - s) * (2 * Math.PI) / p) + c + b +} + +// -- expo + +fun easeExpoIn(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double = + if (t == 0.0) b else c * Math.pow(2.0, 10 * (t / d - 1)) + b + +fun easeExpoInOut(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double { + val td2 = t / (d / 2) + return if (t == 0.0) { + b + } else if (t == d) { + b + c + } else if (td2 < 1) { + c / 2 * Math.pow(2.0, 10 * (t - 1)) + b + } else { + c / 2 * (-Math.pow(2.0, -10 * (t - 1.0)) + 2) + b + } +} + +fun easeExpoOut(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double = + if (t == d) b + c else c * (-Math.pow(2.0, -10 * t / d) + 1) + b + +// -- quad + +fun easeQuadIn(t: Double, b: Double, c: Double, d: Double): Double = c * (t / d) * (t / d) + b + +fun easeQuadInOut(t: Double, b: Double, c: Double, d: Double): Double { + val td = t / (d / 2) + return if (td < 1) { + c / 2 * td * td + b + } else { + -c / 2 * ((td - 1) * (td - 3) - 1) + b + } +} + +fun easeQuadOut(t: Double, b: Double, c: Double, d: Double): Double = -c * (t / d) * (t / d - 2) + b + +// -- quart + +fun easeQuartIn(t: Double, b: Double, c: Double, d: Double): Double { + val n = t / d + return c * n * n * n * n + b +} + +fun easeQuartInOut(t: Double, b: Double, c: Double, d: Double): Double { + val td = t / (d / 2) + val td2 = td - 2.0 + return if (td < 1) c / 2 * td * td * td * td + b else -c / 2 * (td2 * td2 * td2 * td2 - 2) + b +} + +fun easeQuartOut(t: Double, b: Double, c: Double, d: Double): Double { + val td = t / d - 1 + return -c * (td * td * td * td - 1) + b +} + +// -- quint + +fun easeQuintIn(t: Double, b: Double, c: Double, d: Double): Double { + val td = t / d + return c * td * td * td * td * td + b +} + +fun easeQuintInOut(t: Double, b: Double, c: Double, d: Double): Double { + val td = t / d + return c * td * td * td * td * td + b +} + +fun easeQuintOut(t: Double, b: Double, c: Double, d: Double): Double { + val td = t / d - 1 + return c * ((td) * td * td * td * td + 1) + b +} + +// -- sine + +fun easeSineIn(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double = + -c * Math.cos(t / d * (Math.PI / 2)) + c + b + +fun easeSineOut(t: Double, b: Double = 0.0, c: Double = 1.0, d: Double = 1.0): Double = + c * Math.sin(t / d * (Math.PI / 2)) + b + +fun easeSineInOut(t: Double, b: Double, c: Double, d: Double): Double = + -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b + + +enum class Easing(val function: EasingFunction) { + Linear(::easeLinear), + + Zero(::easeZero), + One(::easeOne), + + BackIn(::easeBackIn), + BackInOut(::easeBackInOut), + BackOut(::easeBackOut), + + BounceIn(::easeBounceIn), + BounceInOut(::easeBounceInOut), + BounceOut(::easeBounceOut), + + CircIn(::easeCircIn), + CircInOut(::easeCircInOut), + CircOut(::easeCircOut), + + CubicIn(::easeCubicIn), + CubicInOut(::easeCubicInOut), + CubicOut(::easeCubicOut), + + ElasticIn(::easeElasticIn), + ElasticInOut(::easeElasticInOut), + ElasticOut(::easeElasticOut), + + ExpoIn(::easeExpoIn), + ExpoInOut(::easeExpoInOut), + ExpoOut(::easeExpoOut), + + QuadIn(::easeQuadIn), + QuadInOut(::easeQuadInOut), + QuadOut(::easeQuadOut), + + QuartIn(::easeQuartIn), + QuartInOut(::easeQuartInOut), + QuartOut(::easeQuartOut), + + QuintIn(::easeQuintIn), + QuintInOut(::easeQuintInOut), + QuintOut(::easeQuintOut), + + SineIn(::easeSineIn), + SineInOut(::easeSineInOut), + SineOut(::easeSineOut), +} + + diff --git a/settings.gradle b/settings.gradle index 29230e50..3df1238b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,6 +2,7 @@ rootProject.name = 'orx' include 'orx-camera', 'orx-compositor', + 'orx-easing', 'orx-file-watcher', 'orx-filter-extension', 'orx-integral-image',