Skip to content

Instantly share code, notes, and snippets.

@jakubtomsu
Last active July 15, 2024 14:12
Show Gist options
  • Save jakubtomsu/75ef92cc7914ecde740d4943ef6161c5 to your computer and use it in GitHub Desktop.
Save jakubtomsu/75ef92cc7914ecde740d4943ef6161c5 to your computer and use it in GitHub Desktop.
Easings library ported to Odin
package ease
// Adapted from functions here: https://github.com/warrenm/AHEasing/blob/master/AHEasing/easing.c
// For previews go here: https://easings.net/
import "core:math"
Mode :: enum {
linear = 0,
quad_in,
quad_out,
quad_in_out,
cube_in,
cube_out,
cube_in_out,
quart_in,
quart_out,
quart_in_out,
quint_in,
quint_out,
quint_in_out,
sine_in,
sine_out,
sine_in_out,
circ_in,
circ_out,
circ_in_out,
exp_in,
exp_out,
exp_in_out,
elastic_in,
elastic_out,
elastic_in_out,
back_in,
back_out,
back_in_out,
bounce_in,
bounce_out,
bounce_in_out,
}
linear :: proc(t: f32) -> f32 {
return t
}
quad_in :: proc(t: f32) -> f32 {
return t * t
}
quad_out :: proc(t: f32) -> f32 {
return -(t * (t - 2))
}
quad_in_out :: proc(t: f32) -> f32 {
if t < 0.5 {
return 2 * t * t
}
return (-2 * t * t) + (4 * t) - 1
}
cube_in :: proc(t: f32) -> f32 {
return t * t * t
}
cube_out :: proc(t: f32) -> f32 {
f: f32 = (t - 1)
return f * f * f + 1
}
cube_in_out :: proc(t: f32) -> f32 {
if t < 0.5 {
return 4 * t * t * t
}
f: f32 = (2 * t) - 2
return 0.5 * f * f * f + 1
}
quart_in :: proc(t: f32) -> f32 {
return t * t * t * t
}
quart_out :: proc(t: f32) -> f32 {
f: f32 = (t - 1)
return f * f * f * (1 - t) + 1
}
quart_in_out :: proc(t: f32) -> f32 {
if t < 0.5 {
return 8 * t * t * t * t
}
f: f32 = (t - 1)
return -8 * f * f * f * f + 1
}
quint_in :: proc(t: f32) -> f32 {
return t * t * t * t * t
}
quint_out :: proc(t: f32) -> f32 {
f: f32 = (t - 1)
return f * f * f * f * f + 1
}
quint_in_out :: proc(t: f32) -> f32 {
if t < 0.5 {
return 16 * t * t * t * t * t
}
f: f32 = ((2 * t) - 2)
return 0.5 * f * f * f * f * f + 1
}
sine_in :: proc(t: f32) -> f32 {
return math.sin((t - 1.0) * math.PI * 0.5) + 1.0
}
sine_out :: proc(t: f32) -> f32 {
return math.sin(t * (math.PI * 0.5))
}
sine_in_out :: proc(t: f32) -> f32 {
return 0.5 * (1 - math.cos(t * math.PI))
}
circ_in :: proc(t: f32) -> f32 {
return 1 - math.sqrt(1 - (t * t))
}
circ_out :: proc(t: f32) -> f32 {
return math.sqrt((2 - t) * t)
}
circ_in_out :: proc(t: f32) -> f32 {
if t < 0.5 {
return 0.5 * (1 - math.sqrt(1 - 4 * (t * t)))
}
return 0.5 * (math.sqrt(-((2 * t) - 3) * ((2 * t) - 1)) + 1)
}
exp_in :: proc(t: f32) -> f32 {
return (t == 0) ? 0 : math.pow(2, 10 * (t - 1))
}
exp_out :: proc(t: f32) -> f32 {
return (t == 1) ? 1 : 1 - math.pow(2, -10 * t)
}
exp_in_out :: proc(t: f32) -> f32 {
if t == 0 || t == 1 {
return t
}
if t < 0.5 {
return 0.5 * math.pow(2, (20 * t) - 10)
}
return -0.5 * math.pow(2, (-20 * t) + 10) + 1
}
elastic_in :: proc(t: f32) -> f32 {
return math.sin(13 * (math.PI * 0.5) * t) * math.pow(2, 10 * (t - 1))
}
elastic_out :: proc(t: f32) -> f32 {
return math.sin(-13 * (math.PI * 0.5) * (t + 1)) * math.pow(2, -10 * t) + 1
}
elastic_in_out :: proc(t: f32) -> f32 {
if t < 0.5 {
return 0.5 * math.sin(13 * (math.PI * 0.5) * (2 * t)) * math.pow(2, 10 * ((2 * t) - 1))
}
return 0.5 * (math.sin(-13 * (math.PI * 0.5) * ((2 * t - 1) + 1)) * math.pow(2, -10 * (2 * t - 1)) + 2)
}
back_in :: proc(t: f32) -> f32 {
return t * t * t - t * math.sin(t * math.PI)
}
back_out :: proc(t: f32) -> f32 {
f: f32 = (1 - t)
return 1 - (f * f * f - f * math.sin(f * math.PI))
}
back_in_out :: proc(t: f32) -> f32 {
if (t < 0.5) {
f: f32 = 2 * t
return 0.5 * (f * f * f - f * math.sin(f * math.PI))
} else {
f: f32 = (1 - (2 * t - 1))
return 0.5 * (1 - (f * f * f - f * math.sin(f * math.PI))) + 0.5
}
}
bounce_out :: proc(t: f32) -> f32 {
if t < 4 / 11.0 {
return (121 * t * t) / 16.0
}
if t < 8 / 11.0 {
return (363 / 40.0 * t * t) - (99 / 10.0 * t) + 17 / 5.0
}
if t < 9 / 10.0 {
return (4356 / 361.0 * t * t) - (35442 / 1805.0 * t) + 16061 / 1805.0
}
return (54 / 5.0 * t * t) - (513 / 25.0 * t) + 268 / 25.0
}
bounce_in :: proc(t: f32) -> f32 {
return 1 - bounce_out(1 - t)
}
bounce_in_out :: proc(t: f32) -> f32 {
if t < 0.5 {
return 0.5 * bounce_in(t * 2)
}
return 0.5 * bounce_out(t * 2 - 1) + 0.5
}
mode_ease :: proc(e: Mode, t: f32) -> f32 {
switch (e) {
case .linear:
return linear(t)
case .cube_in:
return cube_in(t)
case .cube_out:
return cube_out(t)
case .cube_in_out:
return cube_in_out(t)
case .quad_in:
return quad_in(t)
case .quad_out:
return quad_out(t)
case .quad_in_out:
return quad_in_out(t)
case .quart_in:
return quart_in(t)
case .quart_out:
return quart_out(t)
case .quart_in_out:
return quart_in_out(t)
case .quint_in:
return quint_in(t)
case .quint_out:
return quint_out(t)
case .quint_in_out:
return quint_in_out(t)
case .sine_in:
return sine_in(t)
case .sine_out:
return sine_out(t)
case .sine_in_out:
return sine_in_out(t)
case .circ_in:
return circ_in(t)
case .circ_out:
return circ_out(t)
case .circ_in_out:
return circ_in_out(t)
case .exp_in:
return exp_in(t)
case .exp_out:
return exp_out(t)
case .exp_in_out:
return exp_in_out(t)
case .elastic_in:
return elastic_in(t)
case .elastic_out:
return elastic_out(t)
case .elastic_in_out:
return elastic_in_out(t)
case .back_in:
return back_in(t)
case .back_out:
return back_out(t)
case .back_in_out:
return back_in_out(t)
case .bounce_in:
return bounce_in(t)
case .bounce_out:
return bounce_out(t)
case .bounce_in_out:
return bounce_in_out(t)
}
return t
}
package ease
// Graphing app example
import "vendor:raylib"
import "core:reflect"
import "core:fmt"
import "core:strings"
main :: proc() {
WINDOW_X :: 800
WINDOW_Y :: 480
raylib.InitWindow(800, 480, "Ease Example")
e := Mode.linear
for !raylib.WindowShouldClose() {
// Update
// Cycle between easing functions
if raylib.IsKeyPressed(.LEFT) do e = Mode((int(e) - 1) %% len(Mode))
if raylib.IsKeyPressed(.RIGHT) do e = Mode((int(e) + 1) %% len(Mode))
// Draw
raylib.BeginDrawing()
raylib.ClearBackground({50, 55, 60, 255})
NUM_POINTS :: 256
Y_MORE :: 0.15
for i in 0 ..< NUM_POINTS - 1 {
x := f32(i) / NUM_POINTS
y := 1.0 - Y_MORE - mode_ease(e, x) * (1.0 - Y_MORE * 2)
x_next := f32(i + 1) / NUM_POINTS
y_next := 1.0 - Y_MORE- mode_ease(e, x_next) * (1.0 - Y_MORE * 2)
raylib.DrawLineEx({x * WINDOW_X, y * WINDOW_Y}, {x_next * WINDOW_X, y_next * WINDOW_Y}, 5.0, {200, 200, 220, 100})
}
raylib.DrawLineEx({0, Y_MORE * WINDOW_Y}, {WINDOW_X, Y_MORE * WINDOW_Y}, 2.0, {200, 200, 220, 50})
raylib.DrawLineEx({0, (1.0 - Y_MORE) * WINDOW_Y}, {WINDOW_X, (1.0 - Y_MORE) * WINDOW_Y}, 2.0, {200, 200, 220, 50})
raylib.DrawText(strings.clone_to_cstring(fmt.tprint("Easing function: <", reflect.enum_string(e), ">"), context.temp_allocator), 5, 5, 20, raylib.WHITE)
raylib.EndDrawing()
}
raylib.CloseWindow()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment