diff options
author | tcmal <me@aria.rip> | 2024-08-25 17:44:23 +0100 |
---|---|---|
committer | tcmal <me@aria.rip> | 2024-08-25 17:44:23 +0100 |
commit | 47a0c0317cc774c19b78582bec9b5b09d56f569a (patch) | |
tree | d03471ea4e084ace9b95a2c5b7febb780b45bb63 /examples/render-quad | |
parent | fb996488aa651cb2e7f46abc083c4318b47e77cd (diff) |
feat(render): draw passes
Diffstat (limited to 'examples/render-quad')
-rw-r--r-- | examples/render-quad/Cargo.toml | 20 | ||||
-rw-r--r-- | examples/render-quad/src/level.rs | 78 | ||||
-rw-r--r-- | examples/render-quad/src/main.rs | 229 |
3 files changed, 327 insertions, 0 deletions
diff --git a/examples/render-quad/Cargo.toml b/examples/render-quad/Cargo.toml new file mode 100644 index 0000000..d32aa6e --- /dev/null +++ b/examples/render-quad/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "render-quad" +version = "0.1.0" +authors = ["Oscar <oscar.shrimpton.personal@gmail.com>"] +edition = "2018" + +[dependencies] +stockton-render = { path = "../../stockton-render", features = ["vulkan"] } +stockton-input = { path = "../../stockton-input" } +stockton-input-codegen = { path = "../../stockton-input-codegen" } +stockton-types = { path = "../../stockton-types" } +stockton-levels = { path = "../../stockton-levels" } +stockton-contrib = { path = "../../stockton-contrib", features = ["delta_time", "flycam"] } +winit = "^0.21" +log = "0.4.0" +simplelog = "^0.10" +image = "0.23.2" +egui = "^0.12" +legion = { version = "^0.3" } +anyhow = "1.0.40" diff --git a/examples/render-quad/src/level.rs b/examples/render-quad/src/level.rs new file mode 100644 index 0000000..d10c3b6 --- /dev/null +++ b/examples/render-quad/src/level.rs @@ -0,0 +1,78 @@ +use stockton_levels::parts::{ + data::{FaceRef, Geometry, TextureRef}, + HasFaces, HasTextures, HasVisData, IsFace, IsTexture, +}; + +pub struct DemoLevel { + pub faces: Box<[Face]>, + pub textures: Box<[Texture]>, +} + +impl DemoLevel { + fn face_idx(&self, search: &Face) -> FaceRef { + for (idx, face) in self.faces.iter().enumerate() { + if face == search { + return idx as u32; + } + } + panic!("face not in level") + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct Face { + pub geometry: Geometry, + pub texture_idx: TextureRef, +} + +impl HasFaces for DemoLevel { + type Face = Face; + + fn get_face(&self, index: FaceRef) -> Option<&Self::Face> { + self.faces.get(index as usize) + } +} + +impl IsFace<DemoLevel> for Face { + fn index(&self, container: &DemoLevel) -> stockton_levels::parts::data::FaceRef { + container.face_idx(self) + } + + fn geometry(&self, _container: &DemoLevel) -> Geometry { + self.geometry.clone() + } + + fn texture_idx(&self, _container: &DemoLevel) -> TextureRef { + self.texture_idx + } +} + +pub struct Texture { + pub name: String, +} + +impl HasTextures for DemoLevel { + type Texture = Texture; + + fn get_texture(&self, idx: TextureRef) -> Option<&Self::Texture> { + self.textures.get(idx as usize) + } +} + +impl IsTexture for Texture { + fn name(&self) -> &str { + &self.name + } +} + +impl<'a> HasVisData<'a> for DemoLevel { + type Faces = std::ops::Range<FaceRef>; + + fn get_visible( + &'a self, + _transform: &stockton_types::components::Transform, + _settings: &stockton_types::components::CameraSettings, + ) -> Self::Faces { + 0..self.faces.len() as u32 + } +} diff --git a/examples/render-quad/src/main.rs b/examples/render-quad/src/main.rs new file mode 100644 index 0000000..b16c3d0 --- /dev/null +++ b/examples/render-quad/src/main.rs @@ -0,0 +1,229 @@ +//! Renders ./example.bsp geometry: (), texture_idx: () geometry: (), texture_idx: () + +#[macro_use] +extern crate stockton_input_codegen; + +#[macro_use] +extern crate legion; + +use anyhow::{Context, Result}; +use log::warn; +use std::collections::BTreeMap; + +use std::sync::{Arc, RwLock}; +use stockton_levels::parts::data::{Geometry, Vertex}; +use stockton_levels::types::Rgba; +use stockton_render::draw::LevelDrawPass; +use winit::{event::Event, event_loop::EventLoop, window::WindowBuilder}; + +use egui::{containers::CentralPanel, Frame}; +use stockton_contrib::delta_time::*; +use stockton_contrib::flycam::*; + +use stockton_input::{Axis, InputManager, Mouse}; + +use stockton_render::error::full_error_display; +use stockton_render::systems::*; +use stockton_render::{Renderer, UiState, WindowEvent}; + +use stockton_types::components::{CameraSettings, CameraVPMatrix, Transform}; +use stockton_types::{Session, Vector2, Vector3}; + +mod level; +use level::*; + +type Dp<'a> = LevelDrawPass<'a, DemoLevel>; + +#[derive(InputManager, Default, Clone, Debug)] +struct MovementInputs { + #[axis] + x: Axis, + + #[axis] + y: Axis, + + #[axis] + z: Axis, +} + +impl FlycamInput for MovementInputs { + fn get_x_axis(&self) -> &Axis { + &self.x + } + fn get_y_axis(&self) -> &Axis { + &self.y + } + fn get_z_axis(&self) -> &Axis { + &self.z + } +} + +#[system] +fn hello_world(#[resource] ui: &mut UiState) { + CentralPanel::default() + .frame(Frame::none()) + .show(ui.ctx(), |ui| { + ui.heading("Hello, World!"); + }); +} + +fn main() { + if let Err(err) = try_main() { + eprintln!("{}", full_error_display(err)); + } +} + +fn try_main<'a>() -> Result<()> { + // Initialise logger + simplelog::TermLogger::init( + log::LevelFilter::Debug, + simplelog::ConfigBuilder::new() + .set_max_level(log::LevelFilter::Debug) + .set_thread_mode(simplelog::ThreadLogMode::Names) + .build(), + simplelog::TerminalMode::Stderr, + simplelog::ColorChoice::Auto, + ) + .context("Error initialising logger")?; + + // Make a window + let event_loop = EventLoop::new(); + let window = WindowBuilder::new() + .build(&event_loop) + .context("Error creating window")?; + + if window.set_cursor_grab(true).is_err() { + warn!("warning: cursor not grabbed"); + } + window.set_cursor_visible(false); + + // TODO: Parse the map file + let map = Arc::new(RwLock::new(DemoLevel { + faces: vec![Face { + geometry: Geometry::Vertices( + Vertex { + position: Vector3::new(-128.0, 128.0, 128.0), + tex: Vector2::new(0.0, 0.0), + color: Rgba::from_slice(&[0, 0, 0, 1]), + }, + Vertex { + position: Vector3::new(-128.0, -128.0, 128.0), + tex: Vector2::new(0.0, 1.0), + color: Rgba::from_slice(&[0, 0, 0, 1]), + }, + Vertex { + position: Vector3::new(128.0, 128.0, 128.0), + tex: Vector2::new(1.0, 0.0), + color: Rgba::from_slice(&[0, 0, 0, 1]), + }, + ), + texture_idx: 0, + }] + .into_boxed_slice(), + textures: vec![Texture { + name: "example_texture".to_string(), + }] + .into_boxed_slice(), + })); + + // Create the UI State + let mut ui = UiState::new(); + + // Create the input manager + let manager = { + use stockton_input::InputMutation::*; + use MovementInputsFields::*; + + let mut actions = BTreeMap::new(); + + actions.insert(17, (Z, PositiveAxis)); // W + actions.insert(30, (X, NegativeAxis)); // A + actions.insert(31, (Z, NegativeAxis)); // S + actions.insert(32, (X, PositiveAxis)); // D + actions.insert(29, (Y, NegativeAxis)); // Ctrl + actions.insert(57, (Y, PositiveAxis)); // Space + + MovementInputsManager::new(actions) + }; + + let ratio = window.inner_size().width as f32 / window.inner_size().height as f32; + + // Load everything into the session + let mut session = Session::new( + move |resources| { + resources.insert(map); + resources.insert(manager); + resources.insert(Timing::default()); + resources.insert(Mouse::default()); + }, + move |schedule| { + schedule + .add_system(update_deltatime_system()) + .add_system(process_window_events_system::< + MovementInputsManager, + Dp<'static>, + >()) + .flush() + .add_system(hello_world_system()) + .add_system(flycam_move_system::<MovementInputsManager>()) + .flush() + .add_thread_local(calc_vp_matrix_system(ratio)); + }, + ); + + // Add our player entity + let player = session.world.push(( + Transform { + position: Vector3::new(0.0, 0.0, 0.0), + rotation: Vector3::new(0.0, 0.0, 0.0), + }, + CameraSettings { + far: 1024.0, + fov: 90.0, + near: 0.1, + }, + CameraVPMatrix::default(), + FlycamControlled::new(512.0, 400.0), + )); + + // Create the renderer + let (renderer, tx): (Renderer<Dp<'static>>, _) = Renderer::new(&window, &session, player)?; + let new_control_flow = renderer.update_control_flow.clone(); + + // Populate the initial UI state + ui.populate_initial_state(&renderer); + + session.resources.insert(renderer); + session.resources.insert(ui); + + // Done loading - This is our main loop. + // It just communicates events to the session and continuously ticks + event_loop.run(move |event, _, flow| { + match event { + Event::MainEventsCleared => { + window.request_redraw(); + } + Event::RedrawRequested(_) => { + session.do_update(); + let mut renderer = session + .resources + .get_mut::<Renderer<Dp<'static>>>() + .unwrap(); + renderer.render(&session).unwrap(); + } + _ => { + if let Some(we) = WindowEvent::from(&event) { + tx.send(we).unwrap() + } + } + } + + // Update the control flow if the session has requested it. + { + let new_control_flow = new_control_flow.read().unwrap(); + if *new_control_flow != *flow { + *flow = *new_control_flow; + } + }; + }); +} |