use dreamwell_engine::game_object::{GameObjectScene, MeshBinding, PrimitiveKind};
use dreamwell_gpu::camera::Camera;
pub const DEFAULT_DREAMLET_CAPACITY: u32 = 65536;
const PROJECTILE_COLOR: [f32; 4] = [0.15, 0.4, 0.95, 1.0];
const DEBRIS_COLOR: [f32; 4] = [0.95, 0.5, 0.1, 1.0];
pub fn create_base_scene() -> GameObjectScene {
let mut scene = GameObjectScene::new("DreamMatter Keynote".to_string());
if let Ok(id) = scene.spawn_primitive("Ground".into(), PrimitiveKind::Plane) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.scale = [80.0, 1.0, 80.0];
}
}
if let Ok(id) = scene.spawn_primitive("ConvergenceTarget".into(), PrimitiveKind::Sphere) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.position = [0.0, 3.0, 0.0];
obj.transform.scale = [3.0, 3.0, 3.0];
}
}
for (i, x) in [-10.0_f32, 0.0, 10.0].iter().enumerate() {
let name = format!("Pillar_{i}");
if let Ok(id) = scene.spawn_primitive(name, PrimitiveKind::Cylinder) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.position = [*x, 3.5, -10.0];
obj.transform.scale = [1.2, 7.0, 1.2];
}
}
}
for (i, x) in [-10.0_f32, 0.0, 10.0].iter().enumerate() {
let name = format!("PillarCap_{i}");
if let Ok(id) = scene.spawn_primitive(name, PrimitiveKind::Sphere) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.position = [*x, 7.2, -10.0];
obj.transform.scale = [1.6, 1.6, 1.6];
}
}
}
if let Ok(id) = scene.spawn_primitive("NearTorus".into(), PrimitiveKind::Torus) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.position = [-4.0, 1.2, 4.0];
obj.transform.scale = [2.0, 2.0, 2.0];
}
}
if let Ok(id) = scene.spawn_primitive("NearCone".into(), PrimitiveKind::Cone) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.position = [4.0, 1.0, 4.0];
obj.transform.scale = [1.5, 2.5, 1.5];
}
}
for (i, (x, z)) in [(-14.0_f32, -6.0_f32), (14.0, -6.0)].iter().enumerate() {
let name = format!("MidSphere_{i}");
if let Ok(id) = scene.spawn_primitive(name, PrimitiveKind::Sphere) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.position = [*x, 2.5, *z];
obj.transform.scale = [3.0, 3.0, 3.0];
}
}
}
for (i, x) in [-25.0_f32, -18.0, 18.0, 25.0].iter().enumerate() {
let name = format!("FarCapsule_{i}");
if let Ok(id) = scene.spawn_primitive(name, PrimitiveKind::Capsule) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.position = [*x, 2.0, -12.0];
obj.transform.scale = [2.0, 4.0, 2.0];
}
}
}
if let Ok(id) = scene.spawn_primitive("ParticlePyramid".into(), PrimitiveKind::Pyramid) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.position = [-7.0, 0.5, 0.0];
obj.transform.scale = [2.5, 3.0, 2.5];
}
}
if let Ok(id) = scene.spawn_primitive("Wedge".into(), PrimitiveKind::Wedge) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.position = [7.0, 0.5, 0.0];
obj.transform.scale = [2.5, 2.0, 2.5];
}
}
if let Ok(id) = scene.spawn_primitive("EmissiveSphere".into(), PrimitiveKind::Sphere) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.position = [5.0, 2.0, -3.0];
obj.transform.scale = [1.5, 1.5, 1.5];
obj.mesh = MeshBinding::Primitive {
kind: PrimitiveKind::Sphere,
color: [5.0, 4.5, 3.0, 1.0], };
}
}
if let Ok(id) = scene.spawn_primitive("GlassCube".into(), PrimitiveKind::Cube) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.position = [-5.0, 1.5, -3.0];
obj.transform.scale = [2.0, 2.0, 2.0];
obj.mesh = MeshBinding::Primitive {
kind: PrimitiveKind::Cube,
color: [0.8, 0.9, 1.0, 0.3], };
}
}
for i in 0..7 {
let x = (i as f32 - 3.0) * 3.5;
let name = format!("FrontCube_{i}");
if let Ok(id) = scene.spawn_primitive(name, PrimitiveKind::Cube) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.position = [x, 0.5, 8.0];
obj.transform.scale = [0.8, 0.8, 0.8];
}
}
}
scene
}
#[allow(dead_code)]
pub fn upload_scene_with_dynamics(
device: &wgpu::Device,
fabric: &mut dreamwell_fabric::DreamFabric,
base_scene: &GameObjectScene,
projectile_positions: &[glam::Vec3],
debris: &[(glam::Vec3, f32)], ) {
let mut scene = base_scene.clone();
for (i, pos) in projectile_positions.iter().enumerate() {
let name = format!("Projectile_{i}");
if let Ok(id) = scene.spawn_primitive(name, PrimitiveKind::Cube) {
if let Some(obj) = scene.find_mut(id) {
obj.transform.position = pos.to_array();
obj.transform.scale = [0.3, 0.3, 0.3];
obj.mesh = MeshBinding::Primitive {
kind: PrimitiveKind::Cube,
color: PROJECTILE_COLOR,
};
}
}
}
for (i, (pos, age)) in debris.iter().enumerate() {
let name = format!("Debris_{i}");
if let Ok(id) = scene.spawn_primitive(name, PrimitiveKind::Cube) {
if let Some(obj) = scene.find_mut(id) {
let fade = (1.0 - age / super::DEBRIS_LIFETIME).max(0.0);
let s = 0.12 * fade;
obj.transform.position = pos.to_array();
obj.transform.scale = [s, s, s];
obj.mesh = MeshBinding::Primitive {
kind: PrimitiveKind::Cube,
color: [
DEBRIS_COLOR[0] * fade,
DEBRIS_COLOR[1] * fade,
DEBRIS_COLOR[2] * fade,
1.0,
],
};
}
}
}
fabric.upload_scene(device, &scene);
}
pub fn setup_benchmark_scene(
device: &wgpu::Device,
_queue: &wgpu::Queue,
fabric: &mut dreamwell_fabric::DreamFabric,
base_scene: &GameObjectScene,
) {
fabric.upload_scene(device, base_scene);
fabric.ensure_particle_capacity(device, DEFAULT_DREAMLET_CAPACITY);
fabric.gpu_scene_mut().scene_lights.add_directional(
dreamwell_engine::lighting::DirectionalLightDesc {
direction: normalize([0.4, -0.65, 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: normalize([-0.3, -0.4, -0.5]),
color: [0.5, 0.55, 0.7],
intensity_lux: 0.6,
},
);
let accent_lights = [
([0.0, 8.0, 0.0], [1.0, 0.95, 0.9], 500.0, 25.0), ([-10.0, 3.0, 0.0], [0.2, 0.4, 0.9], 250.0, 15.0), ([10.0, 3.0, 0.0], [0.9, 0.5, 0.1], 250.0, 15.0), ([0.0, 4.0, -10.0], [0.1, 0.7, 0.3], 180.0, 18.0), ([0.0, 2.5, 10.0], [0.6, 0.1, 0.8], 180.0, 15.0), ([-6.0, 1.5, 6.0], [0.9, 0.7, 0.4], 120.0, 10.0), ([6.0, 1.5, 6.0], [0.4, 0.7, 0.9], 120.0, 10.0), ([0.0, 1.0, 0.0], [1.0, 0.9, 0.7], 100.0, 8.0), ];
for (pos, color, lumens, range) in accent_lights {
fabric.gpu_scene_mut().scene_lights.add_point(
dreamwell_engine::lighting::PointLightDesc {
position: pos,
color,
intensity_lumens: lumens,
range,
},
);
}
fabric.gpu_scene_mut().default_roughness = 0.35;
fabric.gpu_scene_mut().default_metallic = 0.15;
log::info!(
"Keynote scene: {} objects, {} directional + {} point lights, {} Dreamlets",
base_scene.objects.len(),
fabric.gpu_scene().scene_lights.directional.len(),
fabric.gpu_scene().scene_lights.point.len(),
DEFAULT_DREAMLET_CAPACITY,
);
}
pub fn update_sun_orbit(fabric: &mut dreamwell_fabric::DreamFabric, elapsed: f32, duration: f32) {
let angle = (elapsed / duration) * std::f32::consts::TAU * 0.75;
let pitch: f32 = -0.6;
let dir = normalize([
angle.cos() * pitch.cos(),
pitch.sin(),
angle.sin() * pitch.cos(),
]);
if let Some(light) = fabric.gpu_scene_mut().scene_lights.directional.first_mut() {
light.direction = dir;
}
}
pub fn cinematic_camera(elapsed: f32, duration: f32, aspect_ratio: f32) -> Camera {
let t = elapsed / duration;
let orbit_angle = t * std::f32::consts::TAU * 0.75;
let height = 5.0 + 3.0 * (t * std::f32::consts::TAU).sin();
let distance = 16.0 - 4.0 * (t * std::f32::consts::PI * 2.0).sin();
let cam_x = orbit_angle.sin() * distance;
let cam_z = orbit_angle.cos() * distance;
let cam_pos = glam::Vec3::new(cam_x, height, cam_z);
let target = glam::Vec3::new(0.0, 2.0, 0.0);
let mut camera = Camera::default();
camera.position = cam_pos;
camera.view_matrix = glam::Mat4::look_at_rh(cam_pos, target, glam::Vec3::Y);
camera.update_projection(aspect_ratio, 55.0);
camera
}
pub fn benchmark_camera(aspect_ratio: f32) -> Camera {
let mut camera = Camera::default();
camera.position = glam::Vec3::new(0.0, 5.0, 18.0);
let target = glam::Vec3::new(0.0, 2.0, 0.0);
camera.view_matrix = glam::Mat4::look_at_rh(camera.position, target, glam::Vec3::Y);
camera.update_projection(aspect_ratio, 55.0);
camera
}
pub fn setup_physics_colliders(physics: &mut dreamwell_engine::physics::simulation::PhysicsWorld) {
use dreamwell_engine::physics::simulation::{CollisionShape, RigidBody};
physics.add_body(RigidBody::fixed(CollisionShape::Plane {
normal: [0.0, 1.0, 0.0], d: 0.0,
}));
physics.add_body(
RigidBody::fixed(CollisionShape::Sphere { radius: 1.5 })
.with_position([0.0, 3.0, 0.0]).with_restitution(0.7)
);
for x in [-10.0_f32, 0.0, 10.0] {
physics.add_body(
RigidBody::fixed(CollisionShape::Aabb { half_extents: [0.6, 3.5, 0.6] })
.with_position([x, 3.5, -10.0]).with_restitution(0.4)
);
}
for x in [-10.0_f32, 0.0, 10.0] {
physics.add_body(
RigidBody::fixed(CollisionShape::Sphere { radius: 0.8 })
.with_position([x, 7.2, -10.0]).with_restitution(0.6)
);
}
physics.add_body(
RigidBody::fixed(CollisionShape::Sphere { radius: 1.0 })
.with_position([-4.0, 1.2, 4.0]).with_restitution(0.5)
);
physics.add_body(
RigidBody::fixed(CollisionShape::Sphere { radius: 0.75 })
.with_position([4.0, 1.0, 4.0]).with_restitution(0.5)
);
physics.add_body(
RigidBody::fixed(CollisionShape::Sphere { radius: 1.2 })
.with_position([-7.0, 0.5, 0.0]).with_restitution(0.5)
);
physics.add_body(
RigidBody::fixed(CollisionShape::Aabb { half_extents: [1.25, 1.0, 1.25] })
.with_position([7.0, 0.5, 0.0]).with_restitution(0.5)
);
for i in 0..7 {
let x = (i as f32 - 3.0) * 3.5;
physics.add_body(
RigidBody::fixed(CollisionShape::Aabb { half_extents: [0.4, 0.4, 0.4] })
.with_position([x, 0.5, 8.0]).with_restitution(0.5)
);
}
physics.add_body(
RigidBody::fixed(CollisionShape::Sphere { radius: 1.5 })
.with_position([-14.0, 2.5, -6.0]).with_restitution(0.6)
);
physics.add_body(
RigidBody::fixed(CollisionShape::Sphere { radius: 1.5 })
.with_position([14.0, 2.5, -6.0]).with_restitution(0.6)
);
log::info!("Physics colliders: {} static bodies", physics.body_count());
}
pub fn scene_to_gpu_objects(
scene: &GameObjectScene,
default_roughness: f32,
default_metallic: f32,
) -> Vec<dreamwell_gpu::gpu_driven::GpuObjectData> {
use dreamwell_gpu::gpu_driven::{GpuObjectData, MergedMeshBuffer};
let mut objects = Vec::with_capacity(scene.objects.len());
for obj in &scene.objects {
if !obj.visible { continue; }
let MeshBinding::Primitive { kind, color } = &obj.mesh else { continue };
let s = obj.transform.scale;
let p = obj.transform.position;
#[rustfmt::skip]
let model = [
s[0], 0.0, 0.0, 0.0,
0.0, s[1], 0.0, 0.0,
0.0, 0.0, s[2], 0.0,
p[0], p[1], p[2], 1.0,
];
let radius = s[0].max(s[1]).max(s[2]) * 0.75;
let luminance = color[0] * 0.2126 + color[1] * 0.7152 + color[2] * 0.0722;
let emissive = if luminance > 1.0 { luminance } else { 0.0 };
objects.push(GpuObjectData {
model,
base_color: *color,
roughness: default_roughness,
metallic: default_metallic,
emissive_strength: emissive,
normal_scale: 1.0,
bounding_center: p,
bounding_radius: radius,
mesh_id: MergedMeshBuffer::mesh_id_lod0(*kind),
_pad: [0; 3],
});
}
objects
}
pub fn add_dynamic_gpu_objects(
objects: &mut Vec<dreamwell_gpu::gpu_driven::GpuObjectData>,
projectile_positions: &[glam::Vec3],
debris: &[(glam::Vec3, f32)],
) {
use dreamwell_gpu::gpu_driven::{GpuObjectData, MergedMeshBuffer};
let cube_mesh_id = MergedMeshBuffer::mesh_id_lod0(PrimitiveKind::Cube);
for pos in projectile_positions {
let p = pos.to_array();
#[rustfmt::skip]
let model = [
0.3, 0.0, 0.0, 0.0,
0.0, 0.3, 0.0, 0.0,
0.0, 0.0, 0.3, 0.0,
p[0], p[1], p[2], 1.0,
];
objects.push(GpuObjectData {
model,
base_color: PROJECTILE_COLOR,
roughness: 0.3,
metallic: 0.8,
emissive_strength: 0.5,
normal_scale: 1.0,
bounding_center: p,
bounding_radius: 0.3,
mesh_id: cube_mesh_id,
_pad: [0; 3],
});
}
for (pos, age) in debris {
let fade = (1.0 - age / super::DEBRIS_LIFETIME).max(0.0);
let s = 0.12 * fade;
let p = pos.to_array();
#[rustfmt::skip]
let model = [
s, 0.0, 0.0, 0.0,
0.0, s, 0.0, 0.0,
0.0, 0.0, s, 0.0,
p[0], p[1], p[2], 1.0,
];
objects.push(GpuObjectData {
model,
base_color: [
DEBRIS_COLOR[0] * fade,
DEBRIS_COLOR[1] * fade,
DEBRIS_COLOR[2] * fade,
1.0,
],
roughness: 0.5,
metallic: 0.1,
emissive_strength: fade * 2.0,
normal_scale: 1.0,
bounding_center: p,
bounding_radius: s,
mesh_id: cube_mesh_id,
_pad: [0; 3],
});
}
}
pub fn normalize(v: [f32; 3]) -> [f32; 3] {
let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt();
if len > 1e-8 { [v[0] / len, v[1] / len, v[2] / len] } else { [0.0, -1.0, 0.0] }
}