test: cover native material interpolation masks
Docs Deploy / Build and Deploy MkDocs (push) Successful in 34s

This commit is contained in:
Valentin Popov committed 2026-10-18 00:26:25 +04:00
1 parent 36fe4449f1
commit d30dfb58fd
1 file changed
+57
+57
View File
@@ -717,6 +717,10 @@ fn interpolate_coefficients(
mask: u32, mask: u32,
fraction: f32, fraction: f32,
) -> MaterialCoefficients { ) -> MaterialCoefficients {
// World3D 0x3030 receives source and destination wrappers one dword before
// each D3DMATERIAL7 body. Its +4/+14/+24/+34 offsets therefore select
// parameters 4..6, 0..2, 8..10, and 12..14; +0x20 selects parameter 3.
// The other alpha/extra fields, power, and page remain from the left phase.
let left = left.coefficients(); let left = left.coefficients();
let right = right.coefficients(); let right = right.coefficients();
let mut output = left; let mut output = left;
@@ -1305,6 +1309,59 @@ mod tests {
assert_eq!(&wrapped.texture_raw[..4], b"LEFT"); assert_eq!(&wrapped.texture_raw[..4], b"LEFT");
} }
#[test]
fn material_animation_interpolation_masks_match_native_rebased_offsets() {
let left = phase_with_parameters(
[
10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180,
],
b"LEFT",
);
let right = phase_with_parameters(
[
70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230,
240,
],
b"RIGHT",
);
let rgb = |first: u8| [first, first + 10, first + 20].map(|value| f32::from(value) / 255.0);
let cases = [
(0, rgb(10), rgb(50), rgb(90), rgb(130), 0.4),
(1, rgb(40), rgb(50), rgb(90), rgb(130), 0.4),
(2, rgb(10), rgb(80), rgb(90), rgb(130), 0.4),
(4, rgb(10), rgb(50), rgb(120), rgb(130), 0.4),
(8, rgb(10), rgb(50), rgb(90), rgb(160), 0.4),
(16, rgb(10), rgb(50), rgb(90), rgb(130), 0.7),
(0x1f, rgb(40), rgb(80), rgb(120), rgb(160), 0.7),
];
for (mask, additive, directional, specular, extra, opacity) in cases {
let output = interpolate_coefficients(&left, &right, mask, 0.5);
for (actual, expected) in [
(output.additive_rgb, additive),
(output.directional_rgb, directional),
(output.specular_rgb, specular),
(output.extra_rgb, extra),
] {
for channel in 0..3 {
assert!(
(actual[channel] - expected[channel]).abs() < 1e-6,
"mask {mask:#x}, channel {channel}: got {}, expected {}",
actual[channel],
expected[channel]
);
}
}
assert!((output.opacity - opacity).abs() < 1e-6, "mask {mask:#x}");
assert_eq!(output.directional_extra, 80.0 / 255.0);
assert_eq!(output.specular_extra, 120.0 / 255.0);
assert_eq!(output.extra_alpha, 160.0 / 255.0);
assert_eq!(output.power, 170);
assert_eq!(output.page_index, -76);
}
}
#[test] #[test]
fn material_ping_pong_reverses_local_time_and_clamp_holds_last_phase() { fn material_ping_pong_reverses_local_time_and_clamp_holds_last_phase() {
let phases = vec![ let phases = vec![