feat: complete map viewer scene and static CTL pose preview

Complete the interactive mission viewer with environment rendering, audio events, dynamic shadows, free-flight camera controls, and per-component CTL pose sampling.
This commit is contained in:
Valentin Popov committed 2026-10-11 13:12:50 +04:00
1 parent aa51f3574d
commit a8faba8aad
42 files changed
+24411 -1234

No files matched your search

@@ -386,13 +386,13 @@ fn static_surface_extension_name_is_decoded() {
}
#[test]
fn swapchain_plan_prefers_srgb_mailbox_and_clamps_extent() {
fn swapchain_plan_prefers_unorm_mailbox_and_clamps_extent() {
let plan = plan_vulkan_swapchain(&swapchain_request()).expect("swapchain plan");
assert_eq!(
plan.format,
VulkanSurfaceFormat {
format: vk::Format::B8G8R8A8_SRGB.as_raw(),
format: vk::Format::R8G8B8A8_UNORM.as_raw(),
color_space: vk::ColorSpaceKHR::SRGB_NONLINEAR.as_raw(),
}
);
@@ -444,7 +444,7 @@ fn swapchain_plan_accepts_undefined_surface_format_by_picking_stage0_default() {
assert_eq!(
plan.format,
VulkanSurfaceFormat {
format: vk::Format::B8G8R8A8_SRGB.as_raw(),
format: vk::Format::R8G8B8A8_UNORM.as_raw(),
color_space: vk::ColorSpaceKHR::SRGB_NONLINEAR.as_raw(),
}
);
@@ -479,6 +479,66 @@ fn checked_in_shaders_have_valid_spirv_containers() {
assert_eq!(validate_triangle_shaders(), Ok(()));
}
#[test]
fn fragment_shader_dispatches_all_four_material_modes() {
let fragment = include_str!("../../shaders/triangle.frag");
assert!(fragment.contains("int mode = int(round(material.material_mode));"));
assert!(fragment.contains("mode == 0"));
assert!(fragment.contains("mode == 1"));
assert!(fragment.contains("mode == 2"));
assert!(fragment.contains("mode == 3"));
assert!(!fragment.contains("material_mode > 1.5"));
assert!(!fragment.contains("material_mode > 2.5"));
}
#[test]
fn native_specular_reference_uses_squared_power_and_total_overflow_curve() {
fn reference_power(cosine: f32, power: u8) -> f32 {
if power == 0 {
return 0.0;
}
let mut result = cosine;
for _ in 0..power.saturating_sub(1) {
result *= result;
}
result
}
fn reference_curve(value: f32) -> f32 {
if value <= 1.0 {
0.8 * value
} else if value <= 3.0 {
0.1 * value + 0.7
} else {
1.0
}
}
assert_eq!(reference_power(0.5, 0), 0.0);
assert!((reference_power(0.5, 1) - 0.5).abs() < 1e-6);
assert!((reference_power(0.5, 2) - 0.25).abs() < 1e-6);
assert!((reference_power(0.5, 3) - 0.0625).abs() < 1e-6);
let compressed_diffuse = 1.5;
let material_specular = 0.75;
assert!((reference_curve(material_specular + (compressed_diffuse - 1.0)) - 0.825).abs() < 1e-6);
let vertex = include_str!("../../shaders/triangle.vert");
assert!(vertex.contains("result *= result;"));
assert!(
vertex.contains("vec3 total_specular = specular + max(compressed - vec3(1.0), vec3(0.0));")
);
assert!(vertex.contains("if (power <= 0.0 || cosine <= 0.0)"));
}
#[test]
fn shader_computes_radial_fog_per_vertex_and_interpolates_it() {
let vertex = include_str!("../../shaders/triangle.vert");
let fragment = include_str!("../../shaders/triangle.frag");
assert!(vertex.contains("out_fog_factor = native_fog_factor(in_position);"));
assert!(fragment.contains("layout(location = 4) in float in_fog_factor;"));
assert!(!fragment.contains("distance(in_world_position"));
assert!(!fragment.contains("float fog_factor()"));
}
#[test]
fn shader_container_rejects_invalid_spirv() {
assert_eq!(