package ntween import "base:intrinsics" import "core:math" import "core:math/ease" import "core:math/linalg" Tween :: struct($T: typeid) where intrinsics.type_is_float(T) || intrinsics.type_is_array(T) { value: ^T, from: T, to: T, time: f32, duration: f32, ease_type: ease.Ease, active: bool, finished: proc(data: rawptr), data: rawptr, } Tween_Map :: struct($T: typeid) { values: map[^T]Tween(T), } init :: proc( $T: typeid, capacity := 8, ) -> Tween_Map(T) where intrinsics.type_is_float(T) || intrinsics.type_is_array(T) { return {values = make_map_cap(map[^T]Tween(T), capacity)} } clear_tweens :: proc(tweens: ^Tween_Map($T)) { clear(&tweens.values) } destroy_tweens :: proc(tweens: ^Tween_Map($T)) { delete_map(tweens.values) } animate :: proc( tweens: ^Tween_Map($T), value: ^T, to: T, duration: f32, ease: ease.Ease = ease.Ease.Quartic_In_Out, data: rawptr = nil, callback: proc(data: rawptr) = nil, ) -> ^Tween(T) { tween: ^Tween(T) if t, ok := &tweens.values[value]; ok { tween = t } else { tweens.values[value] = {} tween = &tweens.values[value] } tween^ = { value = value, from = value^, to = to, duration = duration, ease_type = ease, active = true, data = data, finished = callback, } return tween } cancel :: proc(t: ^Tween($T)) { t.active = false } process :: proc(tweens: ^Tween_Map($T), delta: f32) { for i, &tween in tweens.values { tween.time += delta p := clamp(tween.time / tween.duration, 0, 1) val := ease.ease(tween.ease_type, p) if tween.value != nil { tween.value^ = math.lerp(tween.from, tween.to, val) } else { tween.active = false } if tween.time >= tween.duration { tween.active = false if tween.finished != nil { tween.finished(tween.data) } } if !tween.active { delete_key(&tweens.values, tween.value) } } }