Revision control
Copy as Markdown
Other Tools
use std::{ffi::c_void, mem::size_of, sync::Arc};
use glam::{Mat4, Vec3, Vec4};
use rand::{thread_rng, Rng};
use metal::{Buffer, Device, NSRange, NSUInteger};
use super::{camera::Camera, geometry::*};
pub struct Scene {
pub device: Device,
pub camera: Camera,
pub geometries: Vec<Arc<dyn Geometry>>,
pub geometry_instances: Vec<Arc<GeometryInstance>>,
pub lights: Vec<AreaLight>,
pub lights_buffer: Buffer,
}
impl Scene {
pub fn new(device: Device) -> Self {
let mut geometries = Vec::<Arc<dyn Geometry>>::new();
let mut light_mesh = TriangleGeometry::new(device.clone(), "light".to_string());
let transform = Mat4::from_translation(Vec3::new(0.0, 1.0, 0.0))
* Mat4::from_scale(Vec3::new(0.5, 1.98, 0.5));
light_mesh.add_cube_with_faces(
FACE_MASK_POSITIVE_Y,
Vec3::new(1.0, 1.0, 1.0),
transform,
true,
);
light_mesh.upload_to_buffers();
let light_mesh = Arc::new(light_mesh);
geometries.push(light_mesh.clone());
let mut geometry_mesh = TriangleGeometry::new(device.clone(), "geometry".to_string());
let transform = Mat4::from_translation(Vec3::new(0.0, 1.0, 0.0))
* Mat4::from_scale(Vec3::new(2.0, 2.0, 2.0));
geometry_mesh.add_cube_with_faces(
FACE_MASK_NEGATIVE_Y | FACE_MASK_POSITIVE_Y | FACE_MASK_NEGATIVE_Z,
Vec3::new(0.725, 0.71, 0.68),
transform,
true,
);
geometry_mesh.add_cube_with_faces(
FACE_MASK_NEGATIVE_X,
Vec3::new(0.63, 0.065, 0.05),
transform,
true,
);
geometry_mesh.add_cube_with_faces(
FACE_MASK_POSITIVE_X,
Vec3::new(0.14, 0.45, 0.091),
transform,
true,
);
let transform = Mat4::from_translation(Vec3::new(-0.335, 0.6, -0.29))
* Mat4::from_rotation_y(0.3)
* Mat4::from_scale(Vec3::new(0.6, 1.2, 0.6));
geometry_mesh.add_cube_with_faces(
FACE_MASK_ALL,
Vec3::new(0.725, 0.71, 0.68),
transform,
false,
);
geometry_mesh.upload_to_buffers();
let geometry_mesh = Arc::new(geometry_mesh);
geometries.push(geometry_mesh.clone());
let mut sphere_geometry = SphereGeometry::new(device.clone());
sphere_geometry.add_sphere_with_origin(
Vec3::new(0.3275, 0.3, 0.3725),
0.3,
Vec3::new(0.725, 0.71, 0.68),
);
sphere_geometry.upload_to_buffers();
let sphere_geometry = Arc::new(sphere_geometry);
geometries.push(sphere_geometry.clone());
let mut rng = thread_rng();
let mut geometry_instances = Vec::new();
let mut lights = Vec::new();
for y in -1..2 {
for x in -1..2 {
let transform =
Mat4::from_translation(Vec3::new(x as f32 * 2.5, y as f32 * 2.5, 0.0));
geometry_instances.push(Arc::new(GeometryInstance {
geometry: light_mesh.clone(),
transform,
mask: GEOMETRY_MASK_LIGHT,
index_in_scene: 0,
}));
geometry_instances.push(Arc::new(GeometryInstance {
geometry: geometry_mesh.clone(),
transform,
mask: GEOMETRY_MASK_TRIANGLE,
index_in_scene: 1,
}));
geometry_instances.push(Arc::new(GeometryInstance {
geometry: sphere_geometry.clone(),
transform,
mask: GEOMETRY_MASK_SPHERE,
index_in_scene: 2,
}));
lights.push(AreaLight {
position: Vec4::new(x as f32 * 2.5, y as f32 * 2.5 + 1.98, 0.0, 0.0),
forward: Vec4::new(0.0, -1.0, 0.0, 0.0),
right: Vec4::new(0.25, 0.0, 0.0, 0.0),
up: Vec4::new(0.0, 0.0, 0.25, 0.0),
colour: Vec4::new(
rng.gen_range(0f32..=1.0),
rng.gen_range(0f32..=1.0),
rng.gen_range(0f32..=1.0),
0.0,
),
});
}
}
let lights_buffer = device.new_buffer_with_data(
lights.as_ptr() as *const c_void,
(lights.len() * size_of::<AreaLight>()) as NSUInteger,
get_managed_buffer_storage_mode(),
);
lights_buffer.did_modify_range(NSRange::new(0, lights_buffer.length()));
lights_buffer.set_label("lights buffer");
Self {
device,
camera: Camera::new(),
geometries,
geometry_instances,
lights,
lights_buffer,
}
}
}