From 5f538de605d878f027968ada467eb628e348d3cf Mon Sep 17 00:00:00 2001 From: Chance Date: Sat, 29 Mar 2025 01:31:16 -0400 Subject: [PATCH] load arbitrary model data --- .cargo/config.toml | 3 + Cargo.lock | 20 ++ Cargo.toml | 10 +- engine/Cargo.toml | 5 +- engine/src/bint.rs | 334 +++++++++++++++++++ engine/src/core/panic.rs | 79 +++-- engine/src/core/render/ctx.rs | 605 +++++++++++++++++++--------------- engine/src/core/render/mod.rs | 210 +++++++++++- engine/src/main.rs | 2 + test.mtl | 2 + 10 files changed, 956 insertions(+), 314 deletions(-) create mode 100644 engine/src/bint.rs create mode 100644 test.mtl diff --git a/.cargo/config.toml b/.cargo/config.toml index ae0e944..3926aa5 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1 +1,4 @@ [alias] + +[build] +rustflags = ["-Ctarget-cpu=native"] diff --git a/Cargo.lock b/Cargo.lock index a86f202..a0be063 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2188,6 +2188,16 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tobj" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04aca6092e5978e708ee784e8ab9b5cf3cdb598b28f99a2f257446e7081a7025" +dependencies = [ + "ahash", + "tokio", +] + [[package]] name = "tokio" version = "1.44.1" @@ -2195,6 +2205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" dependencies = [ "backtrace", + "bytes", "parking_lot", "pin-project-lite", "tokio-macros", @@ -2291,6 +2302,12 @@ version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -3181,6 +3198,7 @@ dependencies = [ name = "zenyx" version = "0.1.0" dependencies = [ + "ahash", "anyhow", "backtrace", "bytemuck", @@ -3196,9 +3214,11 @@ dependencies = [ "regex", "rustyline", "thiserror 2.0.12", + "tobj", "tokio", "tracing", "tracing-subscriber", + "typenum", "wgpu", "winit", ] diff --git a/Cargo.toml b/Cargo.toml index cb0f4ce..28987ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,12 +27,7 @@ codegen-units = 512 strip = "symbols" debug-assertions = true -[profile.dev.build-override] -opt-level = 0 -debug = false -overflow-checks = false -incremental = true -codegen-units = 512 + [workspace.dependencies] lazy_static = "1.5.0" @@ -40,3 +35,6 @@ parking_lot = "0.12.3" [profile.release] debug-assertions = false +lto = true +codegen-units = 1 +panic = "abort" diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 32e799f..47ebe62 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -17,7 +17,7 @@ parking_lot.workspace = true regex = "1.11.1" rustyline = { version = "15.0.0", features = ["derive", "rustyline-derive"] } thiserror = "2.0.11" -tokio = { version = "1.44.1", features = ["macros", "parking_lot","rt-multi-thread"] } +tokio = { version = "1.44.1", features = ["fs", "macros", "parking_lot", "rt-multi-thread"] } wgpu = "24.0.3" winit = "0.30.9" bytemuck = "1.21.0" @@ -25,6 +25,9 @@ futures = "0.3.31" cgmath = "0.18.0" tracing = "0.1.41" tracing-subscriber = "0.3.19" +typenum = { version = "1.18.0", features = ["const-generics"] } +tobj = { version = "4.0.3", features = ["tokio"] } +ahash = "0.8.11" [profile.dev] diff --git a/engine/src/bint.rs b/engine/src/bint.rs new file mode 100644 index 0000000..28563de --- /dev/null +++ b/engine/src/bint.rs @@ -0,0 +1,334 @@ +use std::{ + cmp::Ordering, + convert::From, + fmt, + hash::{Hash, Hasher}, + ops::{ + Add, AddAssign, BitAnd, BitOr, BitXor, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, + Rem, RemAssign, Shl, Shr, Sub, SubAssign, + }, + str::FromStr, +}; + +#[derive(Debug, Clone, Copy)] +pub struct BigInt { + bytes: [u8; N], + len: usize, +} + +impl BigInt { + pub fn from_bytes(bytes: &[u8]) -> Self { + debug_assert!(bytes.len() != 0); + let mut len = bytes.len(); + while len > 1 && bytes[len - 1] == 0 { + len -= 1; + } + let mut arr = [0u8; N]; + arr[..len].copy_from_slice(&bytes[..len]); + BigInt { bytes: arr, len } + } + + pub fn from_u64(value: u64) -> Self { + Self::from_bytes(&value.to_le_bytes()) + } + + fn trim_zeros(mut self) -> Self { + while self.len > 1 && self.bytes[self.len - 1] == 0 { + self.len -= 1; + } + self + } + + pub fn max_value() -> Self { + let mut arr = [0u8; N]; + arr.fill(255); + BigInt { bytes: arr, len: N } + } + pub fn div_rem(&self, other: &Self) -> (Self, Self) { + let mut quotient = BigInt::from(0); + let mut remainder = self.clone(); + let divisor = other.clone(); + + while remainder >= divisor { + let mut multiple = divisor.clone(); + let mut temp_quotient = BigInt::from(1); + while multiple + multiple <= remainder { + multiple = multiple + multiple; + temp_quotient = temp_quotient + temp_quotient; + } + remainder = remainder - multiple; + quotient = quotient + temp_quotient; + } + (quotient.trim_zeros(), remainder.trim_zeros()) + } +} + +impl Add for BigInt { + type Output = Self; + fn add(self, rhs: Self) -> Self { + let mut result = [0u8; N]; + let mut carry = 0u16; + let max_len = self.len.max(rhs.len); + let mut res_len = 0; + + for i in 0..max_len { + let a = self.bytes.get(i).copied().unwrap_or(0) as u16; + let b = rhs.bytes.get(i).copied().unwrap_or(0) as u16; + let sum = a + b + carry; + result[i] = (sum % 256) as u8; + carry = sum / 256; + res_len = i + 1; + } + + if carry > 0 { + result[res_len] = carry as u8; + res_len += 1; + } + + BigInt { + bytes: result, + len: res_len, + } + .trim_zeros() + } +} + +impl AddAssign for BigInt { + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } +} + +impl Sub for BigInt { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + let mut result = [0u8; N]; + let mut borrow = 0i16; + let mut res_len = 0; + + for i in 0..self.len { + let a = self.bytes[i] as i16; + let b = rhs.bytes.get(i).copied().unwrap_or(0) as i16; + let mut diff = a - b - borrow; + borrow = 0; + + if diff < 0 { + diff += 256; + borrow = 1; + } + + result[i] = diff as u8; + res_len = i + 1; + } + + BigInt { + bytes: result, + len: res_len, + } + .trim_zeros() + } +} + +impl SubAssign for BigInt { + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } +} + +impl Mul for BigInt { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + let mut result = BigInt { + bytes: [0; N], + len: 0, + }; + + for i in 0..self.len { + let mut carry = 0u16; + for j in 0..rhs.len { + let idx = i + j; + if idx >= N { + panic!("Multiplication overflow"); + } + let product = + self.bytes[i] as u16 * rhs.bytes[j] as u16 + carry + result.bytes[idx] as u16; + result.bytes[idx] = (product % 256) as u8; + carry = product / 256; + } + let mut k = i + rhs.len; + while carry > 0 && k < N { + let sum = result.bytes[k] as u16 + carry; + result.bytes[k] = (sum % 256) as u8; + carry = sum / 256; + k += 1; + } + result.len = result.len.max(k); + } + + result.trim_zeros() + } +} + +impl MulAssign for BigInt { + fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; + } +} + +impl Div for BigInt { + type Output = Self; + fn div(self, rhs: Self) -> Self { + self.div_rem(&rhs).0 + } +} + +impl DivAssign for BigInt { + fn div_assign(&mut self, rhs: Self) { + *self = *self / rhs; + } +} + +impl Rem for BigInt { + type Output = Self; + fn rem(self, rhs: Self) -> Self { + self.div_rem(&rhs).1 + } +} + +impl RemAssign for BigInt { + fn rem_assign(&mut self, rhs: Self) { + *self = *self % rhs; + } +} + +impl PartialEq for BigInt { + fn eq(&self, other: &Self) -> bool { + self.bytes[..self.len] == other.bytes[..other.len] + } +} + +impl Eq for BigInt {} + +impl Hash for BigInt { + fn hash(&self, state: &mut H) { + self.bytes[..self.len].hash(state); + } +} + +impl PartialOrd for BigInt { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for BigInt { + fn cmp(&self, other: &Self) -> Ordering { + if self.len != other.len { + return self.len.cmp(&other.len); + } + for i in (0..self.len).rev() { + match self.bytes[i].cmp(&other.bytes[i]) { + Ordering::Equal => continue, + ord => return ord, + } + } + Ordering::Equal + } +} + +impl Deref for BigInt { + type Target = [u8]; + fn deref(&self) -> &[u8] { + &self.bytes[..self.len] + } +} + +impl DerefMut for BigInt { + fn deref_mut(&mut self) -> &mut [u8] { + &mut self.bytes[..self.len] + } +} + +macro_rules! impl_from_int { + ($($t:ty),*) => {$( + impl From<$t> for BigInt { + fn from(value: $t) -> Self { + let bytes = value.to_le_bytes(); + Self::from_bytes(&bytes) + } + } + )*}; +} + +impl_from_int!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); + +impl FromStr for BigInt { + type Err = &'static str; + fn from_str(s: &str) -> Result { + let mut result = BigInt::from(0u8); + for c in s.chars() { + if !c.is_digit(10) { + return Err("Invalid digit"); + } + let digit = c.to_digit(10).unwrap() as u8; + result = result * BigInt::from(10u8) + BigInt::from(digit); + } + Ok(result) + } +} + +impl fmt::Display for BigInt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.len == 0 { + return write!(f, "0"); + } + let mut digits = Vec::new(); + let mut bytes = self.bytes[..self.len].to_vec(); + + while !bytes.is_empty() { + let mut remainder = 0u16; + for byte in bytes.iter_mut().rev() { + let value = *byte as u16 + remainder * 256; + *byte = (value / 10) as u8; + remainder = value % 10; + } + digits.push(remainder as u8); + while !bytes.is_empty() && bytes[bytes.len() - 1] == 0 { + bytes.pop(); + } + } + + digits.reverse(); + let s = digits + .iter() + .map(|d| char::from_digit(*d as u32, 10).unwrap()) + .collect::(); + write!(f, "{}", s) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +struct Dint { + bytes: Vec, +} + +impl Deref for Dint { + type Target = [u8]; + fn deref(&self) -> &[u8] { + &self.bytes + } +} + +impl DerefMut for Dint { + fn deref_mut(&mut self) -> &mut [u8] { + &mut self.bytes + } +} + +pub fn main() { + type TheInt = BigInt<2>; + let mut test: TheInt = TheInt::max_value(); + let thing = BigInt::<9>::max_value(); + test /= 2.into(); + println!("{test}") +} diff --git a/engine/src/core/panic.rs b/engine/src/core/panic.rs index 3091ff4..db207f6 100644 --- a/engine/src/core/panic.rs +++ b/engine/src/core/panic.rs @@ -1,3 +1,4 @@ +use std::error::Error; use std::fmt::Write as FmtWrite; use std::mem; @@ -8,50 +9,43 @@ use regex::Regex; static INIT: parking_lot::Once = Once::new(); pub fn set_panic_hook() { - use std::io::Write; - - use colored::Colorize; - - use crate::workspace; - INIT.call_once(|| { let default_hook = std::panic::take_hook(); std::panic::set_hook(Box::new(move |info| { - let log_path = workspace::get_working_dir().unwrap_or_else(|_| { + if let Err(e) = process_panic(info) { + eprintln!("Error in panic hook: {}", e); default_hook(info); - std::process::exit(0); - }); - if !log_path.exists() { - std::fs::create_dir_all(&log_path).unwrap_or_else(|_| { - default_hook(info); - std::process::exit(0); - }); } - let log_path = log_path.join("panic.log"); + std::process::exit(0); + })); + }); +} - let mut file = std::fs::File::create(&log_path).unwrap_or_else(|_| { - default_hook(info); - std::process::exit(0); - }); - let payload = info.payload(); - let payload_str = if let Some(s) = payload.downcast_ref::<&str>() { - *s - } else if let Some(s) = payload.downcast_ref::() { - s - } else { - "" - }; +fn process_panic(info: &std::panic::PanicHookInfo<'_>) -> Result<(), Box> { + use crate::workspace; + use colored::Colorize; + use std::io::Write; - writeln!(file, "{}", payload_str).unwrap_or_else(|_| { - default_hook(info); - std::process::exit(0); - }); - writeln!(file, "{}", render_backtrace().sanitize_path()).unwrap_or_else(|_| { - default_hook(info); - std::process::exit(0); - }); + let log_dir = workspace::get_working_dir()?; + if !log_dir.exists() { + std::fs::create_dir_all(&log_dir)?; + } + let log_path = log_dir.join("panic.log"); - let panic_msg = format!( + let mut file = std::fs::File::create(&log_path)?; + let payload = info.payload(); + let payload_str = if let Some(s) = payload.downcast_ref::<&str>() { + *s + } else if let Some(s) = payload.downcast_ref::() { + s + } else { + "" + }; + + writeln!(file, "{}", payload_str)?; + writeln!(file, "{}", render_backtrace().sanitize_path())?; + + let panic_msg = format!( "Zenyx had a problem and crashed. To help us diagnose the problem you can send us a crash report. We have generated a report file at \"{}\". Submit an issue or email with the subject of \"Zenyx Crash Report\" and include the report as an attachment. @@ -63,11 +57,12 @@ https://github.com/Zenyx-Engine/Zenyx/issues We take privacy seriously, and do not perform any automated error collection. In order to improve the software, we rely on people to submit reports. Thank you kindly!", log_path.display()); - println!("{}", panic_msg.red().bold()); - println!("\nFor future reference, the error summary is as follows:\n{}", payload_str.red().bold()); - std::process::exit(0); - })); - }); + println!("{}", panic_msg.red().bold()); + println!( + "\nFor future reference, the error summary is as follows:\n{}", + payload_str.red().bold() + ); + Ok(()) } fn render_backtrace() -> String { @@ -130,7 +125,7 @@ trait Sanitize { impl Sanitize for str { fn sanitize_path(&self) -> String { let username_pattern = r"(?i)(/home/|/Users/|\\Users\\)([^/\\]+)"; - let re = Regex::new(username_pattern).expect("Failed to sanitize path, aborting operation"); + let re = Regex::new(username_pattern).expect("Failed to compile regex for sanitization"); re.replace_all(self, "${1}").to_string() } } diff --git a/engine/src/core/render/ctx.rs b/engine/src/core/render/ctx.rs index cc65270..86748df 100644 --- a/engine/src/core/render/ctx.rs +++ b/engine/src/core/render/ctx.rs @@ -1,14 +1,16 @@ +use std::borrow::Cow; +use std::mem::offset_of; use std::sync::Arc; use std::time::Instant; -use std::{backtrace::Backtrace, borrow::Cow}; -use cgmath::{Matrix4, Point3, Rad, Vector3, perspective}; +use cgmath::{Deg, Matrix4, Point3, Rad, SquareMatrix, Vector3, perspective}; use futures::executor::block_on; use thiserror::Error; use tracing::{error, trace}; use wgpu::TextureUsages; use wgpu::{Backends, InstanceDescriptor, util::DeviceExt}; use winit::window::Window; + #[derive(Debug, Error)] #[error(transparent)] pub enum ContextErrorKind { @@ -127,13 +129,21 @@ impl From for RenderContextError { } } -const CUBE_SHADER: &str = r" -struct Uniforms { - mvp: mat4x4, +const SHADER_SRC: &str = r#" +struct CameraUniform { + view: mat4x4, + proj: mat4x4, +}; + +struct ModelUniform { + model: mat4x4, }; @group(0) @binding(0) -var u: Uniforms; +var camera: CameraUniform; + +@group(1) @binding(0) +var model: ModelUniform; struct VertexInput { @location(0) position: vec3, @@ -148,27 +158,27 @@ struct VertexOutput { @vertex fn vs_main(input: VertexInput) -> VertexOutput { var output: VertexOutput; - output.clip_position = u.mvp * vec4(input.position, 1.0); + let model_pos = model.model * vec4(input.position, 1.0); + output.clip_position = camera.proj * camera.view * model_pos; output.normal = input.normal; return output; } - @fragment fn fs_main(input: VertexOutput) -> @location(0) vec4 { let ambient: f32 = 0.2; let light_dir = normalize(vec3(0.5, 1.0, 0.5)); let diffuse = clamp(dot(normalize(input.normal), light_dir), 0.0, 1.0); - // Mix ambient light to ensure no face is completely dark. let brightness = ambient + (1.0 - ambient) * diffuse; return vec4(0.7 * brightness, 0.7 * brightness, 0.9 * brightness, 1.0); } -"; +"#; + #[repr(C)] #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] -struct Vertex { - position: [f32; 3], - normal: [f32; 3], +pub struct Vertex { + pub position: [f32; 3], + pub normal: [f32; 3], } impl Vertex { @@ -179,7 +189,7 @@ impl Vertex { format: wgpu::VertexFormat::Float32x3, }, wgpu::VertexAttribute { - offset: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress, + offset: offset_of!(Vertex, normal) as u64, shader_location: 1, format: wgpu::VertexFormat::Float32x3, }, @@ -194,170 +204,165 @@ impl Vertex { } } -static CUBE_VERTICES: &[Vertex] = &[ - Vertex { - position: [-0.5, -0.5, 0.5], - normal: [0.0, 0.0, 1.0], - }, - Vertex { - position: [0.5, -0.5, 0.5], - normal: [0.0, 0.0, 1.0], - }, - Vertex { - position: [0.5, 0.5, 0.5], - normal: [0.0, 0.0, 1.0], - }, - Vertex { - position: [0.5, 0.5, 0.5], - normal: [0.0, 0.0, 1.0], - }, - Vertex { - position: [-0.5, 0.5, 0.5], - normal: [0.0, 0.0, 1.0], - }, - Vertex { - position: [-0.5, -0.5, 0.5], - normal: [0.0, 0.0, 1.0], - }, - Vertex { - position: [0.5, -0.5, -0.5], - normal: [0.0, 0.0, -1.0], - }, - Vertex { - position: [-0.5, -0.5, -0.5], - normal: [0.0, 0.0, -1.0], - }, - Vertex { - position: [-0.5, 0.5, -0.5], - normal: [0.0, 0.0, -1.0], - }, - Vertex { - position: [-0.5, 0.5, -0.5], - normal: [0.0, 0.0, -1.0], - }, - Vertex { - position: [0.5, 0.5, -0.5], - normal: [0.0, 0.0, -1.0], - }, - Vertex { - position: [0.5, -0.5, -0.5], - normal: [0.0, 0.0, -1.0], - }, - Vertex { - position: [0.5, -0.5, 0.5], - normal: [1.0, 0.0, 0.0], - }, - Vertex { - position: [0.5, -0.5, -0.5], - normal: [1.0, 0.0, 0.0], - }, - Vertex { - position: [0.5, 0.5, -0.5], - normal: [1.0, 0.0, 0.0], - }, - Vertex { - position: [0.5, 0.5, -0.5], - normal: [1.0, 0.0, 0.0], - }, - Vertex { - position: [0.5, 0.5, 0.5], - normal: [1.0, 0.0, 0.0], - }, - Vertex { - position: [0.5, -0.5, 0.5], - normal: [1.0, 0.0, 0.0], - }, - Vertex { - position: [-0.5, -0.5, -0.5], - normal: [-1.0, 0.0, 0.0], - }, - Vertex { - position: [-0.5, -0.5, 0.5], - normal: [-1.0, 0.0, 0.0], - }, - Vertex { - position: [-0.5, 0.5, 0.5], - normal: [-1.0, 0.0, 0.0], - }, - Vertex { - position: [-0.5, 0.5, 0.5], - normal: [-1.0, 0.0, 0.0], - }, - Vertex { - position: [-0.5, 0.5, -0.5], - normal: [-1.0, 0.0, 0.0], - }, - Vertex { - position: [-0.5, -0.5, -0.5], - normal: [-1.0, 0.0, 0.0], - }, - Vertex { - position: [-0.5, 0.5, 0.5], - normal: [0.0, 1.0, 0.0], - }, - Vertex { - position: [0.5, 0.5, 0.5], - normal: [0.0, 1.0, 0.0], - }, - Vertex { - position: [0.5, 0.5, -0.5], - normal: [0.0, 1.0, 0.0], - }, - Vertex { - position: [0.5, 0.5, -0.5], - normal: [0.0, 1.0, 0.0], - }, - Vertex { - position: [-0.5, 0.5, -0.5], - normal: [0.0, 1.0, 0.0], - }, - Vertex { - position: [-0.5, 0.5, 0.5], - normal: [0.0, 1.0, 0.0], - }, - Vertex { - position: [-0.5, -0.5, -0.5], - normal: [0.0, -1.0, 0.0], - }, - Vertex { - position: [0.5, -0.5, -0.5], - normal: [0.0, -1.0, 0.0], - }, - Vertex { - position: [0.5, -0.5, 0.5], - normal: [0.0, -1.0, 0.0], - }, - Vertex { - position: [0.5, -0.5, 0.5], - normal: [0.0, -1.0, 0.0], - }, - Vertex { - position: [-0.5, -0.5, 0.5], - normal: [0.0, -1.0, 0.0], - }, - Vertex { - position: [-0.5, -0.5, -0.5], - normal: [0.0, -1.0, 0.0], - }, -]; +#[repr(C)] +#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +struct CameraUniform { + view: [[f32; 4]; 4], + proj: [[f32; 4]; 4], +} -pub struct WgpuCtx<'window> { +#[repr(C)] +#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +struct ModelUniform { + model: [[f32; 4]; 4], +} + +struct Camera { + uniform_buffer: wgpu::Buffer, + bind_group: wgpu::BindGroup, + view: Matrix4, + proj: Matrix4, +} + +impl Camera { + fn new( + device: &wgpu::Device, + bind_group_layout: &wgpu::BindGroupLayout, + width: u32, + height: u32, + ) -> Self { + let view = Matrix4::look_at_rh( + Point3::new(0.0, 0.0, 3.0), + Point3::new(0.0, 0.0, 0.0), + Vector3::unit_y(), + ); + let aspect = width as f32 / height as f32; + let proj = perspective(Rad::from(Deg(45.0)), aspect, 0.1, 100.0); + + let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Camera Uniform Buffer"), + size: std::mem::size_of::() as u64, + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("Camera Bind Group"), + layout: bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: uniform_buffer.as_entire_binding(), + }], + }); + + Self { + uniform_buffer, + bind_group, + view, + proj, + } + } + + fn resize(&mut self, width: u32, height: u32) { + let aspect = width as f32 / height as f32; + self.proj = perspective(Rad::from(Deg(45.0)), aspect, 0.1, 100.0); + } + + fn update(&self, queue: &wgpu::Queue) { + let view_array: [[f32; 4]; 4] = self.view.into(); + let proj_array: [[f32; 4]; 4] = self.proj.into(); + let uniform = CameraUniform { + view: view_array, + proj: proj_array, + }; + queue.write_buffer(&self.uniform_buffer, 0, bytemuck::bytes_of(&uniform)); + } +} + +struct Model { + vertex_buffer: wgpu::Buffer, + index_buffer: wgpu::Buffer, + uniform_buffer: wgpu::Buffer, + bind_group: wgpu::BindGroup, + index_count: u32, // Changed from vertex_count to index_count + transform: Matrix4, +} + +impl Model { + fn new( + device: &wgpu::Device, + vertices: &[Vertex], + indices: &[u32], + bind_group_layout: &wgpu::BindGroupLayout, + ) -> Self { + let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Vertex Buffer"), + contents: bytemuck::cast_slice(vertices), + usage: wgpu::BufferUsages::VERTEX, + }); + + let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Index Buffer"), + contents: bytemuck::cast_slice(indices), // Use proper indices + usage: wgpu::BufferUsages::INDEX, + }); + + let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Model Uniform Buffer"), + size: std::mem::size_of::() as u64, + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("Model Bind Group"), + layout: bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: uniform_buffer.as_entire_binding(), + }], + }); + Self { + vertex_buffer, + index_buffer, + uniform_buffer, + bind_group, + index_count: indices.len() as u32, + transform: Matrix4::identity(), + } + } + + fn update(&self, queue: &wgpu::Queue) { + let model_array: [[f32; 4]; 4] = self.transform.into(); + let uniform = ModelUniform { model: model_array }; + queue.write_buffer(&self.uniform_buffer, 0, bytemuck::bytes_of(&uniform)); + } + + fn set_transform(&mut self, transform: Matrix4) { + self.transform = transform; + } +} + +pub struct Renderer<'window> { device: wgpu::Device, queue: wgpu::Queue, surface: wgpu::Surface<'window>, surface_config: wgpu::SurfaceConfiguration, - adapter: wgpu::Adapter, + camera: Camera, + models: Vec, render_pipeline: wgpu::RenderPipeline, - uniform_buffer: wgpu::Buffer, - vertex_buffer: wgpu::Buffer, - start_time: Instant, + depth_texture: wgpu::Texture, + depth_texture_view: wgpu::TextureView, + camera_bind_group_layout: wgpu::BindGroupLayout, + model_bind_group_layout: wgpu::BindGroupLayout, bg_color: wgpu::Color, + start_time: Instant, last_frame_instant: Instant, frame_count: u32, } -impl<'window> WgpuCtx<'window> { - pub async fn new(window: Arc) -> Result, RenderContextError> { +impl<'window> Renderer<'window> { + pub async fn new(window: Arc) -> Result { let instance = wgpu::Instance::new(&InstanceDescriptor { backends: Backends::from_comma_list("dx12,metal,opengl,webgpu"), ..Default::default() @@ -381,86 +386,97 @@ impl<'window> WgpuCtx<'window> { None, ) })?; + let (device, queue) = adapter .request_device(&wgpu::DeviceDescriptor::default(), None) .await .ctx_err(ContextErrorKind::DeviceRequest, "Device configuration")?; + let size = window.inner_size(); let width = size.width.max(1); let height = size.height.max(1); - let surface_config = wgpu::SurfaceConfiguration { - width: width.max(1), - height: height.max(1), - format: wgpu::TextureFormat::Rgba8UnormSrgb, - present_mode: wgpu::PresentMode::AutoNoVsync, - alpha_mode: wgpu::CompositeAlphaMode::Auto, - view_formats: Vec::new(), - usage: TextureUsages::RENDER_ATTACHMENT, - desired_maximum_frame_latency: 3, - }; - surface.configure(&device, &surface_config); - let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Uniform Buffer"), - size: 64, - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Cube Vertex Buffer"), - contents: bytemuck::cast_slice(CUBE_VERTICES), - usage: wgpu::BufferUsages::VERTEX, - }); - let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("Cube Shader"), - source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(CUBE_SHADER)), - }); - let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: Some("Uniform Bind Group Layout"), - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: wgpu::BufferSize::new(64), - }, - count: None, - }], - }); + + let camera_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("Camera Bind Group Layout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: wgpu::BufferSize::new( + std::mem::size_of::() as u64, + ), + }, + count: None, + }], + }); + + let model_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("Model Bind Group Layout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: wgpu::BufferSize::new( + std::mem::size_of::() as u64, + ), + }, + count: None, + }], + }); + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Cube Pipeline Layout"), - bind_group_layouts: &[&bind_group_layout], + label: Some("Pipeline Layout"), + bind_group_layouts: &[&camera_bind_group_layout, &model_bind_group_layout], push_constant_ranges: &[], }); + + let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("Main Shader"), + source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(SHADER_SRC)), + }); + let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Cube Render Pipeline"), + label: Some("Main Pipeline"), layout: Some(&pipeline_layout), vertex: wgpu::VertexState { module: &shader, entry_point: Some("vs_main"), buffers: &[Vertex::desc()], - compilation_options: wgpu::PipelineCompilationOptions::default(), + compilation_options: Default::default(), }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: Some("fs_main"), targets: &[Some(wgpu::ColorTargetState { - format: surface_config.format, - blend: Some(wgpu::BlendState::ALPHA_BLENDING), + format: surface.get_capabilities(&adapter).formats[0], + blend: Some(wgpu::BlendState::REPLACE), write_mask: wgpu::ColorWrites::ALL, })], - compilation_options: wgpu::PipelineCompilationOptions::default(), + compilation_options: Default::default(), }), primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, strip_index_format: None, front_face: wgpu::FrontFace::Ccw, cull_mode: Some(wgpu::Face::Back), + // cull_mode: , polygon_mode: wgpu::PolygonMode::Fill, unclipped_depth: false, conservative: false, }, - depth_stencil: None, + depth_stencil: Some(wgpu::DepthStencilState { + format: wgpu::TextureFormat::Depth32Float, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::Less, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + }), multisample: wgpu::MultisampleState { count: 1, mask: !0, @@ -469,15 +485,40 @@ impl<'window> WgpuCtx<'window> { multiview: None, cache: None, }); - Ok(WgpuCtx { + + + let camera = Camera::new(&device, &camera_bind_group_layout, width, height); + + let surface_caps = surface.get_capabilities(&adapter); + let surface_config = wgpu::SurfaceConfiguration { + width, + height, + format: surface_caps.formats[0], + present_mode: wgpu::PresentMode::AutoNoVsync, + alpha_mode: wgpu::CompositeAlphaMode::Auto, + view_formats: vec![], + usage: TextureUsages::RENDER_ATTACHMENT, + desired_maximum_frame_latency: 3, + }; + surface.configure(&device, &surface_config); + let (depth_texture, depth_texture_view) = create_depth_texture( + &device, + surface_config.width, + surface_config.height, + // surface_config.format, + ); + + + Ok(Self { device, queue, surface, surface_config, - adapter, + camera, + models: Vec::new(), render_pipeline, - uniform_buffer, - vertex_buffer, + camera_bind_group_layout, + model_bind_group_layout, bg_color: wgpu::Color { r: 0.1, g: 0.1, @@ -487,79 +528,101 @@ impl<'window> WgpuCtx<'window> { start_time: Instant::now(), last_frame_instant: Instant::now(), frame_count: 0, + depth_texture, + depth_texture_view, }) } - pub fn new_blocking(window: Arc) -> Result, RenderContextError> { + pub fn new_blocking(window: Arc) -> Result { block_on(Self::new(window)) } + pub fn add_model(&mut self, vertices: &[Vertex], indicies: &[u32]) { + let model = Model::new( + &self.device, + vertices, + indicies, + &self.model_bind_group_layout, + ); + self.models.push(model); + } + pub fn resize(&mut self, new_size: (u32, u32)) { let (width, height) = new_size; + let (depth_texture,depth_view) = create_depth_texture(&self.device, width, height); self.surface_config.width = width.max(1); self.surface_config.height = height.max(1); self.surface.configure(&self.device, &self.surface_config); + self.depth_texture = depth_texture; + self.depth_texture_view = depth_view; + self.camera.resize(width, height); } pub fn draw(&mut self) { - let elapsed = self.start_time.elapsed().as_secs_f32() * 0.80f32; - let model = Matrix4::from_angle_x(Rad(elapsed)) * Matrix4::from_angle_y(Rad(elapsed)); - let view = Matrix4::look_at_rh( - Point3::new(0.0, 0.0, 3.0), - Point3::new(0.0, 0.0, 0.0), - Vector3::unit_y(), - ); - let aspect = self.surface_config.width as f32 / self.surface_config.height as f32; - let proj = perspective(Rad(std::f32::consts::FRAC_PI_4), aspect, 0.1, 100.0); - let mvp = proj * view * model; - let mvp_array: [[f32; 4]; 4] = [ - [mvp.x.x, mvp.x.y, mvp.x.z, mvp.x.w], - [mvp.y.x, mvp.y.y, mvp.y.z, mvp.y.w], - [mvp.z.x, mvp.z.y, mvp.z.z, mvp.z.w], - [mvp.w.x, mvp.w.y, mvp.w.z, mvp.w.w], - ]; - self.queue - .write_buffer(&self.uniform_buffer, 0, bytemuck::bytes_of(&mvp_array)); + let elapsed = self.start_time.elapsed().as_secs_f32(); + + self.camera.update(&self.queue); + + for (i, model) in self.models.iter_mut().enumerate() { + let angle = Rad(elapsed * 0.8 + i as f32 * 0.3); + model.set_transform(Matrix4::from_angle_x(angle) * Matrix4::from_angle_y(angle)); + model.update(&self.queue); + } + let surface_texture = self .surface .get_current_texture() - .expect("Failed to get surface texture"); - let view_texture = surface_texture + .ctx_err( + ContextErrorKind::SurfaceTexture, + "Surface texture acquisition", + ) + .unwrap(); + + let view = surface_texture .texture .create_view(&wgpu::TextureViewDescriptor::default()); + let mut encoder = self .device .create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("Cube Command Encoder"), + label: Some("Render Encoder"), }); + { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Cube Render Pass"), + label: Some("Main Render Pass"), color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &view_texture, + view: &view, resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Clear(self.bg_color), store: wgpu::StoreOp::Store, }, })], - depth_stencil_attachment: None, - timestamp_writes: None, + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &self.depth_texture_view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: wgpu::StoreOp::Store, + }), + stencil_ops: None, + }), occlusion_query_set: None, + timestamp_writes: None, }); + render_pass.set_pipeline(&self.render_pipeline); - let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("Uniform Bind Group"), - layout: &self.render_pipeline.get_bind_group_layout(0), - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: self.uniform_buffer.as_entire_binding(), - }], - }); - render_pass.set_bind_group(0, &bind_group, &[]); - render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); - render_pass.draw(0..36, 0..1); + render_pass.set_bind_group(0, &self.camera.bind_group, &[]); + + for model in &self.models { + render_pass.set_bind_group(1, &model.bind_group, &[]); + render_pass.set_vertex_buffer(0, model.vertex_buffer.slice(..)); + render_pass + .set_index_buffer(model.index_buffer.slice(..), wgpu::IndexFormat::Uint32); + render_pass.draw_indexed(0..model.index_count, 0, 0..1); + } } + self.queue.submit(Some(encoder.finish())); surface_texture.present(); @@ -573,10 +636,38 @@ impl<'window> WgpuCtx<'window> { } } - pub fn change_bg_color(&mut self, color: wgpu::Color) { + pub fn set_bg_color(&mut self, color: wgpu::Color) { self.bg_color = color; } + pub fn bg_color(&self) -> wgpu::Color { - self.bg_color.clone() + self.bg_color } } +fn create_depth_texture( + device: &wgpu::Device, + width: u32, + height: u32, + // format: wgpu::TextureFormat, +) -> (wgpu::Texture, wgpu::TextureView) { + let size = wgpu::Extent3d { + width, + height, + depth_or_array_layers: 1, + }; + + let desc = wgpu::TextureDescriptor { + label: Some("Depth Texture"), + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Depth32Float, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }; + + let texture = device.create_texture(&desc); + let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + (texture, view) +} \ No newline at end of file diff --git a/engine/src/core/render/mod.rs b/engine/src/core/render/mod.rs index 079c2cf..43b0a6f 100644 --- a/engine/src/core/render/mod.rs +++ b/engine/src/core/render/mod.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; use std::ops::Deref; use std::sync::Arc; -use ctx::WgpuCtx; +use ctx::{Renderer, Vertex}; +use tobj::LoadOptions; use tracing::{debug, error, info, trace, warn}; use wgpu::rwh::HasWindowHandle; use winit::application::ApplicationHandler; @@ -15,7 +16,7 @@ pub mod ctx; struct WindowContext<'window> { window: Arc, - ctx: WgpuCtx<'window>, + ctx: Renderer<'window>, main_window: bool, } impl Deref for WindowContext<'_> { @@ -35,6 +36,161 @@ impl WindowContext<'_> { pub struct App<'window> { windows: HashMap>, } +static CUBE_VERTICES: &[Vertex] = &[ + Vertex { + position: [-0.5, -0.5, 0.5], + normal: [0.0, 0.0, 1.0], + }, + Vertex { + position: [0.5, -0.5, 0.5], + normal: [0.0, 0.0, 1.0], + }, + Vertex { + position: [0.5, 0.5, 0.5], + normal: [0.0, 0.0, 1.0], + }, + Vertex { + position: [0.5, 0.5, 0.5], + normal: [0.0, 0.0, 1.0], + }, + Vertex { + position: [-0.5, 0.5, 0.5], + normal: [0.0, 0.0, 1.0], + }, + Vertex { + position: [-0.5, -0.5, 0.5], + normal: [0.0, 0.0, 1.0], + }, + Vertex { + position: [0.5, -0.5, -0.5], + normal: [0.0, 0.0, -1.0], + }, + Vertex { + position: [-0.5, -0.5, -0.5], + normal: [0.0, 0.0, -1.0], + }, + Vertex { + position: [-0.5, 0.5, -0.5], + normal: [0.0, 0.0, -1.0], + }, + Vertex { + position: [-0.5, 0.5, -0.5], + normal: [0.0, 0.0, -1.0], + }, + Vertex { + position: [0.5, 0.5, -0.5], + normal: [0.0, 0.0, -1.0], + }, + Vertex { + position: [0.5, -0.5, -0.5], + normal: [0.0, 0.0, -1.0], + }, + Vertex { + position: [0.5, -0.5, 0.5], + normal: [1.0, 0.0, 0.0], + }, + Vertex { + position: [0.5, -0.5, -0.5], + normal: [1.0, 0.0, 0.0], + }, + Vertex { + position: [0.5, 0.5, -0.5], + normal: [1.0, 0.0, 0.0], + }, + Vertex { + position: [0.5, 0.5, -0.5], + normal: [1.0, 0.0, 0.0], + }, + Vertex { + position: [0.5, 0.5, 0.5], + normal: [1.0, 0.0, 0.0], + }, + Vertex { + position: [0.5, -0.5, 0.5], + normal: [1.0, 0.0, 0.0], + }, + Vertex { + position: [-0.5, -0.5, -0.5], + normal: [-1.0, 0.0, 0.0], + }, + Vertex { + position: [-0.5, -0.5, 0.5], + normal: [-1.0, 0.0, 0.0], + }, + Vertex { + position: [-0.5, 0.5, 0.5], + normal: [-1.0, 0.0, 0.0], + }, + Vertex { + position: [-0.5, 0.5, 0.5], + normal: [-1.0, 0.0, 0.0], + }, + Vertex { + position: [-0.5, 0.5, -0.5], + normal: [-1.0, 0.0, 0.0], + }, + Vertex { + position: [-0.5, -0.5, -0.5], + normal: [-1.0, 0.0, 0.0], + }, + Vertex { + position: [-0.5, 0.5, 0.5], + normal: [0.0, 1.0, 0.0], + }, + Vertex { + position: [0.5, 0.5, 0.5], + normal: [0.0, 1.0, 0.0], + }, + Vertex { + position: [0.5, 0.5, -0.5], + normal: [0.0, 1.0, 0.0], + }, + Vertex { + position: [0.5, 0.5, -0.5], + normal: [0.0, 1.0, 0.0], + }, + Vertex { + position: [-0.5, 0.5, -0.5], + normal: [0.0, 1.0, 0.0], + }, + Vertex { + position: [-0.5, 0.5, 0.5], + normal: [0.0, 1.0, 0.0], + }, + Vertex { + position: [-0.5, -0.5, -0.5], + normal: [0.0, -1.0, 0.0], + }, + Vertex { + position: [0.5, -0.5, -0.5], + normal: [0.0, -1.0, 0.0], + }, + Vertex { + position: [0.5, -0.5, 0.5], + normal: [0.0, -1.0, 0.0], + }, + Vertex { + position: [0.5, -0.5, 0.5], + normal: [0.0, -1.0, 0.0], + }, + Vertex { + position: [-0.5, -0.5, 0.5], + normal: [0.0, -1.0, 0.0], + }, + Vertex { + position: [-0.5, -0.5, -0.5], + normal: [0.0, -1.0, 0.0], + }, +]; +const CUBE_INDICES: &[u32] = &[ + 0, 1, 2, 2, 3, 0, + 4, 5, 6, 6, 7, 4, + 8, 9, 10, 10, 11, 8, + 12, 13, 14, 14, 15, 12, + 16, 17, 18, 18, 19, 16, + 20, 21, 22, 22, 23, 20, +]; + impl App<'_> { fn create_main_window(&mut self, event_loop: &ActiveEventLoop) { @@ -43,8 +199,45 @@ impl App<'_> { Ok(window) => { let window = Arc::new(window); let window_id = window.id(); - match WgpuCtx::new_blocking(window.clone()) { - Ok(wgpu_ctx) => { + match Renderer::new_blocking(window.clone()) { + Ok(mut wgpu_ctx) => { + let obj = match tobj::load_obj( + "test.obj", + &LoadOptions { + triangulate: true, + single_index: true, + ..Default::default() + }, + ) { + Ok(obj) => obj, + Err(e) => { + error!("{e}"); + panic!() + } + }; + let mesh = obj.0.get(0).unwrap().mesh.clone(); + + let vertices: Vec = (0..mesh.positions.len() / 3) + .map(|i| Vertex { + position: [ + mesh.positions[i * 3], + mesh.positions[i * 3 + 1], + mesh.positions[i * 3 + 2], + ], + normal: if !mesh.normals.is_empty() { + [ + mesh.normals[i * 3], + mesh.normals[i * 3 + 1], + mesh.normals[i * 3 + 2], + ] + } else { + [0.0; 3] + }, + }) + .collect(); + + wgpu_ctx.add_model(&vertices, &mesh.indices); + // wgpu_ctx.add_model(CUBE_VERTICES,CUBE_INDICES); self.windows.insert( window_id, WindowContext { @@ -101,7 +294,7 @@ impl App<'_> { wgpu::Color::BLACK => wgpu::Color::WHITE, _ => wgpu::Color::WHITE, }; - window_context.ctx.change_bg_color(new_color); + window_context.ctx.set_bg_color(new_color); debug!("Toggled background color for window {:?}", window_id); } else { warn!("No window context for toggling background: {:?}", window_id); @@ -111,7 +304,7 @@ impl App<'_> { fn spawn_child_window(&mut self, event_loop: &ActiveEventLoop) { if let Some(main_ctx) = self.windows.values().find(|ctx| ctx.is_main_window()) { let title = format!("Zenyx - New Window {}", self.windows.len()); - //TODO: Verify that this is safe instead of matching on it + // TODO: Verify that this is safe instead of matching on it let win_attr = unsafe { let base = Window::default_attributes().with_title(title); match main_ctx.window_handle() { @@ -123,8 +316,9 @@ impl App<'_> { Ok(window) => { let window = Arc::new(window); let window_id = window.id(); - match WgpuCtx::new_blocking(window.clone()) { - Ok(wgpu_ctx) => { + match Renderer::new_blocking(window.clone()) { + Ok(mut wgpu_ctx) => { + wgpu_ctx.add_model(CUBE_VERTICES,CUBE_INDICES); self.windows.insert( window_id, WindowContext { diff --git a/engine/src/main.rs b/engine/src/main.rs index 8fddb28..ff47bb2 100644 --- a/engine/src/main.rs +++ b/engine/src/main.rs @@ -7,6 +7,7 @@ use tracing::{debug, error, info, warn}; use tracing::{level_filters::LevelFilter, subscriber::set_global_default}; use tracing_subscriber::{layer::Filter, util::SubscriberInitExt}; use winit::event_loop::EventLoop; +pub mod bint; pub mod core; fn init_logger() { @@ -26,6 +27,7 @@ fn init_logger() { #[tokio::main(flavor = "current_thread")] async fn main() -> anyhow::Result<()> { init_logger(); + // bint::main(); if !cfg!(debug_assertions) { info!("{}", "Debug mode disabled".bright_blue()); set_panic_hook(); diff --git a/test.mtl b/test.mtl new file mode 100644 index 0000000..4704186 --- /dev/null +++ b/test.mtl @@ -0,0 +1,2 @@ +# Blender 4.2.3 LTS MTL File: 'None' +# www.blender.org