From e59ebea30411c615f9b8e4777078ff617bb96333 Mon Sep 17 00:00:00 2001 From: Jeffrey Skinner Date: Mon, 11 Sep 2023 05:26:02 +0900 Subject: [PATCH] framework.rs -> lib.rs, smaller binary flags, removed dependencies and standard main function --- .gitignore | 3 +- Cargo.toml | 13 +- CONTRIBUTING.md => contributing.md | 0 LICENSE => license.txt | 0 README.md => readme.md | 2 +- src/framework.rs | 516 ----------------------------- src/lib.rs | 415 ++++++++++++++++++++++- src/main.rs | 181 +++++++++- std/lib.rs | 8 + 9 files changed, 603 insertions(+), 535 deletions(-) rename CONTRIBUTING.md => contributing.md (100%) rename LICENSE => license.txt (100%) rename README.md => readme.md (91%) delete mode 100644 src/framework.rs create mode 100644 std/lib.rs diff --git a/.gitignore b/.gitignore index ea8c4bf..b354aec 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/target +Cargo.lock +target/ \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 5a9789d..782f565 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,23 +1,24 @@ [package] name = "strafe-client" -version = "0.2.0" +version = "0.2.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] async-executor = "1.5.1" -bytemuck = { version = "1.13.1", features = ["derive"] } +bytemuck = { version = "1.14.0", features = ["derive"] } ddsfile = "0.5.1" -env_logger = "0.10.0" glam = "0.24.1" -log = "0.4.20" +logga = "0.1.2" obj = "0.10.2" pollster = "0.3.0" wgpu = "0.17.0" winit = "0.28.6" [profile.release] -lto = true -strip = true codegen-units = 1 +lto = true +opt-level = "z" +panic = "abort" +strip = true \ No newline at end of file diff --git a/CONTRIBUTING.md b/contributing.md similarity index 100% rename from CONTRIBUTING.md rename to contributing.md diff --git a/LICENSE b/license.txt similarity index 100% rename from LICENSE rename to license.txt diff --git a/README.md b/readme.md similarity index 91% rename from README.md rename to readme.md index d7c1688..2622472 100644 --- a/README.md +++ b/readme.md @@ -7,4 +7,4 @@ In development client for jumping on squares (and riding on triangles) 1. Have rust and git installed 2. `git clone https://git.itzana.me/StrafesNET/strafe-client` 3. `cd strafe-client` -4. `cargo run --release` +4. `cargo run --release` \ No newline at end of file diff --git a/src/framework.rs b/src/framework.rs deleted file mode 100644 index d18609f..0000000 --- a/src/framework.rs +++ /dev/null @@ -1,516 +0,0 @@ -use std::future::Future; -#[cfg(target_arch = "wasm32")] -use std::str::FromStr; -#[cfg(not(target_arch = "wasm32"))] -use std::time::Instant; -#[cfg(target_arch = "wasm32")] -use web_sys::{ImageBitmapRenderingContext, OffscreenCanvas}; -use winit::{ - event::{self, WindowEvent}, - event_loop::{ControlFlow, EventLoop}, -}; - -#[allow(dead_code)] -pub fn cast_slice(data: &[T]) -> &[u8] { - use std::{mem::size_of, slice::from_raw_parts}; - - unsafe { from_raw_parts(data.as_ptr() as *const u8, data.len() * size_of::()) } -} - -#[allow(dead_code)] -pub enum ShaderStage { - Vertex, - Fragment, - Compute, -} - -pub trait Example: 'static + Sized { - fn optional_features() -> wgpu::Features { - wgpu::Features::empty() - } - fn required_features() -> wgpu::Features { - wgpu::Features::empty() - } - fn required_downlevel_capabilities() -> wgpu::DownlevelCapabilities { - wgpu::DownlevelCapabilities { - flags: wgpu::DownlevelFlags::empty(), - shader_model: wgpu::ShaderModel::Sm5, - ..wgpu::DownlevelCapabilities::default() - } - } - fn required_limits() -> wgpu::Limits { - wgpu::Limits::downlevel_webgl2_defaults() // These downlevel limits will allow the code to run on all possible hardware - } - fn init( - config: &wgpu::SurfaceConfiguration, - adapter: &wgpu::Adapter, - device: &wgpu::Device, - queue: &wgpu::Queue, - ) -> Self; - fn resize( - &mut self, - config: &wgpu::SurfaceConfiguration, - device: &wgpu::Device, - queue: &wgpu::Queue, - ); - fn update(&mut self, event: WindowEvent); - fn move_mouse(&mut self, delta: (f64,f64)); - fn render( - &mut self, - view: &wgpu::TextureView, - device: &wgpu::Device, - queue: &wgpu::Queue, - spawner: &Spawner, - ); -} - -struct Setup { - window: winit::window::Window, - event_loop: EventLoop<()>, - instance: wgpu::Instance, - size: winit::dpi::PhysicalSize, - surface: wgpu::Surface, - adapter: wgpu::Adapter, - device: wgpu::Device, - queue: wgpu::Queue, - #[cfg(target_arch = "wasm32")] - offscreen_canvas_setup: Option, -} - -#[cfg(target_arch = "wasm32")] -struct OffscreenCanvasSetup { - offscreen_canvas: OffscreenCanvas, - bitmap_renderer: ImageBitmapRenderingContext, -} - -async fn setup(title: &str) -> Setup { - #[cfg(not(target_arch = "wasm32"))] - { - env_logger::init(); - }; - - let event_loop = EventLoop::new(); - let mut builder = winit::window::WindowBuilder::new(); - builder = builder.with_title(title); - #[cfg(windows_OFF)] // TODO - { - use winit::platform::windows::WindowBuilderExtWindows; - builder = builder.with_no_redirection_bitmap(true); - } - let window = builder.build(&event_loop).unwrap(); - - #[cfg(target_arch = "wasm32")] - { - use winit::platform::web::WindowExtWebSys; - let query_string = web_sys::window().unwrap().location().search().unwrap(); - let level: log::Level = parse_url_query_string(&query_string, "RUST_LOG") - .and_then(|x| x.parse().ok()) - .unwrap_or(log::Level::Error); - console_log::init_with_level(level).expect("could not initialize logger"); - std::panic::set_hook(Box::new(console_error_panic_hook::hook)); - // On wasm, append the canvas to the document body - web_sys::window() - .and_then(|win| win.document()) - .and_then(|doc| doc.body()) - .and_then(|body| { - body.append_child(&web_sys::Element::from(window.canvas())) - .ok() - }) - .expect("couldn't append canvas to document body"); - } - - #[cfg(target_arch = "wasm32")] - let mut offscreen_canvas_setup: Option = None; - #[cfg(target_arch = "wasm32")] - { - use wasm_bindgen::JsCast; - use winit::platform::web::WindowExtWebSys; - - let query_string = web_sys::window().unwrap().location().search().unwrap(); - if let Some(offscreen_canvas_param) = - parse_url_query_string(&query_string, "offscreen_canvas") - { - if FromStr::from_str(offscreen_canvas_param) == Ok(true) { - log::info!("Creating OffscreenCanvasSetup"); - - let offscreen_canvas = - OffscreenCanvas::new(1024, 768).expect("couldn't create OffscreenCanvas"); - - let bitmap_renderer = window - .canvas() - .get_context("bitmaprenderer") - .expect("couldn't create ImageBitmapRenderingContext (Result)") - .expect("couldn't create ImageBitmapRenderingContext (Option)") - .dyn_into::() - .expect("couldn't convert into ImageBitmapRenderingContext"); - - offscreen_canvas_setup = Some(OffscreenCanvasSetup { - offscreen_canvas, - bitmap_renderer, - }) - } - } - }; - - log::info!("Initializing the surface..."); - - let backends = wgpu::util::backend_bits_from_env().unwrap_or_else(wgpu::Backends::all); - let dx12_shader_compiler = wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(); - - let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { - backends, - dx12_shader_compiler, - }); - let (size, surface) = unsafe { - let size = window.inner_size(); - - #[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))] - let surface = instance.create_surface(&window).unwrap(); - #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] - let surface = { - if let Some(offscreen_canvas_setup) = &offscreen_canvas_setup { - log::info!("Creating surface from OffscreenCanvas"); - instance.create_surface_from_offscreen_canvas( - offscreen_canvas_setup.offscreen_canvas.clone(), - ) - } else { - instance.create_surface(&window) - } - } - .unwrap(); - - (size, surface) - }; - let adapter = wgpu::util::initialize_adapter_from_env_or_default(&instance, Some(&surface)) - .await - .expect("No suitable GPU adapters found on the system!"); - - #[cfg(not(target_arch = "wasm32"))] - { - let adapter_info = adapter.get_info(); - println!("Using {} ({:?})", adapter_info.name, adapter_info.backend); - } - - let optional_features = E::optional_features(); - let required_features = E::required_features(); - let adapter_features = adapter.features(); - assert!( - adapter_features.contains(required_features), - "Adapter does not support required features for this example: {:?}", - required_features - adapter_features - ); - - let required_downlevel_capabilities = E::required_downlevel_capabilities(); - let downlevel_capabilities = adapter.get_downlevel_capabilities(); - assert!( - downlevel_capabilities.shader_model >= required_downlevel_capabilities.shader_model, - "Adapter does not support the minimum shader model required to run this example: {:?}", - required_downlevel_capabilities.shader_model - ); - assert!( - downlevel_capabilities - .flags - .contains(required_downlevel_capabilities.flags), - "Adapter does not support the downlevel capabilities required to run this example: {:?}", - required_downlevel_capabilities.flags - downlevel_capabilities.flags - ); - - // Make sure we use the texture resolution limits from the adapter, so we can support images the size of the surface. - let needed_limits = E::required_limits().using_resolution(adapter.limits()); - - let trace_dir = std::env::var("WGPU_TRACE"); - let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: None, - features: (optional_features & adapter_features) | required_features, - limits: needed_limits, - }, - trace_dir.ok().as_ref().map(std::path::Path::new), - ) - .await - .expect("Unable to find a suitable GPU adapter!"); - - Setup { - window, - event_loop, - instance, - size, - surface, - adapter, - device, - queue, - #[cfg(target_arch = "wasm32")] - offscreen_canvas_setup, - } -} - -fn start( - #[cfg(not(target_arch = "wasm32"))] Setup { - window, - event_loop, - instance, - size, - surface, - adapter, - device, - queue, - }: Setup, - #[cfg(target_arch = "wasm32")] Setup { - window, - event_loop, - instance, - size, - surface, - adapter, - device, - queue, - offscreen_canvas_setup, - }: Setup, -) { - let spawner = Spawner::new(); - let mut config = surface - .get_default_config(&adapter, size.width, size.height) - .expect("Surface isn't supported by the adapter."); - let surface_view_format = config.format.add_srgb_suffix(); - config.view_formats.push(surface_view_format); - surface.configure(&device, &config); - - log::info!("Initializing the example..."); - let mut example = E::init(&config, &adapter, &device, &queue); - - #[cfg(not(target_arch = "wasm32"))] - let mut last_frame_inst = Instant::now(); - #[cfg(not(target_arch = "wasm32"))] - let (mut frame_count, mut accum_time) = (0, 0.0); - - log::info!("Entering render loop..."); - event_loop.run(move |event, _, control_flow| { - let _ = (&instance, &adapter); // force ownership by the closure - *control_flow = if cfg!(feature = "metal-auto-capture") { - ControlFlow::Exit - } else { - ControlFlow::Poll - }; - match event { - event::Event::RedrawEventsCleared => { - #[cfg(not(target_arch = "wasm32"))] - spawner.run_until_stalled(); - - window.request_redraw(); - } - event::Event::WindowEvent { - event: - WindowEvent::Resized(size) - | WindowEvent::ScaleFactorChanged { - new_inner_size: &mut size, - .. - }, - .. - } => { - // Once winit is fixed, the detection conditions here can be removed. - // https://github.com/rust-windowing/winit/issues/2876 - let max_dimension = adapter.limits().max_texture_dimension_2d; - if size.width > max_dimension || size.height > max_dimension { - log::warn!( - "The resizing size {:?} exceeds the limit of {}.", - size, - max_dimension - ); - } else { - log::info!("Resizing to {:?}", size); - config.width = size.width.max(1); - config.height = size.height.max(1); - example.resize(&config, &device, &queue); - surface.configure(&device, &config); - } - } - event::Event::WindowEvent { event, .. } => match event { - WindowEvent::KeyboardInput { - input: - event::KeyboardInput { - virtual_keycode: Some(event::VirtualKeyCode::Escape), - state: event::ElementState::Pressed, - .. - }, - .. - } - | WindowEvent::CloseRequested => { - *control_flow = ControlFlow::Exit; - } - #[cfg(not(target_arch = "wasm32"))] - WindowEvent::KeyboardInput { - input: - event::KeyboardInput { - virtual_keycode: Some(event::VirtualKeyCode::R), - state: event::ElementState::Pressed, - .. - }, - .. - } => { - println!("{:#?}", instance.generate_report()); - } - _ => { - example.update(event); - } - }, - event::Event::DeviceEvent { - event: - winit::event::DeviceEvent::MouseMotion { - delta, - }, - .. - } => { - example.move_mouse(delta); - }, - event::Event::RedrawRequested(_) => { - #[cfg(not(target_arch = "wasm32"))] - { - accum_time += last_frame_inst.elapsed().as_secs_f32(); - last_frame_inst = Instant::now(); - frame_count += 1; - if frame_count == 100 { - println!( - "Avg frame time {}ms", - accum_time * 1000.0 / frame_count as f32 - ); - accum_time = 0.0; - frame_count = 0; - } - } - - let frame = match surface.get_current_texture() { - Ok(frame) => frame, - Err(_) => { - surface.configure(&device, &config); - surface - .get_current_texture() - .expect("Failed to acquire next surface texture!") - } - }; - let view = frame.texture.create_view(&wgpu::TextureViewDescriptor { - format: Some(surface_view_format), - ..wgpu::TextureViewDescriptor::default() - }); - - example.render(&view, &device, &queue, &spawner); - - frame.present(); - - #[cfg(target_arch = "wasm32")] - { - if let Some(offscreen_canvas_setup) = &offscreen_canvas_setup { - let image_bitmap = offscreen_canvas_setup - .offscreen_canvas - .transfer_to_image_bitmap() - .expect("couldn't transfer offscreen canvas to image bitmap."); - offscreen_canvas_setup - .bitmap_renderer - .transfer_from_image_bitmap(&image_bitmap); - - log::info!("Transferring OffscreenCanvas to ImageBitmapRenderer"); - } - } - } - _ => {} - } - }); -} - -#[cfg(not(target_arch = "wasm32"))] -pub struct Spawner<'a> { - executor: async_executor::LocalExecutor<'a>, -} - -#[cfg(not(target_arch = "wasm32"))] -impl<'a> Spawner<'a> { - fn new() -> Self { - Self { - executor: async_executor::LocalExecutor::new(), - } - } - - #[allow(dead_code)] - pub fn spawn_local(&self, future: impl Future + 'a) { - self.executor.spawn(future).detach(); - } - - fn run_until_stalled(&self) { - while self.executor.try_tick() {} - } -} - -#[cfg(target_arch = "wasm32")] -pub struct Spawner {} - -#[cfg(target_arch = "wasm32")] -impl Spawner { - fn new() -> Self { - Self {} - } - - #[allow(dead_code)] - pub fn spawn_local(&self, future: impl Future + 'static) { - wasm_bindgen_futures::spawn_local(future); - } -} - -#[cfg(not(target_arch = "wasm32"))] -pub fn run(title: &str) { - let setup = pollster::block_on(setup::(title)); - start::(setup); -} - -#[cfg(target_arch = "wasm32")] -pub fn run(title: &str) { - use wasm_bindgen::prelude::*; - - let title = title.to_owned(); - wasm_bindgen_futures::spawn_local(async move { - let setup = setup::(&title).await; - let start_closure = Closure::once_into_js(move || start::(setup)); - - // make sure to handle JS exceptions thrown inside start. - // Otherwise wasm_bindgen_futures Queue would break and never handle any tasks again. - // This is required, because winit uses JS exception for control flow to escape from `run`. - if let Err(error) = call_catch(&start_closure) { - let is_control_flow_exception = error.dyn_ref::().map_or(false, |e| { - e.message().includes("Using exceptions for control flow", 0) - }); - - if !is_control_flow_exception { - web_sys::console::error_1(&error); - } - } - - #[wasm_bindgen] - extern "C" { - #[wasm_bindgen(catch, js_namespace = Function, js_name = "prototype.call.call")] - fn call_catch(this: &JsValue) -> Result<(), JsValue>; - } - }); -} - -#[cfg(target_arch = "wasm32")] -/// Parse the query string as returned by `web_sys::window()?.location().search()?` and get a -/// specific key out of it. -pub fn parse_url_query_string<'a>(query: &'a str, search_key: &str) -> Option<&'a str> { - let query_string = query.strip_prefix('?')?; - - for pair in query_string.split('&') { - let mut pair = pair.split('='); - let key = pair.next()?; - let value = pair.next()?; - - if key == search_key { - return Some(value); - } - } - - None -} - -// This allows treating the framework as a standalone example, -// thus avoiding listing the example names in `Cargo.toml`. -#[allow(dead_code)] -fn main() {} diff --git a/src/lib.rs b/src/lib.rs index 0c71749..940c819 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,414 @@ -pub mod framework; +#[cfg(not(target_arch = "wasm32"))] +use std::time::Instant; +use winit::{ + event::{self, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, +}; +use logga; + +#[allow(dead_code)] +pub fn cast_slice(data: &[T]) -> &[u8] { + use std::{mem::size_of, slice::from_raw_parts}; + + unsafe { from_raw_parts(data.as_ptr() as *const u8, data.len() * size_of::()) } +} + +#[allow(dead_code)] +pub enum ShaderStage { + Vertex, + Fragment, + Compute, +} + +pub trait Example: 'static + Sized { + fn optional_features() -> wgpu::Features { + wgpu::Features::empty() + } + fn required_features() -> wgpu::Features { + wgpu::Features::empty() + } + fn required_downlevel_capabilities() -> wgpu::DownlevelCapabilities { + wgpu::DownlevelCapabilities { + flags: wgpu::DownlevelFlags::empty(), + shader_model: wgpu::ShaderModel::Sm5, + ..wgpu::DownlevelCapabilities::default() + } + } + fn required_limits() -> wgpu::Limits { + wgpu::Limits::downlevel_webgl2_defaults() // These downlevel limits will allow the code to run on all possible hardware + } + fn init( + config: &wgpu::SurfaceConfiguration, + adapter: &wgpu::Adapter, + device: &wgpu::Device, + queue: &wgpu::Queue, + ) -> Self; + fn resize( + &mut self, + config: &wgpu::SurfaceConfiguration, + device: &wgpu::Device, + queue: &wgpu::Queue, + ); + fn update(&mut self, event: WindowEvent); + fn move_mouse(&mut self, delta: (f64,f64)); + fn render( + &mut self, + view: &wgpu::TextureView, + device: &wgpu::Device, + queue: &wgpu::Queue, + ); +} + +struct Setup { + window: winit::window::Window, + event_loop: EventLoop<()>, + instance: wgpu::Instance, + size: winit::dpi::PhysicalSize, + surface: wgpu::Surface, + adapter: wgpu::Adapter, + device: wgpu::Device, + queue: wgpu::Queue, + #[cfg(target_arch = "wasm32")] + offscreen_canvas_setup: Option, +} + +#[cfg(target_arch = "wasm32")] +struct OffscreenCanvasSetup { + offscreen_canvas: OffscreenCanvas, + bitmap_renderer: ImageBitmapRenderingContext, +} + +async fn setup(title: &str) -> Setup { + //logga::init(); + + let event_loop = EventLoop::new(); + let mut builder = winit::window::WindowBuilder::new(); + builder = builder.with_title(title); + #[cfg(windows_OFF)] // TODO + { + use winit::platform::windows::WindowBuilderExtWindows; + builder = builder.with_no_redirection_bitmap(true); + } + let window = builder.build(&event_loop).unwrap(); + + #[cfg(target_arch = "wasm32")] + { + use winit::platform::web::WindowExtWebSys; + let query_string = web_sys::window().unwrap().location().search().unwrap(); + let level: log::Level = parse_url_query_string(&query_string, "RUST_LOG") + .and_then(|x| x.parse().ok()) + .unwrap_or(log::Level::Error); + console_log::init_with_level(level).expect("could not initialize logger"); + std::panic::set_hook(Box::new(console_error_panic_hook::hook)); + // On wasm, append the canvas to the document body + web_sys::window() + .and_then(|win| win.document()) + .and_then(|doc| doc.body()) + .and_then(|body| { + body.append_child(&web_sys::Element::from(window.canvas())) + .ok() + }) + .expect("couldn't append canvas to document body"); + } + + #[cfg(target_arch = "wasm32")] + let mut offscreen_canvas_setup: Option = None; + #[cfg(target_arch = "wasm32")] + { + use wasm_bindgen::JsCast; + use winit::platform::web::WindowExtWebSys; + + let query_string = web_sys::window().unwrap().location().search().unwrap(); + if let Some(offscreen_canvas_param) = + parse_url_query_string(&query_string, "offscreen_canvas") + { + if FromStr::from_str(offscreen_canvas_param) == Ok(true) { + logga::info!("Creating OffscreenCanvasSetup"); + + let offscreen_canvas = + OffscreenCanvas::new(1024, 768).expect("couldn't create OffscreenCanvas"); + + let bitmap_renderer = window + .canvas() + .get_context("bitmaprenderer") + .expect("couldn't create ImageBitmapRenderingContext (Result)") + .expect("couldn't create ImageBitmapRenderingContext (Option)") + .dyn_into::() + .expect("couldn't convert into ImageBitmapRenderingContext"); + + offscreen_canvas_setup = Some(OffscreenCanvasSetup { + offscreen_canvas, + bitmap_renderer, + }) + } + } + }; + + logga::info!("Initializing the surface..."); + + let backends = wgpu::util::backend_bits_from_env().unwrap_or_else(wgpu::Backends::all); + let dx12_shader_compiler = wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(); + + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends, + dx12_shader_compiler, + }); + let (size, surface) = unsafe { + let size = window.inner_size(); + + #[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))] + let surface = instance.create_surface(&window).unwrap(); + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] + let surface = { + if let Some(offscreen_canvas_setup) = &offscreen_canvas_setup { + logga::info!("Creating surface from OffscreenCanvas"); + instance.create_surface_from_offscreen_canvas( + offscreen_canvas_setup.offscreen_canvas.clone(), + ) + } else { + instance.create_surface(&window) + } + } + .unwrap(); + + (size, surface) + }; + let adapter = wgpu::util::initialize_adapter_from_env_or_default(&instance, Some(&surface)) + .await + .expect("No suitable GPU adapters found on the system!"); + + #[cfg(not(target_arch = "wasm32"))] + { + let adapter_info = adapter.get_info(); + println!("Using {} ({:?})", adapter_info.name, adapter_info.backend); + } + + let optional_features = E::optional_features(); + let required_features = E::required_features(); + let adapter_features = adapter.features(); + assert!( + adapter_features.contains(required_features), + "Adapter does not support required features for this example: {:?}", + required_features - adapter_features + ); + + let required_downlevel_capabilities = E::required_downlevel_capabilities(); + let downlevel_capabilities = adapter.get_downlevel_capabilities(); + assert!( + downlevel_capabilities.shader_model >= required_downlevel_capabilities.shader_model, + "Adapter does not support the minimum shader model required to run this example: {:?}", + required_downlevel_capabilities.shader_model + ); + assert!( + downlevel_capabilities + .flags + .contains(required_downlevel_capabilities.flags), + "Adapter does not support the downlevel capabilities required to run this example: {:?}", + required_downlevel_capabilities.flags - downlevel_capabilities.flags + ); + + // Make sure we use the texture resolution limits from the adapter, so we can support images the size of the surface. + let needed_limits = E::required_limits().using_resolution(adapter.limits()); + + let trace_dir = std::env::var("WGPU_TRACE"); + let (device, queue) = adapter + .request_device( + &wgpu::DeviceDescriptor { + label: None, + features: (optional_features & adapter_features) | required_features, + limits: needed_limits, + }, + trace_dir.ok().as_ref().map(std::path::Path::new), + ) + .await + .expect("Unable to find a suitable GPU adapter!"); + + Setup { + window, + event_loop, + instance, + size, + surface, + adapter, + device, + queue, + #[cfg(target_arch = "wasm32")] + offscreen_canvas_setup, + } +} + +fn start( + #[cfg(not(target_arch = "wasm32"))] Setup { + window, + event_loop, + instance, + size, + surface, + adapter, + device, + queue, + }: Setup, + #[cfg(target_arch = "wasm32")] Setup { + window, + event_loop, + instance, + size, + surface, + adapter, + device, + queue, + offscreen_canvas_setup, + }: Setup, +) { + let mut config = surface + .get_default_config(&adapter, size.width, size.height) + .expect("Surface isn't supported by the adapter."); + let surface_view_format = config.format.add_srgb_suffix(); + config.view_formats.push(surface_view_format); + surface.configure(&device, &config); + + logga::info!("Initializing the example..."); + let mut example = E::init(&config, &adapter, &device, &queue); + + #[cfg(not(target_arch = "wasm32"))] + let mut last_frame_inst = Instant::now(); + #[cfg(not(target_arch = "wasm32"))] + let (mut frame_count, mut accum_time) = (0, 0.0); + + logga::info!("Entering render loop..."); + event_loop.run(move |event, _, control_flow| { + let _ = (&instance, &adapter); // force ownership by the closure + *control_flow = if cfg!(feature = "metal-auto-capture") { + ControlFlow::Exit + } else { + ControlFlow::Poll + }; + match event { + event::Event::RedrawEventsCleared => { + #[cfg(not(target_arch = "wasm32"))] + + window.request_redraw(); + } + event::Event::WindowEvent { + event: + WindowEvent::Resized(size) + | WindowEvent::ScaleFactorChanged { + new_inner_size: &mut size, + .. + }, + .. + } => { + // Once winit is fixed, the detection conditions here can be removed. + // https://github.com/rust-windowing/winit/issues/2876 + let max_dimension = adapter.limits().max_texture_dimension_2d; + if size.width > max_dimension || size.height > max_dimension { + logga::warn!( + "The resizing size {:?} exceeds the limit of {}.", + size, + max_dimension + ); + } else { + logga::info!("Resizing to {:?}", size); + config.width = size.width.max(1); + config.height = size.height.max(1); + example.resize(&config, &device, &queue); + surface.configure(&device, &config); + } + } + event::Event::WindowEvent { event, .. } => match event { + WindowEvent::KeyboardInput { + input: + event::KeyboardInput { + virtual_keycode: Some(event::VirtualKeyCode::Escape), + state: event::ElementState::Pressed, + .. + }, + .. + } + | WindowEvent::CloseRequested => { + *control_flow = ControlFlow::Exit; + } + #[cfg(not(target_arch = "wasm32"))] + WindowEvent::KeyboardInput { + input: + event::KeyboardInput { + virtual_keycode: Some(event::VirtualKeyCode::R), + state: event::ElementState::Pressed, + .. + }, + .. + } => { + println!("{:#?}", instance.generate_report()); + } + _ => { + example.update(event); + } + }, + event::Event::DeviceEvent { + event: + winit::event::DeviceEvent::MouseMotion { + delta, + }, + .. + } => { + example.move_mouse(delta); + }, + event::Event::RedrawRequested(_) => { + #[cfg(not(target_arch = "wasm32"))] + { + accum_time += last_frame_inst.elapsed().as_secs_f32(); + last_frame_inst = Instant::now(); + frame_count += 1; + if frame_count == 100 { + println!( + "Avg frame time {}ms", + accum_time * 1000.0 / frame_count as f32 + ); + accum_time = 0.0; + frame_count = 0; + } + } + + let frame = match surface.get_current_texture() { + Ok(frame) => frame, + Err(_) => { + surface.configure(&device, &config); + surface + .get_current_texture() + .expect("Failed to acquire next surface texture!") + } + }; + let view = frame.texture.create_view(&wgpu::TextureViewDescriptor { + format: Some(surface_view_format), + ..wgpu::TextureViewDescriptor::default() + }); + + example.render(&view, &device, &queue); + + frame.present(); + + #[cfg(target_arch = "wasm32")] + { + if let Some(offscreen_canvas_setup) = &offscreen_canvas_setup { + let image_bitmap = offscreen_canvas_setup + .offscreen_canvas + .transfer_to_image_bitmap() + .expect("couldn't transfer offscreen canvas to image bitmap."); + offscreen_canvas_setup + .bitmap_renderer + .transfer_from_image_bitmap(&image_bitmap); + + logga::info!("Transferring OffscreenCanvas to ImageBitmapRenderer"); + } + } + } + _ => {} + } + }); +} + +#[cfg(not(target_arch = "wasm32"))] +pub fn run(title: &str) { + let setup = pollster::block_on(setup::(title)); + start::(setup); +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 720fa6e..6c30916 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,163 @@ +//#![no_std] +#![no_main] + + + + + + + + + + + + + + + + +// I'm trying to replace the stdlib functions so don't delete this yet +/* +extern crate std; +use std::*; + + + +pub struct Vec { + data: [T; 16], + len: usize, +} +impl Vec { + pub fn new() -> Self { + Vec { + data: Default::default(), + len: 0, + } + } + + pub fn push(&mut self, value: T) -> Result<(), &'static str> { + if self.len < self.data.len() { + self.data[self.len] = value; + self.len += 1; + Ok(()) + } else { + Err("Vec is full") + } + } + + pub fn pop(&mut self) -> Option { + if self.len > 0 { + self.len -= 1; + Some(std::mem::replace(&mut self.data[self.len], Default::default())) + } else { + None + } + } + + pub fn len(&self) -> usize { + self.len + } + + pub fn capacity(&self) -> usize { + self.data.len() + } + + pub fn is_empty(&self) -> bool { + self.len == 0 + } +} + +pub struct Iter<'a, T> { + vec: &'a Vec, + index: usize, +} + +impl<'a, T> Vec { + // ... previous methods ... + + pub fn iter(&'a self) -> Iter<'a, T> { + Iter { + vec: self, + index: 0, + } + } +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + if self.index < self.vec.len { + let item = &self.vec.data[self.index]; + self.index += 1; + Some(item) + } else { + None + } + } +} + + + + + + + + + +impl Vec { + // (Previous methods omitted for brevity) + + pub fn drain(&mut self, range: std::ops::Range) -> Drain { + Drain { + vec: self, + range, + } + } +} + +pub struct Drain<'a, T> { + vec: &'a mut Vec, + range: std::ops::Range, +} + +impl<'a, T> Iterator for Drain<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + if let Some(index) = self.range.next_back() { + if index < self.vec.len { + // Swap and remove the element from the Vec + let last_index = self.vec.len - 1; + self.vec.len -= 1; + Some(std::mem::replace(&mut self.vec.data[index], Default::default())) + } else { + None + } + } else { + None + } + } +} +*/ + + + + +//extern crate logga; +//extern crate libc; + +/* +#[panic_handler] +fn my_panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} +*/ + + + + +//use logga; use bytemuck::{Pod, Zeroable}; use std::{borrow::Cow, time::Instant}; use wgpu::{util::DeviceExt, AstcBlock, AstcChannel}; @@ -215,7 +375,7 @@ fn add_obj(device:&wgpu::Device,modeldatas:& mut Vec,source:&[u8]){ } } -impl strafe_client::framework::Example for Skybox { +impl strafe_client::Example for Skybox { fn optional_features() -> wgpu::Features { wgpu::Features::TEXTURE_COMPRESSION_ASTC | wgpu::Features::TEXTURE_COMPRESSION_ETC2 @@ -419,19 +579,19 @@ impl strafe_client::framework::Example for Skybox { let device_features = device.features(); let skybox_format = if device_features.contains(wgpu::Features::TEXTURE_COMPRESSION_ASTC) { - log::info!("Using ASTC"); + logga::info!("Using ASTC"); wgpu::TextureFormat::Astc { block: AstcBlock::B4x4, channel: AstcChannel::UnormSrgb, } } else if device_features.contains(wgpu::Features::TEXTURE_COMPRESSION_ETC2) { - log::info!("Using ETC2"); + logga::info!("Using ETC2"); wgpu::TextureFormat::Etc2Rgb8UnormSrgb } else if device_features.contains(wgpu::Features::TEXTURE_COMPRESSION_BC) { - log::info!("Using BC"); + logga::info!("Using BC"); wgpu::TextureFormat::Bc1RgbaUnormSrgb } else { - log::info!("Using plain"); + logga::info!("Using plain"); wgpu::TextureFormat::Bgra8UnormSrgb }; @@ -447,7 +607,7 @@ impl strafe_client::framework::Example for Skybox { }; let max_mips = layer_size.max_mips(wgpu::TextureDimension::D2); - log::debug!( + logga::debug!( "Copying {:?} skybox images of size {}, {}, 6 with {} mips to gpu", skybox_format, IMAGE_SIZE, @@ -623,7 +783,6 @@ impl strafe_client::framework::Example for Skybox { view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue, - _spawner: &strafe_client::framework::Spawner, ) { let time = Instant::now(); @@ -741,10 +900,12 @@ impl strafe_client::framework::Example for Skybox { } } -fn main() { - strafe_client::framework::run::( + +#[no_mangle] +fn main(_argc: isize, _argv: *const *const u8) { + strafe_client::run::( format!("Strafe Client v{}", env!("CARGO_PKG_VERSION") ).as_str() ); -} +} \ No newline at end of file diff --git a/std/lib.rs b/std/lib.rs new file mode 100644 index 0000000..18efefe --- /dev/null +++ b/std/lib.rs @@ -0,0 +1,8 @@ +#[export_macro] +macro_rules! insssfo { + ($($arg:tt)*) => { + }; +} + + +