mt-lang 0.3.1 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/lsp/diagnostics.rb +1 -1
- data/lib/milk_tea/tooling/linter/imports_platform.rb +14 -3
- data/lib/milk_tea/tooling/linter/release_rules.rb +24 -3
- data/lib/milk_tea/tooling/linter/visitors.rb +1 -0
- data/std/blackboard.mt +100 -0
- data/std/cmd.mt +132 -0
- data/std/color.mt +245 -0
- data/std/graph.mt +237 -0
- data/std/htn.mt +254 -0
- data/std/input.mt +132 -0
- data/std/iter.mt +304 -0
- data/std/mem/ptr.mt +12 -0
- data/std/noise.mt +201 -0
- data/std/pool.mt +82 -0
- data/std/signal.mt +66 -0
- data/std/simd.mt +100 -0
- data/std/steering.mt +132 -0
- data/std/timer.mt +81 -0
- data/std/tween.mt +374 -0
- data/std/utility.mt +208 -0
- metadata +17 -2
data/std/simd.mt
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
## SIMD helpers — load, store, and reduction operations
|
|
2
|
+
## for the built-in simd[T, N] type constructor.
|
|
3
|
+
##
|
|
4
|
+
## Load and store use unsafe ptr casts internally; the user-facing
|
|
5
|
+
## surface is safe because only valid pointer dereferencing is involved.
|
|
6
|
+
##
|
|
7
|
+
## Usage:
|
|
8
|
+
## import std.simd as simd
|
|
9
|
+
## let v = simd.load_aligned_float4(ptr)
|
|
10
|
+
## let s = simd.horizontal_sum_float4(v)
|
|
11
|
+
|
|
12
|
+
import std.mem.ptr as ptr
|
|
13
|
+
|
|
14
|
+
## ── simd[float, 4] ──────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
public function load_aligned_float4(p: ptr[float]) -> simd[float, 4]:
|
|
17
|
+
let sp = unsafe: ptr[simd[float, 4]]<-p
|
|
18
|
+
return sp.load()
|
|
19
|
+
|
|
20
|
+
public function load_unaligned_float4(p: ptr[float]) -> simd[float, 4]:
|
|
21
|
+
return load_aligned_float4(p)
|
|
22
|
+
|
|
23
|
+
public function store_aligned_float4(p: ptr[float], value: simd[float, 4]) -> void:
|
|
24
|
+
let sp = unsafe: ptr[simd[float, 4]]<-p
|
|
25
|
+
sp.store(value)
|
|
26
|
+
|
|
27
|
+
public function store_unaligned_float4(p: ptr[float], value: simd[float, 4]) -> void:
|
|
28
|
+
store_aligned_float4(p, value)
|
|
29
|
+
|
|
30
|
+
public function horizontal_sum_float4(v: simd[float, 4]) -> float:
|
|
31
|
+
return v[0] + v[1] + v[2] + v[3]
|
|
32
|
+
|
|
33
|
+
public function dot_float4(a: simd[float, 4], b: simd[float, 4]) -> float:
|
|
34
|
+
return horizontal_sum_float4(a * b)
|
|
35
|
+
|
|
36
|
+
## ── simd[int, 4] ────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
public function load_aligned_int4(p: ptr[int]) -> simd[int, 4]:
|
|
39
|
+
let sp = unsafe: ptr[simd[int, 4]]<-p
|
|
40
|
+
return sp.load()
|
|
41
|
+
|
|
42
|
+
public function load_unaligned_int4(p: ptr[int]) -> simd[int, 4]:
|
|
43
|
+
return load_aligned_int4(p)
|
|
44
|
+
|
|
45
|
+
public function store_aligned_int4(p: ptr[int], value: simd[int, 4]) -> void:
|
|
46
|
+
let sp = unsafe: ptr[simd[int, 4]]<-p
|
|
47
|
+
sp.store(value)
|
|
48
|
+
|
|
49
|
+
public function store_unaligned_int4(p: ptr[int], value: simd[int, 4]) -> void:
|
|
50
|
+
store_aligned_int4(p, value)
|
|
51
|
+
|
|
52
|
+
public function horizontal_sum_int4(v: simd[int, 4]) -> int:
|
|
53
|
+
return v[0] + v[1] + v[2] + v[3]
|
|
54
|
+
|
|
55
|
+
public function dot_int4(a: simd[int, 4], b: simd[int, 4]) -> int:
|
|
56
|
+
return horizontal_sum_int4(a * b)
|
|
57
|
+
|
|
58
|
+
## ── simd[float, 8] (AVX) ────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
public function load_aligned_float8(p: ptr[float]) -> simd[float, 8]:
|
|
61
|
+
let sp = unsafe: ptr[simd[float, 8]]<-p
|
|
62
|
+
return sp.load()
|
|
63
|
+
|
|
64
|
+
public function load_unaligned_float8(p: ptr[float]) -> simd[float, 8]:
|
|
65
|
+
return load_aligned_float8(p)
|
|
66
|
+
|
|
67
|
+
public function store_aligned_float8(p: ptr[float], value: simd[float, 8]) -> void:
|
|
68
|
+
let sp = unsafe: ptr[simd[float, 8]]<-p
|
|
69
|
+
sp.store(value)
|
|
70
|
+
|
|
71
|
+
public function store_unaligned_float8(p: ptr[float], value: simd[float, 8]) -> void:
|
|
72
|
+
store_aligned_float8(p, value)
|
|
73
|
+
|
|
74
|
+
public function horizontal_sum_float8(v: simd[float, 8]) -> float:
|
|
75
|
+
return v[0] + v[1] + v[2] + v[3] + v[4] + v[5] + v[6] + v[7]
|
|
76
|
+
|
|
77
|
+
public function dot_float8(a: simd[float, 8], b: simd[float, 8]) -> float:
|
|
78
|
+
return horizontal_sum_float8(a * b)
|
|
79
|
+
|
|
80
|
+
## ── simd[double, 2] ─────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
public function load_aligned_double2(p: ptr[double]) -> simd[double, 2]:
|
|
83
|
+
let sp = unsafe: ptr[simd[double, 2]]<-p
|
|
84
|
+
return sp.load()
|
|
85
|
+
|
|
86
|
+
public function load_unaligned_double2(p: ptr[double]) -> simd[double, 2]:
|
|
87
|
+
return load_aligned_double2(p)
|
|
88
|
+
|
|
89
|
+
public function store_aligned_double2(p: ptr[double], value: simd[double, 2]) -> void:
|
|
90
|
+
let sp = unsafe: ptr[simd[double, 2]]<-p
|
|
91
|
+
sp.store(value)
|
|
92
|
+
|
|
93
|
+
public function store_unaligned_double2(p: ptr[double], value: simd[double, 2]) -> void:
|
|
94
|
+
store_aligned_double2(p, value)
|
|
95
|
+
|
|
96
|
+
public function horizontal_sum_double2(v: simd[double, 2]) -> double:
|
|
97
|
+
return v[0] + v[1]
|
|
98
|
+
|
|
99
|
+
public function dot_double2(a: simd[double, 2], b: simd[double, 2]) -> double:
|
|
100
|
+
return horizontal_sum_double2(a * b)
|
data/std/steering.mt
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
## Steering behaviors — Craig Reynolds' autonomous motion.
|
|
2
|
+
##
|
|
3
|
+
## Pure-function steering forces for autonomous agents.
|
|
4
|
+
## Seek, flee, arrive, pursuit, evade, wander, and flocking
|
|
5
|
+
## (separation, alignment, cohesion). All return steering
|
|
6
|
+
## force vectors to be accumulated and applied by the caller.
|
|
7
|
+
##
|
|
8
|
+
## import std.steering as steer
|
|
9
|
+
## var force = steer.Steer.seek(pos, vel, target, max_speed)
|
|
10
|
+
## force = force + steer.Steer.separation(pos, neighbors, r, max_speed)
|
|
11
|
+
|
|
12
|
+
import std.linear_algebra as la
|
|
13
|
+
import std.math as math
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# ── internal helpers ──
|
|
17
|
+
|
|
18
|
+
function set_magnitude(v: vec2, magnitude: float) -> vec2:
|
|
19
|
+
let len = v.length()
|
|
20
|
+
if len <= 0.0:
|
|
21
|
+
return v
|
|
22
|
+
return v * (magnitude / len)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
function limit_force(steering: vec2, max_force: float) -> vec2:
|
|
26
|
+
let mag = steering.length()
|
|
27
|
+
if mag > max_force:
|
|
28
|
+
return steering * (max_force / mag)
|
|
29
|
+
return steering
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# ── public API ──
|
|
33
|
+
|
|
34
|
+
extending vec2:
|
|
35
|
+
public static function seek(position: vec2, velocity: vec2, target: vec2, max_speed: float) -> vec2:
|
|
36
|
+
let desired = target - position
|
|
37
|
+
let desired_vel = set_magnitude(desired, max_speed)
|
|
38
|
+
return desired_vel - velocity
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
public static function flee(position: vec2, velocity: vec2, threat: vec2, max_speed: float) -> vec2:
|
|
42
|
+
let desired = position - threat
|
|
43
|
+
let desired_vel = set_magnitude(desired, max_speed)
|
|
44
|
+
return desired_vel - velocity
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
public static function arrive(position: vec2, velocity: vec2, target: vec2, max_speed: float, slowing_distance: float) -> vec2:
|
|
48
|
+
let offset = target - position
|
|
49
|
+
let distance = offset.length()
|
|
50
|
+
if distance < 0.001:
|
|
51
|
+
return zero[vec2]
|
|
52
|
+
let speed = if distance < slowing_distance: max_speed * distance / slowing_distance else: max_speed
|
|
53
|
+
let desired_vel = offset * (speed / distance)
|
|
54
|
+
return desired_vel - velocity
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
public static function pursuit(position: vec2, velocity: vec2, target_pos: vec2, target_vel: vec2, max_speed: float) -> vec2:
|
|
58
|
+
let offset = target_pos - position
|
|
59
|
+
let distance = offset.length()
|
|
60
|
+
let my_speed = velocity.length()
|
|
61
|
+
var look_ahead: float = distance / (max_speed + 0.001)
|
|
62
|
+
if my_speed > 0.001:
|
|
63
|
+
look_ahead = distance / my_speed
|
|
64
|
+
let future = target_pos + target_vel * look_ahead
|
|
65
|
+
return vec2.seek(position, velocity, future, max_speed)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
public static function evade(position: vec2, velocity: vec2, threat_pos: vec2, threat_vel: vec2, max_speed: float) -> vec2:
|
|
69
|
+
let offset = threat_pos - position
|
|
70
|
+
let distance = offset.length()
|
|
71
|
+
let my_speed = velocity.length()
|
|
72
|
+
var look_ahead: float = distance / (max_speed + 0.001)
|
|
73
|
+
if my_speed > 0.001:
|
|
74
|
+
look_ahead = distance / my_speed
|
|
75
|
+
let future = threat_pos + threat_vel * look_ahead
|
|
76
|
+
return vec2.flee(position, velocity, future, max_speed)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
public static function wander(velocity: vec2, wander_angle: float, wander_distance: float, wander_radius: float) -> vec2:
|
|
80
|
+
if velocity.length() < 0.001:
|
|
81
|
+
return zero[vec2]
|
|
82
|
+
let forward = set_magnitude(velocity, 1.0)
|
|
83
|
+
let circle_center = forward * wander_distance
|
|
84
|
+
let wx = circle_center.x + wander_radius * float<-(math.cos(double<-(wander_angle)))
|
|
85
|
+
let wy = circle_center.y + wander_radius * float<-(math.sin(double<-(wander_angle)))
|
|
86
|
+
let displacement = vec2(x = wx, y = wy)
|
|
87
|
+
return displacement
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
public static function separation(position: vec2, neighbors: span[vec2], desired_separation: float) -> vec2:
|
|
91
|
+
var steer: vec2 = zero[vec2]
|
|
92
|
+
var count: ptr_uint = 0
|
|
93
|
+
for n in neighbors:
|
|
94
|
+
let d = position - n
|
|
95
|
+
let distance = d.length()
|
|
96
|
+
if distance > 0.0 and distance < desired_separation:
|
|
97
|
+
let repulsion = d * (1.0 / distance)
|
|
98
|
+
steer = steer + repulsion
|
|
99
|
+
count += 1
|
|
100
|
+
if count > 0:
|
|
101
|
+
steer = steer / float<-(count)
|
|
102
|
+
return steer
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
public static function alignment(velocity: vec2, neighbor_velocities: span[vec2]) -> vec2:
|
|
106
|
+
var sum: vec2 = zero[vec2]
|
|
107
|
+
var count: ptr_uint = 0
|
|
108
|
+
for nv in neighbor_velocities:
|
|
109
|
+
sum = sum + nv
|
|
110
|
+
count += 1
|
|
111
|
+
if count > 0:
|
|
112
|
+
let avg = sum / float<-(count)
|
|
113
|
+
return avg - velocity
|
|
114
|
+
return zero[vec2]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
public static function cohesion(position: vec2, neighbor_positions: span[vec2], radius: float) -> vec2:
|
|
118
|
+
var sum: vec2 = zero[vec2]
|
|
119
|
+
var count: ptr_uint = 0
|
|
120
|
+
for np in neighbor_positions:
|
|
121
|
+
let d = position - np
|
|
122
|
+
if d.length() < radius:
|
|
123
|
+
sum = sum + np
|
|
124
|
+
count += 1
|
|
125
|
+
if count > 0:
|
|
126
|
+
let center = sum / float<-(count)
|
|
127
|
+
return center - position
|
|
128
|
+
return zero[vec2]
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
public static function limit(steering: vec2, max_force: float) -> vec2:
|
|
132
|
+
return limit_force(steering, max_force)
|
data/std/timer.mt
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
## Timer — countdown and repeating timers.
|
|
2
|
+
##
|
|
3
|
+
## Accumulate delta time and fire when duration is reached.
|
|
4
|
+
## Supports one-shot (auto-stop) and repeating (auto-reset).
|
|
5
|
+
##
|
|
6
|
+
## import std.timer as time
|
|
7
|
+
## var cooldown = time.Timer.create(0.5, false)
|
|
8
|
+
## var regen = time.Timer.create(1.0, true)
|
|
9
|
+
## ...
|
|
10
|
+
## if cooldown.step(dt): do_ability()
|
|
11
|
+
## if regen.step(dt): heal(1)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
public struct Timer:
|
|
15
|
+
duration: float
|
|
16
|
+
elapsed: float
|
|
17
|
+
active: bool
|
|
18
|
+
repeating: bool
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# ── public API ──
|
|
22
|
+
|
|
23
|
+
extending Timer:
|
|
24
|
+
public static function create(duration: float, repeating: bool) -> Timer:
|
|
25
|
+
return Timer(
|
|
26
|
+
duration = duration,
|
|
27
|
+
elapsed = 0.0,
|
|
28
|
+
active = true,
|
|
29
|
+
repeating = repeating
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
public editable function step(dt: float) -> bool:
|
|
34
|
+
if not this.active:
|
|
35
|
+
return false
|
|
36
|
+
this.elapsed = this.elapsed + dt
|
|
37
|
+
if this.elapsed >= this.duration:
|
|
38
|
+
if this.repeating:
|
|
39
|
+
this.elapsed = this.elapsed - this.duration
|
|
40
|
+
else:
|
|
41
|
+
this.elapsed = this.duration
|
|
42
|
+
this.active = false
|
|
43
|
+
return true
|
|
44
|
+
return false
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
public function progress() -> float:
|
|
48
|
+
if this.duration <= 0.0:
|
|
49
|
+
return 1.0
|
|
50
|
+
let p = this.elapsed / this.duration
|
|
51
|
+
if p > 1.0: return 1.0
|
|
52
|
+
return p
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
public function time_left() -> float:
|
|
56
|
+
let t = this.duration - this.elapsed
|
|
57
|
+
if t < 0.0: return 0.0
|
|
58
|
+
return t
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
public editable function reset() -> void:
|
|
62
|
+
this.elapsed = 0.0
|
|
63
|
+
this.active = true
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
public editable function restart(duration: float) -> void:
|
|
67
|
+
this.duration = duration
|
|
68
|
+
this.elapsed = 0.0
|
|
69
|
+
this.active = true
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
public editable function stop() -> void:
|
|
73
|
+
this.active = false
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
public editable function pause() -> void:
|
|
77
|
+
this.active = false
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
public editable function resume() -> void:
|
|
81
|
+
this.active = true
|
data/std/tween.mt
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
## Tweening and easing — smooth value interpolation.
|
|
2
|
+
##
|
|
3
|
+
## Normalized easing functions map [0,1] linear progress to
|
|
4
|
+
## eased progress, following the Robert Penner convention.
|
|
5
|
+
## A Tween struct tracks elapsed time and computes the
|
|
6
|
+
## current interpolated value.
|
|
7
|
+
##
|
|
8
|
+
## import std.tween as tw
|
|
9
|
+
## var t = tw.Tween.create(0.0, 100.0, 2.0, tw.Easing.ease_out_cubic)
|
|
10
|
+
## while t.active:
|
|
11
|
+
## let v = t.value()
|
|
12
|
+
## apply_position(v)
|
|
13
|
+
## t.step(dt)
|
|
14
|
+
|
|
15
|
+
import std.math as math
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
public enum Easing: ubyte
|
|
19
|
+
linear = 0
|
|
20
|
+
ease_in_quad = 1
|
|
21
|
+
ease_out_quad = 2
|
|
22
|
+
ease_in_out_quad = 3
|
|
23
|
+
ease_in_cubic = 4
|
|
24
|
+
ease_out_cubic = 5
|
|
25
|
+
ease_in_out_cubic = 6
|
|
26
|
+
ease_in_quart = 7
|
|
27
|
+
ease_out_quart = 8
|
|
28
|
+
ease_in_out_quart = 9
|
|
29
|
+
ease_in_quint = 10
|
|
30
|
+
ease_out_quint = 11
|
|
31
|
+
ease_in_out_quint = 12
|
|
32
|
+
ease_in_sine = 13
|
|
33
|
+
ease_out_sine = 14
|
|
34
|
+
ease_in_out_sine = 15
|
|
35
|
+
ease_in_expo = 17
|
|
36
|
+
ease_out_expo = 18
|
|
37
|
+
ease_in_out_expo = 19
|
|
38
|
+
ease_in_circ = 20
|
|
39
|
+
ease_out_circ = 21
|
|
40
|
+
ease_in_out_circ = 22
|
|
41
|
+
ease_in_back = 23
|
|
42
|
+
ease_out_back = 24
|
|
43
|
+
ease_in_out_back = 25
|
|
44
|
+
ease_in_elastic = 26
|
|
45
|
+
ease_out_elastic = 27
|
|
46
|
+
ease_in_out_elastic = 28
|
|
47
|
+
ease_in_bounce = 29
|
|
48
|
+
ease_out_bounce = 30
|
|
49
|
+
ease_in_out_bounce = 31
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
public struct Tween:
|
|
53
|
+
duration: float
|
|
54
|
+
elapsed: float
|
|
55
|
+
from: float
|
|
56
|
+
to: float
|
|
57
|
+
easing: Easing
|
|
58
|
+
active: bool
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# ── math helpers ──
|
|
62
|
+
|
|
63
|
+
function pow_f(base: float, exp: float) -> float:
|
|
64
|
+
return float<-(math.pow(double<-(base), double<-(exp)))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
function sin_f(x: float) -> float:
|
|
68
|
+
return float<-(math.sin(double<-(x)))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
function cos_f(x: float) -> float:
|
|
72
|
+
return float<-(math.cos(double<-(x)))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
function sqrt_f(x: float) -> float:
|
|
76
|
+
return float<-(math.sqrt(double<-(x)))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
function ease_out_bounce_f(t: float) -> float:
|
|
80
|
+
let n1 = 7.5625
|
|
81
|
+
let d1 = 2.75
|
|
82
|
+
if t < 1.0 / d1:
|
|
83
|
+
return n1 * t * t
|
|
84
|
+
if t < 2.0 / d1:
|
|
85
|
+
let t1 = t - 1.5 / d1
|
|
86
|
+
return n1 * t1 * t1 + 0.75
|
|
87
|
+
if t < 2.5 / d1:
|
|
88
|
+
let t1 = t - 2.25 / d1
|
|
89
|
+
return n1 * t1 * t1 + 0.9375
|
|
90
|
+
let t1 = t - 2.625 / d1
|
|
91
|
+
return n1 * t1 * t1 + 0.984375
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# ── tween ──
|
|
95
|
+
|
|
96
|
+
extending Tween:
|
|
97
|
+
public static function apply_easing(easing: Easing, t: float) -> float:
|
|
98
|
+
if easing == Easing.linear:
|
|
99
|
+
return t
|
|
100
|
+
|
|
101
|
+
if easing == Easing.ease_in_quad:
|
|
102
|
+
return t * t
|
|
103
|
+
if easing == Easing.ease_out_quad:
|
|
104
|
+
return t * (2.0 - t)
|
|
105
|
+
if easing == Easing.ease_in_out_quad:
|
|
106
|
+
if t < 0.5:
|
|
107
|
+
return 2.0 * t * t
|
|
108
|
+
return -1.0 + (4.0 - 2.0 * t) * t
|
|
109
|
+
|
|
110
|
+
if easing == Easing.ease_in_cubic:
|
|
111
|
+
return t * t * t
|
|
112
|
+
if easing == Easing.ease_out_cubic:
|
|
113
|
+
let t1 = t - 1.0
|
|
114
|
+
return t1 * t1 * t1 + 1.0
|
|
115
|
+
if easing == Easing.ease_in_out_cubic:
|
|
116
|
+
if t < 0.5:
|
|
117
|
+
return 4.0 * t * t * t
|
|
118
|
+
let t1 = -2.0 * t + 2.0
|
|
119
|
+
return 1.0 - t1 * t1 * t1 / 2.0
|
|
120
|
+
|
|
121
|
+
if easing == Easing.ease_in_quart:
|
|
122
|
+
return t * t * t * t
|
|
123
|
+
if easing == Easing.ease_out_quart:
|
|
124
|
+
let t1 = t - 1.0
|
|
125
|
+
return 1.0 - t1 * t1 * t1 * t1
|
|
126
|
+
if easing == Easing.ease_in_out_quart:
|
|
127
|
+
if t < 0.5:
|
|
128
|
+
return 8.0 * t * t * t * t
|
|
129
|
+
let t1 = t - 1.0
|
|
130
|
+
return 1.0 - 8.0 * t1 * t1 * t1 * t1
|
|
131
|
+
|
|
132
|
+
if easing == Easing.ease_in_quint:
|
|
133
|
+
return t * t * t * t * t
|
|
134
|
+
if easing == Easing.ease_out_quint:
|
|
135
|
+
let t1 = t - 1.0
|
|
136
|
+
return 1.0 + t1 * t1 * t1 * t1 * t1
|
|
137
|
+
if easing == Easing.ease_in_out_quint:
|
|
138
|
+
if t < 0.5:
|
|
139
|
+
return 16.0 * t * t * t * t * t
|
|
140
|
+
let t1 = -2.0 * t + 2.0
|
|
141
|
+
return 1.0 - t1 * t1 * t1 * t1 * t1 / 2.0
|
|
142
|
+
|
|
143
|
+
if easing == Easing.ease_in_sine:
|
|
144
|
+
return 1.0 - cos_f(t * 1.5707963)
|
|
145
|
+
if easing == Easing.ease_out_sine:
|
|
146
|
+
return sin_f(t * 1.5707963)
|
|
147
|
+
if easing == Easing.ease_in_out_sine:
|
|
148
|
+
return -(cos_f(3.14159265 * t) - 1.0) / 2.0
|
|
149
|
+
|
|
150
|
+
if easing == Easing.ease_in_expo:
|
|
151
|
+
if t <= 0.0: return 0.0
|
|
152
|
+
return pow_f(2.0, 10.0 * (t - 1.0))
|
|
153
|
+
if easing == Easing.ease_out_expo:
|
|
154
|
+
if t >= 1.0: return 1.0
|
|
155
|
+
return 1.0 - pow_f(2.0, -10.0 * t)
|
|
156
|
+
if easing == Easing.ease_in_out_expo:
|
|
157
|
+
if t <= 0.0: return 0.0
|
|
158
|
+
if t >= 1.0: return 1.0
|
|
159
|
+
if t < 0.5:
|
|
160
|
+
return pow_f(2.0, 20.0 * t - 10.0) / 2.0
|
|
161
|
+
return (2.0 - pow_f(2.0, -20.0 * t + 10.0)) / 2.0
|
|
162
|
+
|
|
163
|
+
if easing == Easing.ease_in_circ:
|
|
164
|
+
return 1.0 - sqrt_f(1.0 - t * t)
|
|
165
|
+
if easing == Easing.ease_out_circ:
|
|
166
|
+
return sqrt_f(1.0 - (t - 1.0) * (t - 1.0))
|
|
167
|
+
if easing == Easing.ease_in_out_circ:
|
|
168
|
+
if t < 0.5:
|
|
169
|
+
return (1.0 - sqrt_f(1.0 - 4.0 * t * t)) / 2.0
|
|
170
|
+
return (sqrt_f(1.0 - (-2.0 * t + 2.0) * (-2.0 * t + 2.0)) + 1.0) / 2.0
|
|
171
|
+
|
|
172
|
+
if easing == Easing.ease_in_back:
|
|
173
|
+
let c1 = 1.70158
|
|
174
|
+
return (c1 + 1.0) * t * t * t - c1 * t * t
|
|
175
|
+
if easing == Easing.ease_out_back:
|
|
176
|
+
let c1 = 1.70158
|
|
177
|
+
let t1 = t - 1.0
|
|
178
|
+
return 1.0 + (c1 + 1.0) * t1 * t1 * t1 + c1 * t1 * t1
|
|
179
|
+
if easing == Easing.ease_in_out_back:
|
|
180
|
+
let c1 = 1.70158
|
|
181
|
+
let c2 = c1 * 1.525
|
|
182
|
+
if t < 0.5:
|
|
183
|
+
return (4.0 * t * t * ((c2 + 1.0) * 2.0 * t - c2)) / 2.0
|
|
184
|
+
let t1 = t - 1.0
|
|
185
|
+
return (4.0 * t1 * t1 * ((c2 + 1.0) * 2.0 * t1 + c2) + 2.0) / 2.0
|
|
186
|
+
|
|
187
|
+
if easing == Easing.ease_in_elastic:
|
|
188
|
+
if t <= 0.0: return 0.0
|
|
189
|
+
if t >= 1.0: return 1.0
|
|
190
|
+
return -pow_f(2.0, 10.0 * t - 10.0) * sin_f((t * 10.0 - 10.75) * 2.0943951)
|
|
191
|
+
if easing == Easing.ease_out_elastic:
|
|
192
|
+
if t <= 0.0: return 0.0
|
|
193
|
+
if t >= 1.0: return 1.0
|
|
194
|
+
return pow_f(2.0, -10.0 * t) * sin_f((t * 10.0 - 0.75) * 2.0943951) + 1.0
|
|
195
|
+
if easing == Easing.ease_in_out_elastic:
|
|
196
|
+
if t <= 0.0: return 0.0
|
|
197
|
+
if t >= 1.0: return 1.0
|
|
198
|
+
if t < 0.5:
|
|
199
|
+
return -(pow_f(2.0, 20.0 * t - 10.0) * sin_f((20.0 * t - 11.125) * 1.3962634)) / 2.0
|
|
200
|
+
return (pow_f(2.0, -20.0 * t + 10.0) * sin_f((20.0 * t - 11.125) * 1.3962634)) / 2.0 + 1.0
|
|
201
|
+
|
|
202
|
+
if easing == Easing.ease_in_bounce:
|
|
203
|
+
return 1.0 - ease_out_bounce_f(1.0 - t)
|
|
204
|
+
if easing == Easing.ease_out_bounce:
|
|
205
|
+
return ease_out_bounce_f(t)
|
|
206
|
+
if easing == Easing.ease_in_out_bounce:
|
|
207
|
+
if t < 0.5:
|
|
208
|
+
return (1.0 - ease_out_bounce_f(1.0 - 2.0 * t)) / 2.0
|
|
209
|
+
return (1.0 + ease_out_bounce_f(2.0 * t - 1.0)) / 2.0
|
|
210
|
+
|
|
211
|
+
return t
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
public static function create(from: float, to: float, duration: float, easing: Easing) -> Tween:
|
|
215
|
+
return Tween(
|
|
216
|
+
duration = duration,
|
|
217
|
+
elapsed = 0.0,
|
|
218
|
+
from = from,
|
|
219
|
+
to = to,
|
|
220
|
+
easing = easing,
|
|
221
|
+
active = true
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
public function value() -> float:
|
|
226
|
+
if this.duration <= 0.0:
|
|
227
|
+
return this.to
|
|
228
|
+
let progress = this.elapsed / this.duration
|
|
229
|
+
if progress >= 1.0:
|
|
230
|
+
return this.to
|
|
231
|
+
if progress <= 0.0:
|
|
232
|
+
return this.from
|
|
233
|
+
let eased = Tween.apply_easing(this.easing, progress)
|
|
234
|
+
return this.from + (this.to - this.from) * eased
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
public editable function step(dt: float) -> bool:
|
|
238
|
+
if not this.active:
|
|
239
|
+
return false
|
|
240
|
+
this.elapsed = this.elapsed + dt
|
|
241
|
+
if this.elapsed >= this.duration:
|
|
242
|
+
this.elapsed = this.duration
|
|
243
|
+
this.active = false
|
|
244
|
+
return true
|
|
245
|
+
return false
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
public editable function reset(from: float, to: float, duration: float, easing: Easing) -> void:
|
|
249
|
+
this.from = from
|
|
250
|
+
this.to = to
|
|
251
|
+
this.duration = duration
|
|
252
|
+
this.easing = easing
|
|
253
|
+
this.elapsed = 0.0
|
|
254
|
+
this.active = true
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
public editable function stop() -> void:
|
|
258
|
+
this.active = false
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
# ── multi-type tweens ──
|
|
262
|
+
|
|
263
|
+
public struct Tween2:
|
|
264
|
+
x: Tween
|
|
265
|
+
y: Tween
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
public struct Tween3:
|
|
269
|
+
x: Tween
|
|
270
|
+
y: Tween
|
|
271
|
+
z: Tween
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
public struct Tween4:
|
|
275
|
+
x: Tween
|
|
276
|
+
y: Tween
|
|
277
|
+
z: Tween
|
|
278
|
+
w: Tween
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
extending Tween2:
|
|
282
|
+
public static function create(from: vec2, to: vec2, duration: float, easing: Easing) -> Tween2:
|
|
283
|
+
return Tween2(
|
|
284
|
+
x = Tween.create(from.x, to.x, duration, easing),
|
|
285
|
+
y = Tween.create(from.y, to.y, duration, easing)
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
public function value() -> vec2:
|
|
290
|
+
return vec2(x = this.x.value(), y = this.y.value())
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
public editable function step(dt: float) -> bool:
|
|
294
|
+
let done_x = this.x.step(dt)
|
|
295
|
+
let done_y = this.y.step(dt)
|
|
296
|
+
return done_x or done_y
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
public editable function reset(from: vec2, to: vec2, duration: float, easing: Easing) -> void:
|
|
300
|
+
this.x.reset(from.x, to.x, duration, easing)
|
|
301
|
+
this.y.reset(from.y, to.y, duration, easing)
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
public editable function stop() -> void:
|
|
305
|
+
this.x.stop()
|
|
306
|
+
this.y.stop()
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
extending Tween3:
|
|
310
|
+
public static function create(from: vec3, to: vec3, duration: float, easing: Easing) -> Tween3:
|
|
311
|
+
return Tween3(
|
|
312
|
+
x = Tween.create(from.x, to.x, duration, easing),
|
|
313
|
+
y = Tween.create(from.y, to.y, duration, easing),
|
|
314
|
+
z = Tween.create(from.z, to.z, duration, easing)
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
public function value() -> vec3:
|
|
319
|
+
return vec3(x = this.x.value(), y = this.y.value(), z = this.z.value())
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
public editable function step(dt: float) -> bool:
|
|
323
|
+
let dx = this.x.step(dt)
|
|
324
|
+
let dy = this.y.step(dt)
|
|
325
|
+
let dz = this.z.step(dt)
|
|
326
|
+
return dx or dy or dz
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
public editable function reset(from: vec3, to: vec3, duration: float, easing: Easing) -> void:
|
|
330
|
+
this.x.reset(from.x, to.x, duration, easing)
|
|
331
|
+
this.y.reset(from.y, to.y, duration, easing)
|
|
332
|
+
this.z.reset(from.z, to.z, duration, easing)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
public editable function stop() -> void:
|
|
336
|
+
this.x.stop()
|
|
337
|
+
this.y.stop()
|
|
338
|
+
this.z.stop()
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
extending Tween4:
|
|
342
|
+
public static function create(from: vec4, to: vec4, duration: float, easing: Easing) -> Tween4:
|
|
343
|
+
return Tween4(
|
|
344
|
+
x = Tween.create(from.x, to.x, duration, easing),
|
|
345
|
+
y = Tween.create(from.y, to.y, duration, easing),
|
|
346
|
+
z = Tween.create(from.z, to.z, duration, easing),
|
|
347
|
+
w = Tween.create(from.w, to.w, duration, easing)
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
public function value() -> vec4:
|
|
352
|
+
return vec4(x = this.x.value(), y = this.y.value(), z = this.z.value(), w = this.w.value())
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
public editable function step(dt: float) -> bool:
|
|
356
|
+
let dx = this.x.step(dt)
|
|
357
|
+
let dy = this.y.step(dt)
|
|
358
|
+
let dz = this.z.step(dt)
|
|
359
|
+
let dw = this.w.step(dt)
|
|
360
|
+
return dx or dy or dz or dw
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
public editable function reset(from: vec4, to: vec4, duration: float, easing: Easing) -> void:
|
|
364
|
+
this.x.reset(from.x, to.x, duration, easing)
|
|
365
|
+
this.y.reset(from.y, to.y, duration, easing)
|
|
366
|
+
this.z.reset(from.z, to.z, duration, easing)
|
|
367
|
+
this.w.reset(from.w, to.w, duration, easing)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
public editable function stop() -> void:
|
|
371
|
+
this.x.stop()
|
|
372
|
+
this.y.stop()
|
|
373
|
+
this.z.stop()
|
|
374
|
+
this.w.stop()
|