Easing function tool
parent
1ae417af5c
commit
9e1014bbd9
|
@ -20,3 +20,5 @@ convert_case = "0.6.0"
|
||||||
roxmltree = "0.18.0"
|
roxmltree = "0.18.0"
|
||||||
regex = "1.9.5"
|
regex = "1.9.5"
|
||||||
euclid = "0.22.9"
|
euclid = "0.22.9"
|
||||||
|
flo_curves = "0.7.2"
|
||||||
|
fixed = "1.24.0"
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{error::Error, fs::File, io::Write, path::Path, collections::HashMap};
|
use std::{error::Error, fs::File, io::Write, path::Path, collections::HashMap};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use crate::reskit::{tileset, soundtrack::{formats::dmf::DmfModule, engines::echo::engine::{EchoFormat, EchoArtifact}}, utility::print_good, level::{converter::get_tiled_tilemap, system::{get_tiles, get_code, get_tilemap, get_collision_map, get_objs, get_sprites}}};
|
use crate::reskit::{tileset, soundtrack::{formats::dmf::DmfModule, engines::echo::engine::{EchoFormat, EchoArtifact}}, utility::print_good, level::{converter::get_tiled_tilemap, system::{get_tiles, get_code, get_tilemap, get_collision_map, get_objs, get_sprites}}, easing::get_cubic_bezier};
|
||||||
use super::settings::{Args, Tools, TileOutputFormat, TileOrder};
|
use super::settings::{Args, Tools, TileOutputFormat, TileOrder};
|
||||||
|
|
||||||
pub fn run_command() -> Result<(), Box<dyn Error>> {
|
pub fn run_command() -> Result<(), Box<dyn Error>> {
|
||||||
|
@ -129,6 +129,25 @@ pub fn run_command() -> Result<(), Box<dyn Error>> {
|
||||||
code_asm.write_all( &get_code( &tiled_file, "testlevel", "levels/" )?.as_bytes() )?;
|
code_asm.write_all( &get_code( &tiled_file, "testlevel", "levels/" )?.as_bytes() )?;
|
||||||
print_good( "exported level.asm" );
|
print_good( "exported level.asm" );
|
||||||
}
|
}
|
||||||
|
Tools::Easing { output_directory, interval, point_1, point_2 } => {
|
||||||
|
let cp1: Vec<&str> = point_1.split( "," ).collect();
|
||||||
|
if cp1.len() != 2 {
|
||||||
|
return Err( format!( "invalid format for point_1: {}", point_1 ) )?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ( cp1_x, cp1_y ): ( f64, f64 ) = ( cp1[ 0 ].parse()?, cp1[ 1 ].parse()? );
|
||||||
|
|
||||||
|
let cp2: Vec<&str> = point_1.split( "," ).collect();
|
||||||
|
if cp2.len() != 2 {
|
||||||
|
return Err( format!( "invalid format for point_2: {}", point_2 ) )?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ( cp2_x, cp2_y ): ( f64, f64 ) = ( cp2[ 0 ].parse()?, cp2[ 1 ].parse()? );
|
||||||
|
|
||||||
|
let mut easing = File::create( format!( "{}curve.bin", output_directory ) )?;
|
||||||
|
easing.write_all( &get_cubic_bezier( ( 0.0, 0.0 ), ( cp1_x, cp1_y ), ( cp2_x, cp2_y ), ( 1.0, 1.0 ), interval )? )?;
|
||||||
|
print_good( "exported curve.bin" );
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok( () )
|
Ok( () )
|
||||||
|
|
|
@ -124,5 +124,27 @@ pub enum Tools {
|
||||||
/// Console system type
|
/// Console system type
|
||||||
#[arg(short, long, value_enum, default_value_t=SystemType::Md)]
|
#[arg(short, long, value_enum, default_value_t=SystemType::Md)]
|
||||||
console: SystemType
|
console: SystemType
|
||||||
|
},
|
||||||
|
|
||||||
|
#[command(name = "easing")]
|
||||||
|
#[command(about = "Generate an easing curve given a time interval and control points.")]
|
||||||
|
Easing {
|
||||||
|
|
||||||
|
/// Output directory for artifacts
|
||||||
|
#[arg(short, long, default_value_t=String::from("./"))]
|
||||||
|
output_directory: String,
|
||||||
|
|
||||||
|
/// Time span of the easing curve (in 1/60 s increments)
|
||||||
|
#[arg(short,long)]
|
||||||
|
interval: u16,
|
||||||
|
|
||||||
|
/// First control point of the cubic bezier (format: <x>,<y>)
|
||||||
|
#[arg(long)]
|
||||||
|
point_1: String,
|
||||||
|
|
||||||
|
/// Second control point of the cubic bezier (format: <x>,<y>)
|
||||||
|
#[arg(long)]
|
||||||
|
point_2: String
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
use std::error::Error;
|
||||||
|
use fixed::FixedI32;
|
||||||
|
use fixed::types::extra::U16;
|
||||||
|
use flo_curves::*;
|
||||||
|
use flo_curves::{bezier, Coord2};
|
||||||
|
|
||||||
|
use super::utility::print_info;
|
||||||
|
|
||||||
|
/*
|
||||||
|
stinkhead7ds easing curve description:
|
||||||
|
|
||||||
|
e.g. going from 120 to 140
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output a binary for a cubic bezier defined by the given four points and the
|
||||||
|
* time interval defined as number of 1/60 jiffies.
|
||||||
|
*/
|
||||||
|
pub fn get_cubic_bezier( p0: (f64, f64), c0: (f64, f64), c1: (f64, f64), p1: (f64, f64), jiffies: u16 ) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
|
let mut result: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
|
// 2 bytes: Number of frames this curve spans
|
||||||
|
result.extend( jiffies.to_be_bytes() );
|
||||||
|
|
||||||
|
let curve = bezier::Curve::from_points(
|
||||||
|
Coord2( p0.0, p0.1 ),
|
||||||
|
( Coord2( c0.0, c0.1 ), Coord2( c1.0, c1.1 ) ),
|
||||||
|
Coord2( p1.0, p1.1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut current_jiffy = 0.0;
|
||||||
|
// (jiffies) of 16.16 fixed point integers: Each 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 ) );
|
||||||
|
current_jiffy += 1.0 / jiffies as f64;
|
||||||
|
|
||||||
|
let as_fixed = FixedI32::<U16>::from_num( x );
|
||||||
|
result.extend( as_fixed.to_be_bytes() );
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok( result )
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
|
pub mod easing;
|
||||||
pub mod level;
|
pub mod level;
|
||||||
pub mod soundtrack;
|
pub mod soundtrack;
|
||||||
pub mod tileset;
|
pub mod tileset;
|
||||||
|
|
Loading…
Reference in New Issue