use iridia::flow::Values;
use iridia::matrix::{Unshown, Words, lines};
use iridia::{Majorness, Program, ResourceKind};
fn lines_of(program: &Program, name: &str) -> Result<Majorness, Unshown> {
read(program, name, false)
}
fn palette_lines_of(program: &Program, name: &str) -> Result<Majorness, Unshown> {
read(program, name, true)
}
fn read(program: &Program, name: &str, indexed: bool) -> Result<Majorness, Unshown> {
let values = Values::of_program(program).expect("the value graph");
for r in &program.interface.resources {
let ResourceKind::ConstantBuffer { layout } = &r.kind else {
continue;
};
if let Some(c) = layout.constants.iter().find(|c| c.name == name) {
let size = c.ty.size().expect("a sized constant");
let words = if indexed {
Words::Indexed
} else {
Words::At(c.offset / 4..(c.offset + size).div_ceil(4))
};
return lines(&values, r.id, &words);
}
}
panic!("no constant {name}")
}
fn dxbc(bytes: &[u8]) -> Program {
iridia_dxbc::lift(bytes).expect("fxc's program lifts")
}
fn dxil(bytes: &[u8]) -> Program {
iridia_dxil::lift(bytes).expect("dxc's program lifts")
}
const SINGLE_UV_VS: &[u8] = include_bytes!("fixtures/single_uv_vs.dxbc");
const SKIN_VS: &[u8] = include_bytes!("fixtures/layered_skin_vs.dxbc");
#[test]
fn a_matrix_applied_to_a_column_vector_is_read_by_columns() {
let single = dxbc(SINGLE_UV_VS);
assert_eq!(lines_of(&single, "VC_MatrixViewProj"), Ok(Majorness::Column));
let skin = dxbc(SKIN_VS);
for name in ["VC_MatrixViewProj", "FC_MatrixView"] {
assert_eq!(lines_of(&skin, name), Ok(Majorness::Column), "{name}");
}
}
#[test]
fn a_palette_is_read_by_the_lines_of_its_elements() {
let skin = dxbc(SKIN_VS);
for name in ["VC_aClothCancelObjMatrix", "VC_aObjMatrix"] {
assert_eq!(palette_lines_of(&skin, name), Ok(Majorness::Row), "{name}");
}
}
#[test]
fn a_palette_blended_then_chosen_by_a_flag_is_read_by_rows() {
for (fixture, program) in [
(
"dxc",
dxil(include_bytes!("fixtures/layered_cloth_blend_vs.dxil")),
),
(
"fxc",
dxbc(include_bytes!("fixtures/layered_cloth_blend_vs.dxbc")),
),
] {
assert_eq!(
palette_lines_of(&program, "VC_aObjMatrix"),
Ok(Majorness::Row),
"{fixture}"
);
}
}
#[test]
fn a_palette_read_only_for_its_translations_shows_no_arrangement() {
let billboard = dxbc(include_bytes!("fixtures/layered_billboard_vs.dxbc"));
assert_eq!(
palette_lines_of(&billboard, "VC_aObjMatrix"),
Err(Unshown::NotApplied)
);
}
#[test]
fn a_matrix_applied_to_a_row_vector_is_read_by_rows() {
for (fixture, program) in [
("vertex.dxil", dxil(include_bytes!("fixtures/vertex.dxil"))),
("vertex.66.dxil", dxil(include_bytes!("fixtures/vertex.66.dxil"))),
("vertex.od.dxil", dxil(include_bytes!("fixtures/vertex.od.dxil"))),
] {
assert_eq!(
lines_of(&program, "world_view_projection"),
Ok(Majorness::Row),
"{fixture}"
);
}
}
#[test]
fn a_constant_never_applied_shows_no_arrangement() {
let program = dxil(include_bytes!("fixtures/vertex.dxil"));
assert_eq!(lines_of(&program, "tint"), Err(Unshown::NotApplied));
}
#[test]
fn a_constant_s_lines_are_read_at_its_place() {
use iridia::matrix::lines_at;
use iridia_interface::MatrixLines;
let skin = dxbc(SKIN_VS);
let graph = skin.graph().expect("the value graph");
let at = |graph: Result<&iridia::ProgramGraph, &str>, name: &str| {
let (resource, c) = skin
.interface
.resources
.iter()
.find_map(|r| match &r.kind {
ResourceKind::ConstantBuffer { layout } => layout
.constants
.iter()
.find(|c| c.name == name)
.map(|c| (r.id, c)),
_ => None,
})
.expect("the constant");
let size = c.ty.size().expect("a sized constant");
lines_at(graph, &skin.interface, resource, c.offset, size)
};
assert_eq!(at(Ok(&graph), "VC_MatrixViewProj"), MatrixLines::Columns);
assert_eq!(at(Ok(&graph), "VC_aObjMatrix"), MatrixLines::Rows);
assert_eq!(
at(Ok(&graph), "SC_CameraPos"),
MatrixLines::Unshown(Unshown::NotApplied)
);
assert_eq!(
at(Err("a call"), "VC_MatrixViewProj"),
MatrixLines::Unshown(Unshown::Unexamined {
why: "the value graph: a call".into()
})
);
}