diff --git a/vlib/math/interpolation.v b/vlib/math/interpolation.v index 6ed74be10a..01572bd1a8 100644 --- a/vlib/math/interpolation.v +++ b/vlib/math/interpolation.v @@ -11,6 +11,16 @@ pub fn mix[T](start T, end T, t T) T { return start * (1 - t) + end * t } +// exp_decay returns a frame independent exponential decay value between `a` and `b` using `delta_time_seconds`. +// `decay` is supposed to be useful in the range 1.0 to 25.0. From slow to fast. +// The function is a frame rate independent (approximation) of the well-known `lerp` or `mix` (linear interpolation) function. +// It is ported to V from the pseudo code shown towards the end of the video https://youtu.be/LSNQuFEDOyQ?t=2977 +// NOTE: Thanks to Freya Holmér for the function and the work done in this field. +@[inline] +pub fn exp_decay[T](a T, b T, decay f64, delta_time_seconds f64) T { + return T(f64(b) + (f64(a) - f64(b)) * exp(-decay * delta_time_seconds)) +} + // clip constrain the given value `x`, to lie between two further values `min_value` and `max_value`. // See: https://registry.khronos.org/OpenGL-Refpages/gl4/html/clamp.xhtml // Also: https://en.wikipedia.org/wiki/Clamp_(function) diff --git a/vlib/math/interpolation_test.v b/vlib/math/interpolation_test.v index 7135f7eee1..b5369669bb 100644 --- a/vlib/math/interpolation_test.v +++ b/vlib/math/interpolation_test.v @@ -1,5 +1,7 @@ import math +const decay = 100 + fn test_mix() { assert math.mix(0.0, 100.0, 0.0) == 0.0 assert math.mix(0.0, 100.0, 0.1) == 10.0 @@ -18,6 +20,20 @@ fn test_mix() { assert math.mix(100.0, 500.0, 1.0) == 500.0 } +fn test_exp_decay() { + assert math.exp_decay(0.0, 100.0, decay, 0.0) == 0.0 + assert math.exp_decay(0.0, 100.0, decay, 1.0) == 100.0 + + assert math.exp_decay(100.0, 500.0, decay, 0.0) == 100.0 + assert math.exp_decay(100.0, 500.0, decay, 1.0) == 500.0 + + assert math.exp_decay(0, 100, decay, 0.0) == 0 + assert math.exp_decay(0, 100, decay, 1.0) == 100 + + assert math.exp_decay(100, 500, decay, 0.0) == 100 + assert math.exp_decay(100, 500, decay, 1.0) == 500 +} + fn test_clip() { assert math.clip(0.0, 10.0, 50.0) == 10.0 assert math.clip(5.5, 10.0, 50.0) == 10.0