Ease :: enum { linear; quad; cubic; quart; quint; expo; sine; circ; back; elastic; } Transition :: enum { in; out; in_out; } /* Calculate a tween value for the given process, easing function, and transition. The value returned can be used like so: progress := 1.0 / time_in_seconds; current = original + ease(progress, .cubic, .in_out); @Note: Progress must be between 0.0 and 1.0 */ ease :: (progress: $T, $$ease: Ease = .linear, $$transition: Transition = .in) -> T #modify { return meta.type_is_float(T); } { p := progress; #insert -> string { expressions :: string.[ "p", // linear "p * p", // quad "p * p * p", // cubic "p * p * p * p", // quart "p * p * p * p * p", // quint "math.pow(2, (10 * (p - 1)))", // expo "-math.cos(p * (math.PI * 0.5)) + 1", // sine "-(math.sqrt(1 - (p * p)) - 1)", // circ "p * p * (2.7 * p - 1.7)", // back "-math.pow(2, 10 * (p - 1)) * math.sin((p - 1.075) * (math.PI * 2) / 0.3)" // elastic ]; b: basic.String_Builder; if is_constant(ease) basic.append(*b, "#"); basic.append(*b, "if ease == {\n"); info := type_info(Ease); for info.names { basic.print_to_builder(*b, #string END case .%1; %2if transition == { case .in; return %3; case .out; p = 1 - p; return p - (%3); case .in_out; p *= 2; if p < 1 { return 0.5 * (%3); } p = 2 - p; return 0.5 * (1 - (%3)) + 0.5; } END, it, ifx is_constant(transition) "#" else "", expressions[it_index]); } basic.append(*b, "}\n"); return basic.builder_to_string(*b); } return p; } #scope_file; meta :: #import "jc/meta"; math :: #import "Math"; // @future basic :: #import "Basic"; // @future