Convert 16.16 fixed point curve export to fractional x/128 export

stinkhead7ds
Ashley N. 2023-10-22 13:10:01 -04:00
parent 9e1014bbd9
commit 18f1e20aa1
1 changed files with 21 additions and 19 deletions

View File

@ -1,6 +1,4 @@
use std::error::Error; use std::error::Error;
use fixed::FixedI32;
use fixed::types::extra::U16;
use flo_curves::*; use flo_curves::*;
use flo_curves::{bezier, Coord2}; 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 140-120=20 increments
0.0 is +0 and 1.0 is +20 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 console has no floating point and fixed point will overflow 16-bit
reskit accepts arguments for control points and exports 16.16 fixed point binary files each curve tailored for use case. for camera motion:
so a 1 second animation is 60 increments, 2 seconds is 120, etc. - 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
each iteration be like: 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.
1. take cubic bezier sample and post increment equivalent PAL framerate curves can be export in the same curve file.
2. the value at this iteration is (final - beginning) * sample - 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
a. so example (140-120)*0.5 for a linear curve sampled right in the middle 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.
3. round the value to the nearest whole integer - 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
4. do not go back to 1 if we exhausted the curve - 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
need fixed point arithmetic multiplication - 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; 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 { for i in 0..jiffies {
let point = curve.point_at_pos( current_jiffy ); let point = curve.point_at_pos( current_jiffy );
let x = point.1; 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; current_jiffy += 1.0 / jiffies as f64;
let as_fixed = FixedI32::<U16>::from_num( x ); result.push( x );
result.extend( as_fixed.to_be_bytes() );
} }
Ok( result ) Ok( result )