added floats.interpolate(), math.interpolate(), and LERP example

This commit is contained in:
Irmen de Jong 2024-11-24 08:51:34 +01:00
parent 90f1e7fd6a
commit 857d2eefca
8 changed files with 267 additions and 4 deletions

View File

@ -662,4 +662,12 @@ log2_tab
cx16.r0++
return v0 + cx16.r0
}
sub interpolate(ubyte v, ubyte inputMin, ubyte inputMax, ubyte outputMin, ubyte outputMax) -> ubyte {
; Interpolate a value v in interval [inputMin, inputMax] to output interval [outputMin, outputMax]
; There is no version for words because of lack of precision in the fixed point calculation there.
cx16.r0 = ((v-inputMin)*256+inputMax) / (inputMax-inputMin)
cx16.r0 *= (outputMax-outputMin)
return cx16.r0H + outputMin
}
}

View File

@ -12,6 +12,14 @@ txt {
alias print_f = floats.print
}
math {
%option merge, ignore_unused ; add functions to math
alias lerpf = floats.lerp
alias lerpf_fast = floats.lerp_fast
alias interpolatef = floats.interpolate
}
floats {
; the floating point functions shared across compiler targets
%option merge, no_symbol_prefixing, ignore_unused
@ -286,4 +294,12 @@ sub lerp_fast(float v0, float v1, float t) -> float {
return v0 + t * (v1 - v0)
}
sub interpolate(float v, float inputMin, float inputMax, float outputMin, float outputMax) -> float {
; Interpolate a value v in interval [inputMin, inputMax] to output interval [outputMin, outputMax]
if outputMin==outputMax
return outputMin
v = (v - inputMin) / (inputMax - inputMin)
return v * (outputMax - outputMin) + outputMin
}
}

View File

@ -15,6 +15,13 @@ txt {
alias print_f = floats.print
}
math {
%option merge, ignore_unused ; add functions to math
alias lerpf = floats.lerp
alias lerpf_fast = floats.lerp_fast
}
floats {
@ -233,4 +240,12 @@ sub lerp_fast(float v0, float v1, float t) -> float {
return v0 + t * (v1 - v0)
}
sub interpolate(float v, float inputMin, float inputMax, float outputMin, float outputMax) -> float {
; Interpolate a value v in interval [inputMin, inputMax] to output interval [outputMin, outputMax]
if outputMin==outputMax
return outputMin
v = (v - inputMin) / (inputMax - inputMin)
return v * (outputMax - outputMin) + outputMin
}
}

View File

@ -417,4 +417,12 @@ math {
cx16.r0++
return v0 + cx16.r0
}
sub interpolate(ubyte v, ubyte inputMin, ubyte inputMax, ubyte outputMin, ubyte outputMax) -> ubyte {
; Interpolate a value v in interval [inputMin, inputMax] to output interval [outputMin, outputMax]
; There is no version for words because of lack of precision in the fixed point calculation there.
cx16.r0 = ((v-inputMin)*256+inputMax) / (inputMax-inputMin)
cx16.r0 *= (outputMax-outputMin)
return cx16.r0H + outputMin
}
}

View File

