From 18f1e20aa12f709956b56039285f0843b427449a Mon Sep 17 00:00:00 2001 From: ashley Date: Sun, 22 Oct 2023 13:10:01 -0400 Subject: [PATCH] Convert 16.16 fixed point curve export to fractional x/128 export --- src/reskit/easing.rs | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/reskit/easing.rs b/src/reskit/easing.rs index b756085..eb83a4f 100644 --- a/src/reskit/easing.rs +++ b/src/reskit/easing.rs @@ -1,6 +1,4 @@ use std::error::Error; -use fixed::FixedI32; -use fixed::types::extra::U16; use flo_curves::*; use flo_curves::{bezier, Coord2}; @@ -14,20 +12,19 @@ easing function is cubic bezier going from 0.0 to 1.0 140-120=20 increments 0.0 is +0 and 1.0 is +20 -so e.g. if you read a 0.5 at the given increment it's 0.5 * 20 = +10 -curves are exported from reskit sampled at 1/60 increments -reskit accepts arguments for control points and exports 16.16 fixed point binary files -so a 1 second animation is 60 increments, 2 seconds is 120, etc. - -each iteration be like: -1. take cubic bezier sample and post increment -2. the value at this iteration is (final - beginning) * sample - a. so example (140-120)*0.5 for a linear curve sampled right in the middle -3. round the value to the nearest whole integer -4. do not go back to 1 if we exhausted the curve - -need fixed point arithmetic multiplication +console has no floating point and fixed point will overflow 16-bit +each curve tailored for use case. for camera motion: +- generate the cubic bezier easing curve in my custom branch of reskit, converting 0.0-1.0 floating point spans to x/128 fractions equivalent to x/100 fractions. + literal grade school shit i realised i wasted a weekend re-deriving from first principles. these fparts even export as single bytes, so that's 3 less bytes per point + on the curve than if i were sticking with 16.16 fix. for a 1 second animation, 60 points are taken on the 0.0-1.0 curve, for a 2 second animation, 120 points are taken, etc. + equivalent PAL framerate curves can be export in the same curve file. +- the camera animates moves by setting a new destination point and performing interpolation of intermediate positions along the curve - just like css easing functions, or + unity/unreal bezier curves. you restrict camera new position to +/- powers of two in any axis to eliminate mul[s/u].w. e.g. camera moves +2, +4, +8.... in the x direction. +- for each axis, new position - current position = span of movement. so if you're starting at x = 30 and moving to x = 46, you're going +16 in the x direction +- while the camera is animating, interpolate positions by reading the fractional on the curve for the current frame and doing fractional * span / 128. since new camera positions + in any axis are kept power of two this can all be done using asl/asr. take the remainder with the and 2^127 trick and bump the resulting value up 1 if the modulo is >= 64 +- ✨ cubic bezier animated camera motion */ @@ -48,15 +45,20 @@ pub fn get_cubic_bezier( p0: (f64, f64), c0: (f64, f64), c1: (f64, f64), p1: (f6 ); let mut current_jiffy = 0.0; - // (jiffies) of 16.16 fixed point integers: Each point in the curve at the given frame + // For each point in curve: 1 byte fractional point in the curve at the given frame for i in 0..jiffies { let point = curve.point_at_pos( current_jiffy ); let x = point.1; - print_info( &format!( "at iteration {}, curve is {:?}, 16.16 format will be {}", i, point, x ) ); + + // Round and convert x to n/100 fraction, then equivalent n/128 fraction + let x = ( ( x * 100.0 ).round() / 100.0 ) * 100.0; // only get last two decimal places, then convert to whole number + let x = x * 128.0 / 100.0; // x / 100 = y / 128 + let x = x.round() as u8; + + print_info( &format!( "at iteration {}, curve is {:?}, fractional format will be {}", i, point, x ) ); current_jiffy += 1.0 / jiffies as f64; - let as_fixed = FixedI32::::from_num( x ); - result.extend( as_fixed.to_be_bytes() ); + result.push( x ); } Ok( result )