use std::sync::atomic::AtomicBool;
use glam::Vec3;
use super::{GpuAccumulate, GpuBatchItem, GpuSceneRef, tests::acquire_or_skip};
use crate::{
geometry::{
cuts::StandardGemCuts,
tool::{GPU_MAX_TOOL_PRIMITIVES, ToolPrimitive},
},
optics::{
materials::GemMaterial,
raytracer::{Camera, LightingPreset},
},
};
const SIZE: u32 = 16;
const fn scene<'a>(
camera: &'a Camera,
planes: &'a [crate::geometry::GpuFacetPlane],
material: &'a GemMaterial,
) -> GpuSceneRef<'a> {
GpuSceneRef {
camera,
width: SIZE,
height: SIZE,
planes,
facet_finishes: &[],
material,
max_bounces: 4,
environment: LightingPreset::Daylight.studio(1.0, 0.4, 0.35),
}
}
const fn dimple() -> ToolPrimitive {
ToolPrimitive::ball(Vec3::new(0.2, 0.32, 0.1), 0.25)
}
fn total(accum: &[Vec3]) -> Vec3 {
accum.iter().copied().sum()
}
#[test]
fn the_backend_traces_tools_and_declines_a_stone_beyond_the_limit() {
let Some(backend) =
acquire_or_skip("the_backend_traces_tools_and_declines_a_stone_beyond_the_limit")
else {
return;
};
let camera = Camera::new(0.35, 0.28, 5.0, 18.0);
let planes = StandardGemCuts::standard_round_brilliant();
let material = GemMaterial::by_name("Diamond").expect("Diamond is a built-in material");
let scene = scene(&camera, &planes, &material);
let pixels = (SIZE * SIZE) as usize;
let mut flat = vec![Vec3::ZERO; pixels];
assert!(backend.try_accumulate_geom(&scene, &[], 0, 8, &mut flat));
let mut cut = vec![Vec3::ZERO; pixels];
assert!(backend.try_accumulate_geom(&scene, &[dimple()], 0, 8, &mut cut));
assert_ne!(flat, cut, "the dimple must change the picture");
assert!(total(&cut).length() > 0.0);
let too_many = vec![dimple(); GPU_MAX_TOOL_PRIMITIVES + 1];
let mut untouched = vec![Vec3::ZERO; pixels];
assert!(!backend.try_accumulate_geom(&scene, &too_many, 0, 8, &mut untouched));
assert!(untouched.iter().all(|p| *p == Vec3::ZERO));
let at_limit = vec![dimple(); GPU_MAX_TOOL_PRIMITIVES];
let mut full = vec![Vec3::ZERO; pixels];
assert!(backend.try_accumulate_geom(&scene, &at_limit, 0, 2, &mut full));
}
#[test]
fn a_concave_picture_in_a_batch_equals_the_same_picture_alone() {
let Some(backend) =
acquire_or_skip("a_concave_picture_in_a_batch_equals_the_same_picture_alone")
else {
return;
};
let camera = Camera::new(0.35, 0.28, 5.0, 18.0);
let planes = StandardGemCuts::standard_round_brilliant();
let material = GemMaterial::by_name("Diamond").expect("Diamond is a built-in material");
let scene = scene(&camera, &planes, &material);
let pixels = (SIZE * SIZE) as usize;
let tools = [dimple()];
let mut alone = vec![Vec3::ZERO; pixels];
assert!(backend.try_accumulate_geom(&scene, &tools, 16, 8, &mut alone));
let mut flat_out = vec![Vec3::ZERO; pixels];
let mut cut_out = vec![Vec3::ZERO; pixels];
let mut items = [
GpuBatchItem {
scene: self::scene(&camera, &planes, &material),
tools: &[],
first_sample: 0,
samples: 4,
out: &mut flat_out,
},
GpuBatchItem {
scene: self::scene(&camera, &planes, &material),
tools: &tools,
first_sample: 16,
samples: 8,
out: &mut cut_out,
},
];
let mut outcomes = Vec::new();
backend.try_accumulate_batch_cancellable(&mut items, &AtomicBool::new(false), &mut |i, o| {
outcomes.push((i, o));
});
assert_eq!(
outcomes,
vec![(0, GpuAccumulate::Done), (1, GpuAccumulate::Done)]
);
assert_eq!(
cut_out, alone,
"the batch must trace the tools like the single path"
);
assert_ne!(flat_out, cut_out);
}