Add RenderCallbacks intermediate layer
This commit is contained in:
parent
55b3979ea7
commit
99633ea0be
|
@ -3,7 +3,7 @@
|
||||||
use crate::camera::Camera;
|
use crate::camera::Camera;
|
||||||
use crate::pass::{self, debug, mesh};
|
use crate::pass::{self, debug, mesh};
|
||||||
use crate::scene;
|
use crate::scene;
|
||||||
use crate::viewport::{ViewportInfo, WinitViewport};
|
use crate::viewport::{Viewport, ViewportInfo};
|
||||||
use crate::Renderer;
|
use crate::Renderer;
|
||||||
use legion::systems::Builder;
|
use legion::systems::Builder;
|
||||||
use legion::world::SubWorld;
|
use legion::world::SubWorld;
|
||||||
|
@ -11,6 +11,12 @@ use legion::*;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// Callbacks trait for acquiring renderer input dynamically.
|
||||||
|
pub trait RenderCallbacks: 'static + Send + Sync {
|
||||||
|
fn get_viewports(&mut self) -> Vec<(&dyn Viewport, Camera)>;
|
||||||
|
fn present(&mut self);
|
||||||
|
}
|
||||||
|
|
||||||
/// Initializes the Cyborg renderer within a Legion world.
|
/// Initializes the Cyborg renderer within a Legion world.
|
||||||
///
|
///
|
||||||
/// Uses the provided [Builder] to run all rendering code.
|
/// Uses the provided [Builder] to run all rendering code.
|
||||||
|
@ -19,7 +25,11 @@ use std::sync::Arc;
|
||||||
/// - [Renderer]
|
/// - [Renderer]
|
||||||
/// - [ViewportInfo] (TODO: dynamic viewport targeting)
|
/// - [ViewportInfo] (TODO: dynamic viewport targeting)
|
||||||
/// - [mesh::ShaderInfo]
|
/// - [mesh::ShaderInfo]
|
||||||
pub fn build_renderer(resources: &mut Resources, builder: &mut Builder) {
|
pub fn build_renderer<T: RenderCallbacks>(
|
||||||
|
callbacks: T,
|
||||||
|
resources: &mut Resources,
|
||||||
|
builder: &mut Builder,
|
||||||
|
) {
|
||||||
let renderer = resources.get_mut::<Renderer>().unwrap();
|
let renderer = resources.get_mut::<Renderer>().unwrap();
|
||||||
let viewport_info = resources.get::<ViewportInfo>().unwrap();
|
let viewport_info = resources.get::<ViewportInfo>().unwrap();
|
||||||
let mesh_shaders = resources.get::<mesh::ShaderInfo>().unwrap();
|
let mesh_shaders = resources.get::<mesh::ShaderInfo>().unwrap();
|
||||||
|
@ -52,27 +62,27 @@ pub fn build_renderer(resources: &mut Resources, builder: &mut Builder) {
|
||||||
resources.insert(mesh_pass);
|
resources.insert(mesh_pass);
|
||||||
resources.insert(debug_pass);
|
resources.insert(debug_pass);
|
||||||
|
|
||||||
|
resources.insert(callbacks);
|
||||||
|
|
||||||
builder.add_system(draw_transformed_meshes_system());
|
builder.add_system(draw_transformed_meshes_system());
|
||||||
builder.add_system(draw_debug_system());
|
builder.add_system(draw_debug_system());
|
||||||
builder.add_system(draw_debug_transformed_system());
|
builder.add_system(draw_debug_transformed_system());
|
||||||
builder.add_system(render_system());
|
builder.add_system(render_system::<T>());
|
||||||
builder.add_system(present_winit_system());
|
builder.add_system(present_system::<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[system]
|
#[system]
|
||||||
#[read_component(WinitViewport)]
|
fn render<T: RenderCallbacks>(
|
||||||
#[read_component(Camera)]
|
#[resource] callbacks: &mut T,
|
||||||
fn render(
|
|
||||||
world: &mut SubWorld,
|
|
||||||
#[resource] renderer: &mut Renderer,
|
#[resource] renderer: &mut Renderer,
|
||||||
#[resource] mesh_pass: &mut pass::RenderPassBox<mesh::MeshPass>,
|
#[resource] mesh_pass: &mut pass::RenderPassBox<mesh::MeshPass>,
|
||||||
#[resource] debug_pass: &mut pass::RenderPassBox<debug::DebugPass>,
|
#[resource] debug_pass: &mut pass::RenderPassBox<debug::DebugPass>,
|
||||||
) {
|
) {
|
||||||
let target_query: Vec<_> = <(&WinitViewport, &Camera)>::query().iter(world).collect();
|
let viewports = callbacks.get_viewports();
|
||||||
if target_query.len() > 1 {
|
if viewports.len() > 1 {
|
||||||
eprintln!("Cyborg does not currently support more than one viewport at a time!");
|
eprintln!("Cyborg does not currently support more than one viewport at a time!");
|
||||||
return;
|
return;
|
||||||
} else if let Some((viewport, camera)) = target_query.get(0) {
|
} else if let Some((viewport, camera)) = viewports.get(0) {
|
||||||
let mut passes: Vec<&mut dyn pass::RenderPassBoxTrait> = Vec::new();
|
let mut passes: Vec<&mut dyn pass::RenderPassBoxTrait> = Vec::new();
|
||||||
passes.push(mesh_pass);
|
passes.push(mesh_pass);
|
||||||
passes.push(debug_pass);
|
passes.push(debug_pass);
|
||||||
|
@ -80,6 +90,11 @@ fn render(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[system]
|
||||||
|
fn present<T: RenderCallbacks>(#[resource] callbacks: &mut T) {
|
||||||
|
callbacks.present();
|
||||||
|
}
|
||||||
|
|
||||||
#[system(for_each)]
|
#[system(for_each)]
|
||||||
fn draw_transformed_meshes(
|
fn draw_transformed_meshes(
|
||||||
#[resource] mesh_pass: &pass::RenderPassBox<mesh::MeshPass>,
|
#[resource] mesh_pass: &pass::RenderPassBox<mesh::MeshPass>,
|
||||||
|
@ -92,11 +107,6 @@ fn draw_transformed_meshes(
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[system(for_each)]
|
|
||||||
fn present_winit(viewport: &mut WinitViewport) {
|
|
||||||
viewport.present();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[system(for_each)]
|
#[system(for_each)]
|
||||||
#[filter(!component::<scene::Transform>())]
|
#[filter(!component::<scene::Transform>())]
|
||||||
fn draw_debug(
|
fn draw_debug(
|
||||||
|
|
168
src/main.rs
168
src/main.rs
|
@ -1,4 +1,4 @@
|
||||||
use cyborg::camera::Camera;
|
use cyborg::camera::{Camera, Flycam};
|
||||||
use cyborg::pass::{mesh, RenderPassBox};
|
use cyborg::pass::{mesh, RenderPassBox};
|
||||||
use cyborg::shader;
|
use cyborg::shader;
|
||||||
use cyborg::storage::mesh::*;
|
use cyborg::storage::mesh::*;
|
||||||
|
@ -7,6 +7,7 @@ use cyborg::Renderer;
|
||||||
use legion::*;
|
use legion::*;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use winit::dpi::PhysicalSize;
|
||||||
use winit::{
|
use winit::{
|
||||||
event::*,
|
event::*,
|
||||||
event_loop::{ControlFlow, EventLoop},
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
@ -58,6 +59,11 @@ fn update_dt(#[resource] dt: &mut DeltaTime) {
|
||||||
dt.last_update = std::time::Instant::now();
|
dt.last_update = std::time::Instant::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[system]
|
||||||
|
fn update_app(#[resource] app: &mut Application) {
|
||||||
|
app.update();
|
||||||
|
}
|
||||||
|
|
||||||
#[system(for_each)]
|
#[system(for_each)]
|
||||||
fn apply_gravity(#[resource] dt: &DeltaTime, velocity: &mut Velocity) {
|
fn apply_gravity(#[resource] dt: &DeltaTime, velocity: &mut Velocity) {
|
||||||
const GRAVITY: f32 = 6.0;
|
const GRAVITY: f32 = 6.0;
|
||||||
|
@ -114,6 +120,7 @@ fn update_debug(draw_list: &mut cyborg::scene::DebugDrawList, velocity: &Velocit
|
||||||
fn build_update_schedule() -> Schedule {
|
fn build_update_schedule() -> Schedule {
|
||||||
let mut builder = Schedule::builder();
|
let mut builder = Schedule::builder();
|
||||||
builder.add_system(update_dt_system());
|
builder.add_system(update_dt_system());
|
||||||
|
builder.add_system(update_app_system());
|
||||||
builder.add_system(apply_gravity_system());
|
builder.add_system(apply_gravity_system());
|
||||||
builder.add_system(move_particles_system());
|
builder.add_system(move_particles_system());
|
||||||
builder.add_system(respawn_particles_system());
|
builder.add_system(respawn_particles_system());
|
||||||
|
@ -199,6 +206,65 @@ fn make_terrain(attributes: &mesh::Attributes) -> MeshBuffer {
|
||||||
mesh
|
mesh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Application {
|
||||||
|
window: winit::window::Window,
|
||||||
|
viewport: WinitViewport,
|
||||||
|
flycam: Flycam,
|
||||||
|
is_grabbed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Application {
|
||||||
|
pub fn update(&mut self) {
|
||||||
|
self.flycam.update();
|
||||||
|
self.window.request_redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_mouse_motion(&mut self, x: f64, y: f64) {
|
||||||
|
if self.is_grabbed {
|
||||||
|
self.flycam.process_mouse(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_mouse_event(&mut self, button: MouseButton, state: ElementState) {
|
||||||
|
if button == MouseButton::Left && state == ElementState::Pressed && !self.is_grabbed {
|
||||||
|
self.window.set_cursor_grab(true).unwrap();
|
||||||
|
self.window.set_cursor_visible(false);
|
||||||
|
self.is_grabbed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_key_event(&mut self, key: VirtualKeyCode, state: ElementState) {
|
||||||
|
if key == VirtualKeyCode::Escape && state == ElementState::Pressed {
|
||||||
|
if self.is_grabbed {
|
||||||
|
self.window.set_cursor_grab(false).unwrap();
|
||||||
|
self.window.set_cursor_visible(true);
|
||||||
|
self.is_grabbed = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.flycam.process_keyboard(key, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_resize(&mut self, new_size: PhysicalSize<u32>) {
|
||||||
|
self.viewport.resize(new_size);
|
||||||
|
self.flycam.resize(new_size.width, new_size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_surface_lost(&mut self) {
|
||||||
|
self.viewport.resize(self.viewport.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl cyborg::legion::RenderCallbacks for Application {
|
||||||
|
fn get_viewports(&mut self) -> Vec<(&dyn Viewport, Camera)> {
|
||||||
|
vec![(&self.viewport as &dyn Viewport, self.flycam.get_camera())]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn present(&mut self) {
|
||||||
|
self.viewport.present();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||||
|
@ -216,8 +282,7 @@ fn main() {
|
||||||
|
|
||||||
resources.insert(viewport.get_info().to_owned());
|
resources.insert(viewport.get_info().to_owned());
|
||||||
|
|
||||||
let mut flycam = cyborg::camera::Flycam::new(0.002, 10.0, 0.25);
|
let flycam = cyborg::camera::Flycam::new(0.002, 10.0, 0.25);
|
||||||
let mut is_grabbed = false;
|
|
||||||
|
|
||||||
let shader_store = Arc::new(shader::ShaderStore::new(viewport.device.clone()));
|
let shader_store = Arc::new(shader::ShaderStore::new(viewport.device.clone()));
|
||||||
let shaders_dir = std::env::current_dir().unwrap();
|
let shaders_dir = std::env::current_dir().unwrap();
|
||||||
|
@ -235,8 +300,15 @@ fn main() {
|
||||||
|
|
||||||
resources.insert(mesh_shaders);
|
resources.insert(mesh_shaders);
|
||||||
|
|
||||||
|
let application = Application {
|
||||||
|
window,
|
||||||
|
viewport,
|
||||||
|
flycam,
|
||||||
|
is_grabbed: false,
|
||||||
|
};
|
||||||
|
|
||||||
let mut render_schedule = Schedule::builder();
|
let mut render_schedule = Schedule::builder();
|
||||||
cyborg::legion::build_renderer(&mut resources, &mut render_schedule);
|
cyborg::legion::build_renderer(application, &mut resources, &mut render_schedule);
|
||||||
let mut render_schedule = render_schedule.build();
|
let mut render_schedule = render_schedule.build();
|
||||||
|
|
||||||
let example_vertices = vec![
|
let example_vertices = vec![
|
||||||
|
@ -317,17 +389,15 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let viewport_entity = world.push((viewport, flycam.get_camera()));
|
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, _, control_flow| match event {
|
||||||
Event::RedrawRequested(_) => {
|
Event::RedrawRequested(_) => {
|
||||||
let mut viewport_entry = world.entry_mut(viewport_entity).unwrap();
|
let mut application = resources.get_mut::<Application>().unwrap();
|
||||||
let viewport = viewport_entry.get_component_mut::<WinitViewport>().unwrap();
|
match application.viewport.acquire() {
|
||||||
match viewport.acquire() {
|
Err(wgpu::SurfaceError::Lost) => application.on_surface_lost(),
|
||||||
Err(wgpu::SurfaceError::Lost) => viewport.resize(viewport.size),
|
|
||||||
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
|
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
|
||||||
Err(e) => eprintln!("error: {:?}", e),
|
Err(e) => eprintln!("error: {:?}", e),
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
|
drop(application);
|
||||||
render_schedule.execute(&mut world, &mut resources);
|
render_schedule.execute(&mut world, &mut resources);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -335,70 +405,46 @@ fn main() {
|
||||||
Event::MainEventsCleared => {
|
Event::MainEventsCleared => {
|
||||||
update_schedule.execute(&mut world, &mut resources);
|
update_schedule.execute(&mut world, &mut resources);
|
||||||
shader_watcher.watch();
|
shader_watcher.watch();
|
||||||
flycam.update();
|
|
||||||
window.request_redraw();
|
|
||||||
|
|
||||||
let mut viewport_entry = world.entry_mut(viewport_entity).unwrap();
|
|
||||||
let camera = viewport_entry.get_component_mut::<Camera>().unwrap();
|
|
||||||
let _ = std::mem::replace(camera, flycam.get_camera());
|
|
||||||
}
|
}
|
||||||
Event::DeviceEvent { ref event, .. } => match event {
|
Event::DeviceEvent { ref event, .. } => match event {
|
||||||
DeviceEvent::MouseMotion { delta } => {
|
DeviceEvent::MouseMotion { delta } => {
|
||||||
if is_grabbed {
|
let mut application = resources.get_mut::<Application>().unwrap();
|
||||||
flycam.process_mouse(delta.0, delta.1);
|
application.on_mouse_motion(delta.0, delta.1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
ref event,
|
ref event,
|
||||||
window_id,
|
window_id,
|
||||||
} if window_id == window.id() => match event {
|
} => {
|
||||||
WindowEvent::KeyboardInput {
|
let mut application = resources.get_mut::<Application>().unwrap();
|
||||||
input:
|
if window_id == application.window.id() {
|
||||||
KeyboardInput {
|
match event {
|
||||||
virtual_keycode: Some(key),
|
WindowEvent::KeyboardInput {
|
||||||
state,
|
input:
|
||||||
|
KeyboardInput {
|
||||||
|
virtual_keycode: Some(key),
|
||||||
|
state,
|
||||||
|
..
|
||||||
|
},
|
||||||
..
|
..
|
||||||
},
|
} => {
|
||||||
..
|
application.on_key_event(*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 {
|
WindowEvent::MouseInput { button, state, .. } => {
|
||||||
flycam.process_keyboard(*key, *state);
|
application.on_mouse_event(*button, *state);
|
||||||
|
}
|
||||||
|
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||||
|
WindowEvent::Resized(physical_size) => {
|
||||||
|
application.on_resize(*physical_size);
|
||||||
|
}
|
||||||
|
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
|
||||||
|
application.on_resize(**new_inner_size);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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) => {
|
|
||||||
let mut viewport_entry = world.entry_mut(viewport_entity).unwrap();
|
|
||||||
let viewport = viewport_entry.get_component_mut::<WinitViewport>().unwrap();
|
|
||||||
viewport.resize(*physical_size);
|
|
||||||
flycam.resize(physical_size.width, physical_size.height);
|
|
||||||
}
|
|
||||||
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
|
|
||||||
let mut viewport_entry = world.entry_mut(viewport_entity).unwrap();
|
|
||||||
let viewport = viewport_entry.get_component_mut::<WinitViewport>().unwrap();
|
|
||||||
viewport.resize(**new_inner_size);
|
|
||||||
flycam.resize(new_inner_size.width, new_inner_size.height);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
_ => {}
|
_ => {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue