mod cpu {
use std::collections::BTreeMap;
use wavyte::{
Anim, Asset, BackendKind, BlendMode, Canvas, Clip, ClipProps, Composition, FrameIndex,
FrameRange, PathAsset, PreparedAssetStore, RenderSettings, Track, Transform2D,
create_backend, render_frame,
};
fn mix64(mut z: u64) -> u64 {
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^ (z >> 31)
}
fn digest_u64(bytes: &[u8]) -> u64 {
let mut state = 0x9E37_79B9_7F4A_7C15u64;
for chunk in bytes.chunks(8) {
let mut v = 0u64;
for (i, &b) in chunk.iter().enumerate() {
v |= (b as u64) << (i * 8);
}
state = mix64(state ^ v);
}
state
}
fn store_for(comp: &Composition) -> PreparedAssetStore {
PreparedAssetStore::prepare(comp, ".").unwrap()
}
fn simple_path_comp() -> Composition {
let mut assets = BTreeMap::new();
assets.insert(
"p0".to_string(),
Asset::Path(PathAsset {
svg_path_d: "M10,10 L54,10 L54,54 L10,54 Z".to_string(),
}),
);
Composition {
fps: wavyte::Fps::new(30, 1).unwrap(),
canvas: Canvas {
width: 64,
height: 64,
},
duration: FrameIndex(1),
assets,
tracks: vec![Track {
name: "main".to_string(),
z_base: 0,
layout_mode: wavyte::LayoutMode::Absolute,
layout_gap_px: 0.0,
layout_padding: wavyte::Edges::default(),
layout_align_x: wavyte::LayoutAlignX::Start,
layout_align_y: wavyte::LayoutAlignY::Start,
layout_grid_columns: 2,
clips: vec![Clip {
id: "c0".to_string(),
asset: "p0".to_string(),
range: FrameRange::new(FrameIndex(0), FrameIndex(1)).unwrap(),
props: ClipProps {
transform: Anim::constant(Transform2D::default()),
opacity: Anim::constant(1.0),
blend: BlendMode::Normal,
},
z_offset: 0,
effects: vec![],
transition_in: None,
transition_out: None,
}],
}],
seed: 1,
}
}
fn two_layer_path_comp() -> Composition {
let mut assets = BTreeMap::new();
assets.insert(
"p0".to_string(),
Asset::Path(PathAsset {
svg_path_d: "M0,0 L64,0 L64,64 L0,64 Z".to_string(),
}),
);
assets.insert(
"p1".to_string(),
Asset::Path(PathAsset {
svg_path_d: "M16,16 L48,16 L48,48 L16,48 Z".to_string(),
}),
);
Composition {
fps: wavyte::Fps::new(30, 1).unwrap(),
canvas: Canvas {
width: 64,
height: 64,
},
duration: FrameIndex(1),
assets,
tracks: vec![
Track {
name: "bg".to_string(),
z_base: 0,
layout_mode: wavyte::LayoutMode::Absolute,
layout_gap_px: 0.0,
layout_padding: wavyte::Edges::default(),
layout_align_x: wavyte::LayoutAlignX::Start,
layout_align_y: wavyte::LayoutAlignY::Start,
layout_grid_columns: 2,
clips: vec![Clip {
id: "c0".to_string(),
asset: "p0".to_string(),
range: FrameRange::new(FrameIndex(0), FrameIndex(1)).unwrap(),
props: ClipProps {
transform: Anim::constant(Transform2D::default()),
opacity: Anim::constant(1.0),
blend: BlendMode::Normal,
},
z_offset: 0,
effects: vec![],
transition_in: None,
transition_out: None,
}],
},
Track {
name: "fg".to_string(),
z_base: 1,
layout_mode: wavyte::LayoutMode::Absolute,
layout_gap_px: 0.0,
layout_padding: wavyte::Edges::default(),
layout_align_x: wavyte::LayoutAlignX::Start,
layout_align_y: wavyte::LayoutAlignY::Start,
layout_grid_columns: 2,
clips: vec![Clip {
id: "c1".to_string(),
asset: "p1".to_string(),
range: FrameRange::new(FrameIndex(0), FrameIndex(1)).unwrap(),
props: ClipProps {
transform: Anim::constant(Transform2D::default()),
opacity: Anim::constant(1.0),
blend: BlendMode::Normal,
},
z_offset: 0,
effects: vec![],
transition_in: None,
transition_out: None,
}],
},
],
seed: 1,
}
}
#[test]
fn cpu_render_is_deterministic_and_nonempty() {
let comp = simple_path_comp();
let settings = RenderSettings {
clear_rgba: Some([0, 0, 0, 255]),
};
let mut backend = create_backend(BackendKind::Cpu, &settings).unwrap();
let assets = store_for(&comp);
let a = render_frame(&comp, FrameIndex(0), backend.as_mut(), &assets).unwrap();
let b = render_frame(&comp, FrameIndex(0), backend.as_mut(), &assets).unwrap();
assert_eq!(a.width, 64);
assert_eq!(a.height, 64);
assert!(a.premultiplied);
assert_eq!(digest_u64(&a.data), digest_u64(&b.data));
assert!(a.data.iter().any(|&x| x != 0));
}
#[test]
fn cpu_render_two_layers_is_nonempty() {
let comp = two_layer_path_comp();
let settings = RenderSettings {
clear_rgba: Some([0, 0, 0, 255]),
};
let mut backend = create_backend(BackendKind::Cpu, &settings).unwrap();
let assets = store_for(&comp);
let frame = render_frame(&comp, FrameIndex(0), backend.as_mut(), &assets).unwrap();
assert_eq!(frame.width, 64);
assert_eq!(frame.height, 64);
assert!(frame.premultiplied);
assert!(frame.data.iter().any(|&x| x != 0));
}
}