d3/src/main.rs
2022-07-24 21:45:27 -07:00

279 lines
9.1 KiB
Rust

#![warn(clippy::pedantic)]
#![allow(clippy::too_many_lines)]
// we use lots of casts, so explicitly allowing
#![allow(clippy::cast_possible_truncation)]
#![allow(clippy::cast_sign_loss)]
#![allow(clippy::cast_precision_loss)]
use d3::quaternion::Quaternion;
use d3::rgb::Rgb;
use d3::vector2::Vec2;
use d3::vector3::{Direction3, Vec3};
use softbuffer::GraphicsContext;
use std::collections::HashMap;
use std::f32::consts::PI;
use std::thread;
use std::time::{Duration, Instant};
use winit::dpi::PhysicalPosition;
use winit::event::{
ElementState, Event, KeyboardInput, ModifiersState, MouseButton, VirtualKeyCode, WindowEvent,
};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
use crate::buffer::GraphicsBuffer;
mod buffer;
#[derive(Clone, Copy, Debug)]
struct Transform {
pos: Vec3,
rot: Quaternion,
}
#[derive(Clone, Copy)]
struct Camera {
transform: Transform,
near_clip: f32,
far_clip: f32,
vertical_fov: f32,
}
#[derive(Clone, Copy)]
struct Triangle {
points: [Vec3; 3],
color: Rgb,
}
struct InputManager {
keys: HashMap<VirtualKeyCode, bool>,
buttons: HashMap<MouseButton, bool>,
modifier_keys: ModifiersState,
mouse_pos: Vec2,
mouse_delta: Vec2,
}
impl InputManager {
fn new() -> Self {
Self {
keys: HashMap::new(),
buttons: HashMap::new(),
modifier_keys: ModifiersState::empty(),
mouse_pos: (0, 0).into(),
mouse_delta: (0, 0).into(),
}
}
fn handle_keyboard_input(&mut self, ev: KeyboardInput) {
if let Some(keycode) = ev.virtual_keycode {
self.keys.insert(
keycode,
match ev.state {
ElementState::Pressed => true,
ElementState::Released => false,
},
);
}
}
fn handle_mouse_movement(&mut self, ev: PhysicalPosition<f64>) {
let ev = ev.cast::<f32>();
let new_pos = Vec2::from((ev.x, ev.y));
self.mouse_delta += new_pos - self.mouse_pos;
self.mouse_pos = new_pos;
}
fn handle_modifiers_changed(&mut self, ev: ModifiersState) {
self.modifier_keys = ev;
}
fn handle_mouse_button(&mut self, ev: (MouseButton, ElementState)) {
self.buttons.insert(
ev.0,
match ev.1 {
ElementState::Pressed => true,
ElementState::Released => false,
},
);
}
fn key_pressed(&self, key: VirtualKeyCode) -> bool {
self.keys.get(&key).copied().unwrap_or_default()
}
fn button_pressed(&self, button: MouseButton) -> bool {
self.buttons.get(&button).copied().unwrap_or_default()
}
fn end_of_frame(&mut self) {
self.mouse_delta = (0, 0).into();
}
}
fn main() {
let mut camera = Camera {
transform: Transform {
pos: Vec3::default(),
rot: Quaternion::one(),
},
near_clip: 0.1,
far_clip: 10.0,
vertical_fov: 70.0,
};
macro_rules! tri {
($a:expr, $b:expr, $c:expr; $col:expr) => {
Triangle {
points: [$a.into(), $b.into(), $c.into()],
color: $col.into(),
}
};
}
let tris = vec![
tri!((1, 1, 5), (1, -1, 5), (-1, -1, 5); Rgb::RED),
tri!((1, 1, 5), (-1, -1, 5), (-1, 1, 5); Rgb::GREEN),
tri!((-1, 1, 7), (-1, -1, 7), (1, -1, 7); Rgb::BLUE),
tri!((-1, 1, 7), (1, -1, 7), (1, 1, 7); Rgb::YELLOW),
];
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
let mut graphics_context = unsafe { GraphicsContext::new(window) }.unwrap();
let mut graphics_buffer = GraphicsBuffer::new();
let mut input_manager = InputManager::new();
let mut last_frame_start_time = Instant::now();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Poll;
match event {
Event::MainEventsCleared => {
thread::sleep(
Duration::from_secs_f32(1.0 / 30.0)
.saturating_sub(Instant::now() - last_frame_start_time),
);
let start_time = Instant::now();
let delta_time = (start_time - last_frame_start_time).as_secs_f32();
last_frame_start_time = start_time;
let (width, height) = {
let size = graphics_context.window().inner_size();
(size.width as u16, size.height as u16)
};
graphics_buffer
.resize_and_clear((width.into(), height.into()).into(), 0xbb_bb_bb.into());
if input_manager.key_pressed(VirtualKeyCode::A) {
camera.transform.pos +=
(Direction3::Left * 2.0 * delta_time).rotate_by(camera.transform.rot);
}
if input_manager.key_pressed(VirtualKeyCode::D) {
camera.transform.pos +=
(Direction3::Right * 2.0 * delta_time).rotate_by(camera.transform.rot);
}
if input_manager.key_pressed(VirtualKeyCode::W) {
camera.transform.pos +=
(Direction3::Forward * 2.0 * delta_time).rotate_by(camera.transform.rot);
}
if input_manager.key_pressed(VirtualKeyCode::S) {
camera.transform.pos +=
(Direction3::Backward * 2.0 * delta_time).rotate_by(camera.transform.rot);
}
if input_manager.modifier_keys.shift() {
camera.transform.pos +=
(Direction3::Down * 2.0 * delta_time).rotate_by(camera.transform.rot);
}
if input_manager.key_pressed(VirtualKeyCode::Space) {
camera.transform.pos +=
(Direction3::Up * 2.0 * delta_time).rotate_by(camera.transform.rot);
}
if input_manager.key_pressed(VirtualKeyCode::Q) {
*control_flow = ControlFlow::Exit;
}
if input_manager.button_pressed(MouseButton::Right) {
camera
.transform
.rot
.compose_in_place(Quaternion::rotation_around(
Direction3::Up.into(),
input_manager.mouse_delta.x / 1000.0,
));
camera
.transform
.rot
.compose_in_place(Quaternion::rotation_around(
Vec3::from(Direction3::Right).rotate_by(camera.transform.rot),
input_manager.mouse_delta.y / 1000.0,
));
}
for tri in &tris {
let points = tri.points.map(|v| transform_point(camera, v));
graphics_buffer.draw_line(points[0], points[1], tri.color);
graphics_buffer.draw_line(points[1], points[2], tri.color);
graphics_buffer.draw_line(points[2], points[0], tri.color);
}
graphics_context.set_buffer(&graphics_buffer, width, height);
// graphics_context
// .window()
// .set_cursor_position(LogicalPosition::new(400, 300))
// .unwrap();
// graphics_context.window().set_cursor_visible(false);
input_manager.end_of_frame();
}
Event::WindowEvent { window_id, event }
if window_id == graphics_context.window().id() =>
{
match event {
WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
}
WindowEvent::KeyboardInput { input, .. } => {
input_manager.handle_keyboard_input(input);
}
WindowEvent::CursorMoved { position, .. } => {
input_manager.handle_mouse_movement(position);
}
WindowEvent::ModifiersChanged(state) => {
input_manager.handle_modifiers_changed(state);
}
WindowEvent::MouseInput { state, button, .. } => {
input_manager.handle_mouse_button((button, state));
}
_ => {}
}
}
_ => {}
}
});
}
fn transform_point(camera: Camera, mut point: Vec3) -> Vec3 {
point -= camera.transform.pos;
let mut point = point.rotate_by(camera.transform.rot.inv());
let z_scale = point.z.abs();
if z_scale < (1.0 / 10000.0) {
point.x = 0.0;
point.y = 0.0;
} else {
let fov_scale = camera.vertical_fov.to_radians().tan();
let scale = fov_scale * z_scale;
point.x /= scale;
point.y /= scale;
}
point.z -= camera.near_clip;
point.z /= camera.far_clip - camera.near_clip;
point
}