339 lines
9.5 KiB
Rust
339 lines
9.5 KiB
Rust
use winit::{
|
|
event::*,
|
|
event_loop::{ControlFlow, EventLoop},
|
|
window::WindowBuilder,
|
|
};
|
|
|
|
mod camera;
|
|
mod commands;
|
|
mod handle;
|
|
mod mesh;
|
|
mod model;
|
|
mod pool;
|
|
mod procgen;
|
|
mod renderer;
|
|
mod scene;
|
|
mod shader;
|
|
mod texture;
|
|
|
|
use camera::*;
|
|
use model::*;
|
|
use renderer::Renderer;
|
|
use scene::*;
|
|
use texture::*;
|
|
|
|
trait WorldState {
|
|
fn update(&mut self);
|
|
fn render(&self) -> Vec<MeshInstance>;
|
|
}
|
|
|
|
struct Grid {
|
|
meshes: Vec<MeshInstance>,
|
|
}
|
|
|
|
impl Grid {
|
|
fn new(ren: &mut Renderer) -> Self {
|
|
let model = GltfModel::load(ren);
|
|
let mut meshes = Vec::new();
|
|
for x in -5..5 {
|
|
for y in -5..5 {
|
|
let translation = glam::Vec3::new(x as f32, 0.0, y as f32) * 3.0;
|
|
let transform = glam::Mat4::from_translation(translation);
|
|
model.draw(&mut meshes, transform);
|
|
}
|
|
}
|
|
|
|
Self { meshes }
|
|
}
|
|
}
|
|
|
|
impl WorldState for Grid {
|
|
fn update(&mut self) {}
|
|
|
|
fn render(&self) -> Vec<MeshInstance> {
|
|
self.meshes.clone()
|
|
}
|
|
}
|
|
|
|
struct Metaballs {
|
|
mesh: MeshInstance,
|
|
}
|
|
|
|
impl Metaballs {
|
|
fn new(mut ren: &mut Renderer) -> Self {
|
|
use procgen::marching_cubes::*;
|
|
|
|
let metaballs = vec![
|
|
glam::Vec3A::new(-5., -5., 2.),
|
|
glam::Vec3A::new(8., 0.0, -1.),
|
|
glam::Vec3A::new(1., 5., -3.),
|
|
];
|
|
|
|
let field = |x: i32, y: i32, z: i32| {
|
|
let c = glam::Vec3A::new(x as f32, y as f32, z as f32);
|
|
let mut sum = 0.0;
|
|
for ball in metaballs.iter() {
|
|
sum += 1.0 / ball.distance(c);
|
|
}
|
|
|
|
sum - 0.4
|
|
};
|
|
|
|
let r = 20;
|
|
let domain = MarchDomain {
|
|
min: Vec3::new(-r, -r, -r),
|
|
max: Vec3::new(r, r, r),
|
|
};
|
|
|
|
let vertices = marching_cubes(field, &domain);
|
|
let vertices: Vec<mesh::Vertex> = vertices
|
|
.iter()
|
|
.map(|v| mesh::Vertex {
|
|
position: v.position.into(),
|
|
normal: v.normal.into(),
|
|
tex_coords: [0.0; 2],
|
|
})
|
|
.collect();
|
|
|
|
let indices = (0..(vertices.len() as u32)).collect();
|
|
|
|
let mesh_data = mesh::MeshData {
|
|
vertices, indices
|
|
};
|
|
|
|
let zeroed_data = pool::TextureData {
|
|
width: 8,
|
|
height: 8,
|
|
data: vec![0x00; 256],
|
|
};
|
|
|
|
let albedo_raw = include_bytes!("assets/brick_moss_001_diff_1k.jpg");
|
|
let albedo_data = load_texture_data(albedo_raw);
|
|
|
|
let metalrough_raw = include_bytes!("assets/brick_moss_001_metalrough_1k.jpg");
|
|
let metalrough_data = load_texture_data(metalrough_raw);
|
|
|
|
let mesh = ren.load_mesh(&mesh_data);
|
|
let albedo = ren.load_texture(&albedo_data);
|
|
let metalrough = ren.load_texture(&metalrough_data);
|
|
let material = ren.load_material(&pool::MaterialData { albedo, metallic_roughness: metalrough });
|
|
|
|
let mesh = scene::MeshInstance {
|
|
mesh, material, transform: glam::Mat4::IDENTITY,
|
|
};
|
|
|
|
Self { mesh }
|
|
}
|
|
}
|
|
|
|
impl WorldState for Metaballs {
|
|
fn update(&mut self) {}
|
|
|
|
fn render(&self) -> Vec<MeshInstance> {
|
|
vec![self.mesh]
|
|
}
|
|
}
|
|
|
|
struct Planet {
|
|
speed: f32,
|
|
offset: f32,
|
|
radius: f32,
|
|
size: f32,
|
|
}
|
|
|
|
struct Planets {
|
|
start: std::time::Instant,
|
|
planets: Vec<Planet>,
|
|
model: GltfModel,
|
|
}
|
|
|
|
impl Planets {
|
|
fn new(ren: &mut Renderer) -> Self {
|
|
let start = std::time::Instant::now();
|
|
let model = GltfModel::load(ren);
|
|
|
|
let mut planets = Vec::new();
|
|
for i in 0..10 {
|
|
let i = i as f32;
|
|
planets.push(Planet {
|
|
speed: 1.618 * 1.5 / i,
|
|
offset: 0.0,
|
|
radius: i * 2.0,
|
|
size: 0.5,
|
|
});
|
|
}
|
|
|
|
Self {
|
|
start,
|
|
planets,
|
|
model,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl WorldState for Planets {
|
|
fn update(&mut self) {}
|
|
|
|
fn render(&self) -> Vec<MeshInstance> {
|
|
let elapsed = self.start.elapsed().as_secs_f32();
|
|
|
|
let mut meshes = Vec::new();
|
|
for planet in self.planets.iter() {
|
|
let translation = glam::Vec3::new(0.0, 0.0, planet.radius);
|
|
let translation = glam::Mat4::from_translation(translation);
|
|
let theta = planet.speed * elapsed + planet.offset;
|
|
let rotation = glam::Mat4::from_rotation_y(theta);
|
|
self.model.draw(&mut meshes, rotation * translation);
|
|
}
|
|
|
|
meshes
|
|
}
|
|
}
|
|
|
|
async fn make_window_renderer(window: &winit::window::Window) -> Renderer {
|
|
let size = window.inner_size();
|
|
|
|
let instance = wgpu::Instance::new(wgpu::Backends::all());
|
|
let surface = unsafe { instance.create_surface(window) };
|
|
let adapter = instance
|
|
.request_adapter(&wgpu::RequestAdapterOptions {
|
|
power_preference: wgpu::PowerPreference::LowPower,
|
|
compatible_surface: Some(&surface),
|
|
force_fallback_adapter: false,
|
|
})
|
|
.await
|
|
.unwrap();
|
|
|
|
let (device, queue) = adapter
|
|
.request_device(
|
|
&wgpu::DeviceDescriptor {
|
|
features: wgpu::Features::empty(),
|
|
limits: wgpu::Limits::default(),
|
|
label: None,
|
|
},
|
|
None,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let config = wgpu::SurfaceConfiguration {
|
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
format: surface.get_preferred_format(&adapter).unwrap(),
|
|
width: size.width,
|
|
height: size.height,
|
|
present_mode: wgpu::PresentMode::Fifo,
|
|
};
|
|
surface.configure(&device, &config);
|
|
|
|
Renderer::new(size, surface, device, queue, config)
|
|
}
|
|
|
|
fn main() {
|
|
let event_loop = EventLoop::new();
|
|
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
|
let mut camera = Flycam::new(10.0, 0.002);
|
|
let mut is_grabbed = false;
|
|
let mut ren = pollster::block_on(make_window_renderer(&window));
|
|
// let mut state: Box<dyn WorldState> = Box::new(Planets::new(&mut ren));
|
|
// let mut state: Box<dyn WorldState> = Box::new(Grid::new(&mut ren));
|
|
let mut state: Box<dyn WorldState> = Box::new(Metaballs::new(&mut ren));
|
|
|
|
let lights = vec![
|
|
PointLight {
|
|
center: glam::Vec3A::new(0.0, 5.0, 0.0),
|
|
intensity: glam::Vec3A::new(100.0, 100.0, 100.0),
|
|
},
|
|
PointLight {
|
|
center: glam::Vec3A::new(-7.0, 5.0, 7.0),
|
|
intensity: glam::Vec3A::new(100.0, 0.0, 0.0),
|
|
},
|
|
PointLight {
|
|
center: glam::Vec3A::new(7.0, 5.0, 7.0),
|
|
intensity: glam::Vec3A::new(0.0, 100.0, 0.0),
|
|
},
|
|
PointLight {
|
|
center: glam::Vec3A::new(0.0, 5.0, -7.0),
|
|
intensity: glam::Vec3A::new(0.0, 0.0, 100.0),
|
|
},
|
|
PointLight {
|
|
center: glam::Vec3A::new(0.0, 50.0, 0.0),
|
|
intensity: glam::Vec3A::new(1000.0, 1000.0, 1000.0),
|
|
},
|
|
];
|
|
|
|
event_loop.run(move |event, _, control_flow| match event {
|
|
Event::RedrawRequested(_) => {
|
|
let scene = Scene {
|
|
meshes: &state.render(),
|
|
point_lights: &lights,
|
|
};
|
|
match ren.render(&camera, &scene) {
|
|
Ok(_) => {}
|
|
Err(wgpu::SurfaceError::Lost) => ren.resize(ren.size),
|
|
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
|
|
Err(wgpu::SurfaceError::Timeout) => {}
|
|
Err(e) => println!("error: {:?}", e),
|
|
};
|
|
}
|
|
Event::MainEventsCleared => {
|
|
camera.update();
|
|
state.update();
|
|
window.request_redraw();
|
|
}
|
|
Event::DeviceEvent { ref event, .. } => match event {
|
|
DeviceEvent::MouseMotion { delta } => {
|
|
if is_grabbed {
|
|
camera.process_mouse(delta.0, delta.1);
|
|
}
|
|
}
|
|
_ => {}
|
|
},
|
|
Event::WindowEvent {
|
|
ref event,
|
|
window_id,
|
|
} if window_id == window.id() => match event {
|
|
WindowEvent::KeyboardInput {
|
|
input:
|
|
KeyboardInput {
|
|
virtual_keycode: Some(key),
|
|
state,
|
|
..
|
|
},
|
|
..
|
|
} => {
|
|
if *state == ElementState::Pressed && *key == VirtualKeyCode::Escape {
|
|
if is_grabbed {
|
|
window.set_cursor_grab(false).unwrap();
|
|
window.set_cursor_visible(true);
|
|
is_grabbed = false;
|
|
}
|
|
} else {
|
|
camera.process_keyboard(*key, *state);
|
|
}
|
|
}
|
|
WindowEvent::MouseInput {
|
|
button: MouseButton::Left,
|
|
state: ElementState::Pressed,
|
|
..
|
|
} => {
|
|
if !is_grabbed {
|
|
window.set_cursor_grab(true).unwrap();
|
|
window.set_cursor_visible(false);
|
|
is_grabbed = true;
|
|
}
|
|
}
|
|
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
|
WindowEvent::Resized(physical_size) => {
|
|
ren.resize(*physical_size);
|
|
camera.resize(physical_size.width, physical_size.height);
|
|
}
|
|
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
|
|
ren.resize(**new_inner_size);
|
|
camera.resize(new_inner_size.width, new_inner_size.height);
|
|
}
|
|
_ => {}
|
|
},
|
|
_ => {}
|
|
});
|
|
}
|