mod app;
use app::*;
use std::f64::consts::PI;
use std::sync::Arc;
use truck_meshalgo::prelude::*;
use truck_platform::*;
use truck_rendimpl::*;
use winit::{dpi::*, event::*, keyboard::*};
struct MyApp {
scene: WindowScene,
instance0: PolygonInstance,
instance1: PolygonInstance,
instance2: WireFrameInstance,
instance3: WireFrameInstance,
wireinstance: WireFrameInstance,
rotate_flag: bool,
prev_cursor: Vector2,
render_mode: RenderMode,
}
#[derive(Clone, Copy, Debug)]
enum RenderMode {
All,
Surface,
WireFrame,
InterferenceOnly,
}
#[async_trait(?Send)]
impl App for MyApp {
async fn init(window: Arc<winit::window::Window>) -> MyApp {
let sample_count = 4;
let matrix = Matrix4::look_at_rh(
Point3::new(2.0, 2.0, 2.0),
Point3::origin(),
Vector3::unit_y(),
);
let camera = Camera::perspective_camera(
matrix.invert().unwrap(),
Rad(std::f64::consts::PI / 4.0),
0.1,
40.0,
);
let scene_desc = WindowSceneDescriptor {
studio: StudioConfig {
camera,
lights: vec![Light {
position: Point3::new(2.0, 2.0, 2.0),
color: Vector3::new(1.0, 1.0, 1.0),
light_type: LightType::Point,
}],
..Default::default()
},
backend_buffer: BackendBufferConfig {
sample_count,
..Default::default()
},
};
let mut scene = WindowScene::from_window(window, &scene_desc).await;
let sphere0 = sphere(Point3::new(0.0, 0.0, 0.7), 1.0, 50, 50);
let sphere1 = sphere(Point3::new(0.0, 0.0, -0.7), 1.0, 50, 50);
let intersect = sphere0.extract_interference(&sphere1);
let creator = scene.instance_creator();
let instance0 = creator.create_instance(
&sphere0,
&PolygonState {
material: Material {
albedo: Vector4::new(1.0, 1.0, 1.0, 0.8),
alpha_blend: true,
..Default::default()
},
..Default::default()
},
);
let instance1 = creator.create_instance(
&sphere1,
&PolygonState {
material: Material {
albedo: Vector4::new(1.0, 1.0, 1.0, 0.8),
alpha_blend: true,
..Default::default()
},
..Default::default()
},
);
let instance2 = creator.create_instance(&sphere0, &Default::default());
let instance3 = creator.create_instance(&sphere1, &Default::default());
let wireinstance = creator.create_instance(
&intersect,
&WireFrameState {
color: Vector4::new(1.0, 0.0, 0.0, 1.0),
..Default::default()
},
);
scene.add_object(&instance0);
scene.add_object(&instance1);
scene.add_object(&instance2);
scene.add_object(&instance3);
scene.add_object(&wireinstance);
MyApp {
scene,
rotate_flag: false,
prev_cursor: Vector2::zero(),
instance0,
instance1,
instance2,
instance3,
wireinstance,
render_mode: RenderMode::All,
}
}
fn mouse_input(&mut self, state: ElementState, button: MouseButton) -> ControlFlow {
match button {
MouseButton::Left => {
self.rotate_flag = state == ElementState::Pressed;
}
MouseButton::Right => {
let (light, camera) = {
let desc = self.scene.studio_config_mut();
(&mut desc.lights[0], &desc.camera)
};
match light.light_type {
LightType::Point => {
light.position = camera.position();
}
LightType::Uniform => {
light.position = camera.position();
let strength = light.position.to_vec().magnitude();
light.position /= strength;
}
}
}
_ => {}
}
Self::default_control_flow()
}
fn mouse_wheel(&mut self, delta: MouseScrollDelta, _: TouchPhase) -> ControlFlow {
match delta {
MouseScrollDelta::LineDelta(_, y) => {
let camera = &mut self.scene.studio_config_mut().camera;
let trans_vec = camera.eye_direction() * 0.2 * y as f64;
camera.matrix = Matrix4::from_translation(trans_vec) * camera.matrix;
}
MouseScrollDelta::PixelDelta(_) => {}
};
Self::default_control_flow()
}
fn cursor_moved(&mut self, position: PhysicalPosition<f64>) -> ControlFlow {
let position = Vector2::new(position.x, position.y);
if self.rotate_flag {
let matrix = &mut self.scene.studio_config_mut().camera.matrix;
let position = Vector2::new(position.x, position.y);
let dir2d = position - self.prev_cursor;
if dir2d.so_small() {
return Self::default_control_flow();
}
let mut axis = dir2d[1] * matrix[0].truncate();
axis += dir2d[0] * matrix[1].truncate();
axis /= axis.magnitude();
let angle = dir2d.magnitude() * 0.01;
let mat = Matrix4::from_axis_angle(axis, Rad(angle));
*matrix = mat.invert().unwrap() * *matrix;
}
self.prev_cursor = position;
Self::default_control_flow()
}
fn keyboard_input(&mut self, input: KeyEvent, _: bool) -> ControlFlow {
if input.state == ElementState::Released {
return Self::default_control_flow();
}
let keycode = match input.physical_key {
PhysicalKey::Code(keycode) => keycode,
_ => return Self::default_control_flow(),
};
if keycode == KeyCode::Space {
self.render_mode = match self.render_mode {
RenderMode::All => RenderMode::Surface,
RenderMode::Surface => RenderMode::WireFrame,
RenderMode::WireFrame => RenderMode::InterferenceOnly,
RenderMode::InterferenceOnly => RenderMode::All,
};
self.scene.clear_objects();
match self.render_mode {
RenderMode::All => {
self.scene.add_object(&self.instance0);
self.scene.add_object(&self.instance1);
self.scene.add_object(&self.instance2);
self.scene.add_object(&self.instance3);
self.scene.add_object(&self.wireinstance);
}
RenderMode::Surface => {
self.scene.add_object(&self.instance0);
self.scene.add_object(&self.instance1);
self.scene.add_object(&self.wireinstance);
}
RenderMode::WireFrame => {
self.scene.add_object(&self.instance2);
self.scene.add_object(&self.instance3);
self.scene.add_object(&self.wireinstance);
}
RenderMode::InterferenceOnly => {
self.scene.add_object(&self.wireinstance);
}
}
}
Self::default_control_flow()
}
fn render(&mut self) { self.scene.render_frame(); }
}
fn sphere(center: Point3, radius: f64, udiv: usize, vdiv: usize) -> PolygonMesh {
let positions = (0..udiv)
.flat_map(move |i| {
(0..vdiv).map(move |j| {
let u = 2.0 * PI * i as f64 / udiv as f64;
let v = PI * j as f64 / (vdiv - 1) as f64;
center + radius * Vector3::new(u.cos() * v.sin(), u.sin() * v.sin(), v.cos())
})
})
.collect::<Vec<_>>();
let normals = (0..udiv)
.flat_map(move |i| {
(0..vdiv).map(move |j| {
let u = 2.0 * PI * i as f64 / udiv as f64;
let v = PI * j as f64 / (vdiv - 1) as f64;
Vector3::new(u.cos() * v.sin(), u.sin() * v.sin(), v.cos())
})
})
.collect::<Vec<_>>();
let faces = (0..udiv)
.flat_map(move |i| {
(0..vdiv - 1).map(move |j| {
let a = [
i * vdiv + j,
i * vdiv + (j + 1) % vdiv,
(i + 1) % udiv * vdiv + (j + 1) % vdiv,
(i + 1) % udiv * vdiv + j,
];
[
(a[0], None, Some(a[0])),
(a[1], None, Some(a[1])),
(a[2], None, Some(a[2])),
(a[3], None, Some(a[3])),
]
})
})
.collect();
PolygonMesh::new(
StandardAttributes {
positions,
normals,
..Default::default()
},
faces,
)
}
fn main() { MyApp::run() }