use dreamwell_gpu::gpu_driven::{GpuObjectData, MergedMeshBuffer};
use dreamwell_engine::game_object::PrimitiveKind;
pub fn generate_stress_scene(count: u32) -> Vec<GpuObjectData> {
let mut objects = Vec::with_capacity(count as usize);
objects.push(make_object(
PrimitiveKind::Plane,
[0.0, 0.0, 0.0],
[200.0, 1.0, 200.0],
[0.3, 0.3, 0.35, 1.0],
0.9, 0.0,
));
let remaining = (count - 1) as usize;
let grid_side = (remaining as f32).sqrt().ceil() as usize;
let spacing = 3.0_f32;
let half = (grid_side as f32) * spacing * 0.5;
let shapes = PrimitiveKind::ALL;
for i in 0..remaining {
let gx = (i % grid_side) as f32;
let gz = (i / grid_side) as f32;
let x = gx * spacing - half;
let z = gz * spacing - half;
let y = 0.5 + (i as f32 * 0.137).sin().abs() * 2.0;
let shape = shapes[i % shapes.len()];
let scale_base = 0.3 + (i as f32 * 0.73).sin().abs() * 0.7;
let hue = (i as f32 * 0.618) % 1.0; let color = hsv_to_rgb(hue, 0.5, 0.8);
let roughness = 0.1 + (i as f32 * 0.31).sin().abs() * 0.8;
let metallic = if i % 5 == 0 { 0.8 } else { 0.1 };
objects.push(make_object(
shape,
[x, y, z],
[scale_base, scale_base, scale_base],
[color[0], color[1], color[2], 1.0],
roughness, metallic,
));
}
log::info!(
"Stress scene: {} objects, {}x{} grid, {:.0}m span",
objects.len(), grid_side, grid_side, half * 2.0,
);
objects
}
fn make_object(
kind: PrimitiveKind,
position: [f32; 3],
scale: [f32; 3],
color: [f32; 4],
roughness: f32,
metallic: f32,
) -> GpuObjectData {
#[rustfmt::skip]
let model = [
scale[0], 0.0, 0.0, 0.0,
0.0, scale[1], 0.0, 0.0,
0.0, 0.0, scale[2], 0.0,
position[0], position[1], position[2], 1.0,
];
let radius = scale[0].max(scale[1]).max(scale[2]) * 0.75;
GpuObjectData {
model,
base_color: color,
roughness,
metallic,
emissive_strength: 0.0,
normal_scale: 1.0,
bounding_center: position,
bounding_radius: radius,
mesh_id: MergedMeshBuffer::mesh_id_lod0(kind),
_pad: [0; 3],
}
}
fn hsv_to_rgb(h: f32, s: f32, v: f32) -> [f32; 3] {
let c = v * s;
let h2 = h * 6.0;
let x = c * (1.0 - ((h2 % 2.0) - 1.0).abs());
let m = v - c;
let (r, g, b) = if h2 < 1.0 { (c, x, 0.0) }
else if h2 < 2.0 { (x, c, 0.0) }
else if h2 < 3.0 { (0.0, c, x) }
else if h2 < 4.0 { (0.0, x, c) }
else if h2 < 5.0 { (x, 0.0, c) }
else { (c, 0.0, x) };
[r + m, g + m, b + m]
}
pub fn setup_stress_lights(fabric: &mut dreamwell_fabric::DreamFabric) {
fabric.gpu_scene_mut().scene_lights.add_directional(
dreamwell_engine::lighting::DirectionalLightDesc {
direction: [0.3, -0.7, 0.5],
color: [1.0, 0.95, 0.85],
intensity_lux: 2.5,
},
);
fabric.gpu_scene_mut().scene_lights.add_directional(
dreamwell_engine::lighting::DirectionalLightDesc {
direction: [-0.3, -0.4, -0.5],
color: [0.5, 0.55, 0.7],
intensity_lux: 0.6,
},
);
fabric.gpu_scene_mut().scene_lights.add_point(
dreamwell_engine::lighting::PointLightDesc {
position: [0.0, 20.0, 0.0],
color: [1.0, 0.95, 0.9],
intensity_lumens: 2000.0,
range: 100.0,
},
);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn stress_scene_100() {
let objects = generate_stress_scene(100);
assert_eq!(objects.len(), 100);
}
#[test]
fn stress_scene_has_ground() {
let objects = generate_stress_scene(10);
assert_eq!(objects[0].bounding_center[1], 0.0);
}
#[test]
fn stress_scene_colors_vary() {
let objects = generate_stress_scene(20);
let colors: Vec<[f32; 4]> = objects[1..].iter().map(|o| o.base_color).collect();
let unique: std::collections::HashSet<u32> = colors.iter()
.map(|c| (c[0] * 1000.0) as u32)
.collect();
assert!(unique.len() > 3, "Expected color variety, got {}", unique.len());
}
}