mirror of
https://github.com/irmen/prog8.git
synced 2024-11-28 10:51:14 +00:00
added floats.interpolate(), math.interpolate(), and LERP example
This commit is contained in:
parent
90f1e7fd6a
commit
857d2eefca
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -132,6 +132,7 @@ class TestCompilerOnExamplesCx16: FunSpec({
|
||||
"cxlogo",
|
||||
"diskspeed",
|
||||
"fileseek",
|
||||
"interpolation",
|
||||
"kefrenbars",
|
||||
"keyboardhandler",
|
||||
"life",
|
||||
|
@ -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
|
||||
--------
|
||||
|
192
examples/cx16/interpolation.p8
Normal file
192
examples/cx16/interpolation.p8
Normal 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'
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user