@ -132,6 +132,7 @@ class TestCompilerOnExamplesCx16: FunSpec({
"cxlogo",
"diskspeed",
"fileseek",
"interpolation",
"kefrenbars",
"keyboardhandler",
"life",

View File

@ -697,10 +697,13 @@ Provides definitions for the ROM/Kernal subroutines and utility routines dealing
Linear interpolation (LERP). Precise method, which guarantees v = v1 when t = 1.
Returns an interpolation between two inputs (v0, v1) for a parameter t in the closed unit interval [0.0, 1.0]
``lerp_fast(v0, v1, t)```
``lerp_fast(v0, v1, t)``
Linear interpolation (LERP). Imprecise (but faster) method, which does not guarantee v = v1 when t = 1
Teturns an interpolation between two inputs (v0, v1) for a parameter t in the closed unit interval [0.0, 1.0]
``interpolate(v, inputMin, inputMax, outputMin, outputMax)``
Interpolate a value v in interval [inputMin, inputMax] to output interval [outputMin, outputMax]
graphics
--------
@ -857,6 +860,11 @@ but perhaps the provided ones can be of service too.
Returns an interpolation between two inputs (v0, v1) for a parameter t in the interval [0, 65535]
Guarantees v = v1 when t = 65535.
``interpolate(v, inputMin, inputMax, outputMin, outputMax)``
Interpolate a value v in interval [inputMin, inputMax] to output interval [outputMin, outputMax]
All values are unsigned bytes.
(there is no version for word values because of lack of precision in the fixed point calculation there).
cx16logo
--------

View File

@ -0,0 +1,192 @@
%import math
%import textio
%import sprites
%import floats
; shows the use of the LERP (Linear intERPolation) routines that prog8 provides.
; math.lerp / math.lerpw / floats.lerp / floats.lerp_fast
; LERP explained here: https://en.wikipedia.org/wiki/Linear_interpolation
; Here are a lot of easing functions you can use:
; https://blog.febucci.com/2018/08/easing-functions/ (links at the bottom)
main {
uword mx, my
sub start() {
void cx16.set_screen_mode(3)
cx16.mouse_config2(1)
sprites.set_mousepointer_hand()
repeat {
txt.cls()
txt.print("\n\n floats.lerp()")
sys.wait(60)
repeat 2 lerp_float()
txt.cls()
txt.print("\n\n floats.lerp() with easing")
sys.wait(60)
repeat 2 lerp_float_easing()
txt.cls()
txt.print("\n\n integer math.lerp()")
sys.wait(60)
repeat 2 lerp_normal()
txt.cls()
txt.print("\n\n integer math.lerp() with easing")
sys.wait(60)
repeat 2 lerp_easing()
txt.cls()
txt.print("\n\n floats.interpolate()")
sys.wait(60)
repeat 2 interpolate_float()
txt.cls()
txt.print("\n\n integer math.interpolate()")
sys.wait(60)
repeat 2 interpolate_int()
}
}
sub interpolate_float() {
ubyte tt
for tt in 0 to 255 step 3 {
sys.waitvsync()
mx = floats.interpolate(tt as float, 0, 255, 50, 250) as uword
my = floats.interpolate(tt as float, 0, 255, 30, 150) as uword
cx16.mouse_set_pos(mx, my)
}
for tt in 255 downto 0 step -3 {
sys.waitvsync()
mx = floats.interpolate(tt as float, 0, 255, 50, 250) as uword
my = floats.interpolate(tt as float, 0, 255, 30, 150) as uword
cx16.mouse_set_pos(mx, my)
}
}
sub interpolate_int() {
ubyte tt
for tt in 50 to 250 step 3 {
sys.waitvsync()
mx = math.interpolate(tt, 50, 250, 50, 250)
my = math.interpolate(tt, 50, 250, 30, 150)
cx16.mouse_set_pos(mx, my)
}
for tt in 250 downto 50 step -3 {
sys.waitvsync()
mx = math.interpolate(tt, 50, 250, 50, 250)
my = math.interpolate(tt, 50, 250, 30, 150)
cx16.mouse_set_pos(mx, my)
}
}
sub lerp_float() {
ubyte tt
for tt in 0 to 255 step 3 {
sys.waitvsync()
mx = floats.lerp(50, 250, tt as float/256) as uword
my = floats.lerp(30, 150, tt as float/256) as uword
cx16.mouse_set_pos(mx, my)
}
for tt in 255 downto 0 step -3 {
sys.waitvsync()
mx = floats.lerp(50, 250, tt as float/256) as uword
my = floats.lerp(30, 150, tt as float/256) as uword
cx16.mouse_set_pos(mx, my)
}
}
sub lerp_float_easing() {
float e
ubyte tt
for tt in 0 to 255 step 2 {
sys.waitvsync()
e = ease(tt)
mx = floats.lerp(50, 250, e) as uword
my = floats.lerp(30, 150, e) as uword
cx16.mouse_set_pos(mx, my)
}
for tt in 255 downto 0 step -2 {
sys.waitvsync()
e = 1 - ease(255-tt)
mx = floats.lerp(50, 250, e) as uword
my = floats.lerp(30, 150, e) as uword
cx16.mouse_set_pos(mx, my)
}
sub ease(ubyte t) -> float {
; bounce
const float n1 = 7.5625
const float d1 = 2.75
float x = t as float/256
if (x < 1 / d1) {
return n1 * x * x;
} else if (x < 2 / d1) {
x = x - 1.5 / d1;
return n1 * x * x + 0.75;
} else if (x < 2.5 / d1) {
x = x - 2.25 / d1;
return n1 * x * x + 0.9375;
} else {
x = x - 2.625 / d1;
return n1 * x * x + 0.984375;
}
}
sub ease2(ubyte t) -> float {
; 'smootherstep'
float x = t as float/256
return x * x * x * (x * (x * 6 - 15) + 10)
}
}
sub lerp_normal() {
ubyte tt
for tt in 0 to 255 step 3 {
sys.waitvsync()
mx = math.lerp(50, 250, tt)
my = math.lerp(30, 150, tt)
cx16.mouse_set_pos(mx, my)
}
for tt in 255 downto 0 step -3 {
sys.waitvsync()
mx = math.lerp(50, 250, tt)
my = math.lerp(30, 150, tt)
cx16.mouse_set_pos(mx, my)
}
}
sub lerp_easing() {
ubyte e
ubyte tt
for tt in 0 to 255 step 3 {
sys.waitvsync()
e = ease(tt)
mx = math.lerp(50, 250, e)
my = math.lerp(30, 150, e)
cx16.mouse_set_pos(mx, my)
}
for tt in 255 downto 0 step -3 {
sys.waitvsync()
e = ease(tt)
mx = math.lerp(50, 250, e)
my = math.lerp(30, 150, e)
cx16.mouse_set_pos(mx, my)
}
sub ease(ubyte t) -> ubyte {
return msb(t as uword*t) ; 'squaring'
}
}
}

View File

@ -1,10 +1,25 @@
%import floats
%import math
%import textio
%zeropage basicsafe
main {
alias print = txt.print_ub
sub start() {
print(42)
floats.print(floats.interpolate(0, 0, 10, 1000, 2000))
txt.spc()
txt.print_uw(math.interpolate(10, 10, 20, 100, 200))
txt.nl()
floats.print(floats.interpolate(2.22, 0, 10, 1000, 2000))
txt.spc()
txt.print_uw(math.interpolate(12, 10, 20, 100, 200))
txt.nl()
floats.print(floats.interpolate(5.0, 0, 10, 1000, 2000))
txt.spc()
txt.print_uw(math.interpolate(15, 10, 20, 100, 200))
txt.nl()
floats.print(floats.interpolate(10, 0, 10, 1000, 2000))
txt.spc()
txt.print_uw(math.interpolate(20, 10, 20, 100, 200))
txt.nl()
}
}