diff --git a/Cargo.lock b/Cargo.lock index a0be063..1531833 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ "getrandom", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -112,6 +112,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -315,7 +324,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317" dependencies = [ - "approx", + "approx 0.4.0", "num-traits", ] @@ -443,6 +452,34 @@ dependencies = [ "urlencoding", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -523,6 +560,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "endian-type" version = "0.1.2" @@ -752,6 +795,44 @@ dependencies = [ "gl_generator", ] +[[package]] +name = "glyph_brush" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0060f4ed4ef64a5876d9836d7d6c9ed43a463f3ca431682bec1c326064c8c93e" +dependencies = [ + "glyph_brush_draw_cache", + "glyph_brush_layout", + "ordered-float 5.0.0", + "rustc-hash 2.1.1", + "twox-hash", +] + +[[package]] +name = "glyph_brush_draw_cache" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6c910def52365fef3f439a6b50a4d5c11b28eec4cf6c191f6dfea18e88d7f" +dependencies = [ + "ab_glyph", + "crossbeam-channel", + "crossbeam-deque", + "linked-hash-map", + "rayon", + "rustc-hash 2.1.1", +] + +[[package]] +name = "glyph_brush_layout" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1e288bfd2f6c0313f78bf5aa538356ad481a3bb97e9b7f93220ab0066c5992" +dependencies = [ + "ab_glyph", + "approx 0.5.1", + "xi-unicode", +] + [[package]] name = "gpu-alloc" version = "0.6.0" @@ -1111,6 +1192,12 @@ dependencies = [ "redox_syscall 0.5.10", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -1213,7 +1300,7 @@ dependencies = [ "hexf-parse", "indexmap", "log", - "rustc-hash", + "rustc-hash 1.1.0", "spirv", "strum", "termcolor", @@ -1566,6 +1653,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-float" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2c1f9f56e534ac6a9b8a4600bdf0f530fb393b5f393e7b4d03489c3cf0c3f01" +dependencies = [ + "num-traits", +] + [[package]] name = "overload" version = "0.1.1" @@ -1669,6 +1765,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy 0.8.24", +] + [[package]] name = "presser" version = "0.3.1" @@ -1727,6 +1832,36 @@ dependencies = [ "nibble_vec", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "range-alloc" version = "0.1.4" @@ -1739,6 +1874,26 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -1815,6 +1970,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustix" version = "0.38.44" @@ -2302,6 +2463,15 @@ version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +[[package]] +name = "twox-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7b17f197b3050ba473acf9181f7b1d3b66d1cf7356c6cc57886662276e65908" +dependencies = [ + "rand", +] + [[package]] name = "typenum" version = "1.18.0" @@ -2645,7 +2815,7 @@ dependencies = [ "parking_lot", "profiling", "raw-window-handle", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", "thiserror 2.0.12", "wgpu-hal", @@ -2682,13 +2852,13 @@ dependencies = [ "ndk-sys 0.5.0+25.2.9519653", "objc", "once_cell", - "ordered-float", + "ordered-float 4.6.0", "parking_lot", "profiling", "range-alloc", "raw-window-handle", "renderdoc-sys", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", "thiserror 2.0.12", "wasm-bindgen", @@ -2710,6 +2880,18 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wgpu_text" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccd192487eb81eb51f8f0eb82fea0865e71ab4f002f7942bee0bba04fc2a0b8c" +dependencies = [ + "bytemuck", + "glyph_brush", + "log", + "wgpu", +] + [[package]] name = "winapi" version = "0.3.9" @@ -3136,6 +3318,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" +[[package]] +name = "xi-unicode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" + [[package]] name = "xkbcommon-dl" version = "0.4.2" @@ -3220,6 +3408,7 @@ dependencies = [ "tracing-subscriber", "typenum", "wgpu", + "wgpu_text", "winit", ] @@ -3229,7 +3418,16 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive 0.8.24", ] [[package]] @@ -3243,6 +3441,17 @@ dependencies = [ "syn", ] +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zerofrom" version = "0.1.6" diff --git a/Cargo.toml b/Cargo.toml index 28987ac..4bd4bc4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,39 +2,16 @@ resolver = "2" members = ["engine","subcrates/zen_core"] -[profile.dev] - -rpath = false -panic = "abort" -lto = "off" -opt-level = 0 -debug = false -overflow-checks = false -incremental = true -codegen-units = 512 - - -strip = "symbols" -debug-assertions = true - -[profile.dev.package."*"] -opt-level = 0 -debug = false -overflow-checks = false -incremental = true -codegen-units = 512 - - -strip = "symbols" -debug-assertions = true - [workspace.dependencies] lazy_static = "1.5.0" parking_lot = "0.12.3" [profile.release] -debug-assertions = false lto = true codegen-units = 1 panic = "abort" +split-debuginfo = "off" + +[profile.dev] +debug = 0 diff --git a/Pumpkin.mtl b/Pumpkin.mtl new file mode 100644 index 0000000..5052cb5 --- /dev/null +++ b/Pumpkin.mtl @@ -0,0 +1,22 @@ +# Blender 4.2.3 LTS MTL File: 'None' +# www.blender.org + +newmtl Material.001 +Ns 0.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.000000 0.000000 0.000000 +Ke 0.000000 0.000000 0.000000 +Ni 1.500000 +d 1.000000 +illum 1 + +newmtl Material.003 +Ns 0.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.000000 0.000000 0.000000 +Ke 0.000000 0.000000 0.000000 +Ni 1.500000 +d 1.000000 +illum 1 diff --git a/Pumpkin.obj b/Pumpkin.obj new file mode 100644 index 0000000..3213ff6 --- /dev/null +++ b/Pumpkin.obj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea2ba2cb7b88b20e6b1d52c0726e7a707b20a6ed22f23d640031e87d1942f5a3 +size 681889 diff --git a/default.nix b/default.nix index 0f91f93..4b49658 100644 --- a/default.nix +++ b/default.nix @@ -40,7 +40,6 @@ in doCheck = false; LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath buildInputs}"; - fixupPhase = '' wrapProgram $out/bin/${pname} --set PATH ${bash}/bin:\$PATH --set LD_LIBRARY_PATH ${pkgs.lib.makeLibraryPath buildInputs} ''; diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 47ebe62..62aaf9d 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -3,35 +3,42 @@ name = "zenyx" version = "0.1.0" edition = "2024" repository = "https://github.com/Zenyx-Engine/Zenyx" + [dependencies] +# TBR anyhow = "1.0.94" +# TBR (if possible) backtrace = "0.3.74" +# TBR (if possible) chrono = "0.4.39" colored = "3.0.0" +# TBR (if possible) crashreport = "1.0.1" +# TBR dirs-next = "2.0.0" - +# TBR == (To be removed) +# TBR lazy_static.workspace = true +# TBR once_cell = "1.21.1" parking_lot.workspace = true +# TBR (if possible) regex = "1.11.1" +# TBR (if possible) rustyline = { version = "15.0.0", features = ["derive", "rustyline-derive"] } thiserror = "2.0.11" +# Tokio is heavy but so far its the best option, we should make better use of it or switch to another runtime. 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" +# TBR (if possible) futures = "0.3.31" cgmath = "0.18.0" tracing = "0.1.41" tracing-subscriber = "0.3.19" +# TBR typenum = { version = "1.18.0", features = ["const-generics"] } tobj = { version = "4.0.3", features = ["tokio"] } ahash = "0.8.11" - - -[profile.dev] -debug-assertions = true - -[profile.release] -debug-assertions = false +wgpu_text = "0.9.2" diff --git a/engine/src/bint.rs b/engine/src/bint.rs deleted file mode 100644 index 28563de..0000000 --- a/engine/src/bint.rs +++ /dev/null @@ -1,334 +0,0 @@ -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/render/DejaVuSans.ttf b/engine/src/core/render/DejaVuSans.ttf new file mode 100644 index 0000000..5267218 Binary files /dev/null and b/engine/src/core/render/DejaVuSans.ttf differ diff --git a/engine/src/core/render/ctx.rs b/engine/src/core/render/ctx.rs index 86748df..7024e0f 100644 --- a/engine/src/core/render/ctx.rs +++ b/engine/src/core/render/ctx.rs @@ -6,9 +6,12 @@ use std::time::Instant; use cgmath::{Deg, Matrix4, Point3, Rad, SquareMatrix, Vector3, perspective}; use futures::executor::block_on; use thiserror::Error; -use tracing::{error, trace}; +use tracing::{error, info, trace}; use wgpu::TextureUsages; use wgpu::{Backends, InstanceDescriptor, util::DeviceExt}; +use wgpu_text::glyph_brush::ab_glyph::FontRef; +use wgpu_text::glyph_brush::{HorizontalAlign, Layout, OwnedSection, OwnedText, VerticalAlign}; +use wgpu_text::{BrushBuilder, TextBrush}; use winit::window::Window; #[derive(Debug, Error)] @@ -129,50 +132,7 @@ impl From for RenderContextError { } } -const SHADER_SRC: &str = r#" -struct CameraUniform { - view: mat4x4, - proj: mat4x4, -}; - -struct ModelUniform { - model: mat4x4, -}; - -@group(0) @binding(0) -var camera: CameraUniform; - -@group(1) @binding(0) -var model: ModelUniform; - -struct VertexInput { - @location(0) position: vec3, - @location(1) normal: vec3, -}; - -struct VertexOutput { - @builtin(position) clip_position: vec4, - @location(0) normal: vec3, -}; - -@vertex -fn vs_main(input: VertexInput) -> VertexOutput { - var output: VertexOutput; - 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); - let brightness = ambient + (1.0 - ambient) * diffuse; - return vec4(0.7 * brightness, 0.7 * brightness, 0.9 * brightness, 1.0); -} -"#; +const SHADER_SRC: &str = include_str!("shader.wgsl"); #[repr(C)] #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] @@ -284,7 +244,7 @@ struct Model { index_buffer: wgpu::Buffer, uniform_buffer: wgpu::Buffer, bind_group: wgpu::BindGroup, - index_count: u32, // Changed from vertex_count to index_count + index_count: u32, transform: Matrix4, } @@ -359,6 +319,15 @@ pub struct Renderer<'window> { start_time: Instant, last_frame_instant: Instant, frame_count: u32, + fps: f32, + font_state: FontState, +} + +struct FontState { + brush: TextBrush>, + section: OwnedSection, + scale: f32, + color: wgpu::Color, } impl<'window> Renderer<'window> { @@ -485,7 +454,6 @@ impl<'window> Renderer<'window> { multiview: None, cache: None, }); - let camera = Camera::new(&device, &camera_bind_group_layout, width, height); @@ -508,6 +476,36 @@ impl<'window> Renderer<'window> { // surface_config.format, ); + let font_bytes = include_bytes!("DejaVuSans.ttf"); + let font = FontRef::try_from_slice(font_bytes).map_err(|e| { + RenderContextError::new( + ContextErrorKind::DeviceRequest, + Some("Font loading".into()), + None, + ) + })?; + + let brush = + BrushBuilder::using_font(font).build(&device, width, height, surface_config.format); + let base_width = 1280.0; + let base_scale = 30.0; + let scale = base_scale * (surface_config.width as f32 / base_width as f32).clamp(0.5, 2.0); + let color = wgpu::Color::WHITE; + + let section = OwnedSection::default() + .add_text(OwnedText::new("FPS: 0.00").with_scale(scale).with_color([ + color.r as f32, + color.g as f32, + color.b as f32, + color.a as f32, + ])) + .with_screen_position((10.0, 10.0)) + .with_bounds((base_scale * 200.0, base_scale * 2.0)) + .with_layout( + Layout::default() + .h_align(HorizontalAlign::Left) + .v_align(VerticalAlign::Top), + ); Ok(Self { device, @@ -530,6 +528,13 @@ impl<'window> Renderer<'window> { frame_count: 0, depth_texture, depth_texture_view, + fps: 0f32, + font_state: FontState { + brush, + section, + scale, + color, + }, }) } @@ -549,12 +554,19 @@ impl<'window> Renderer<'window> { 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); + 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.font_state + .brush + .resize_view(width as f32, height as f32, &self.queue); + let base_width = 1280.0; + let base_scale = 30.0; + let scale = base_scale * (width as f32 / base_width as f32).clamp(0.5, 2.0); + self.font_state.scale = scale; self.camera.resize(width, height); } @@ -565,7 +577,8 @@ impl<'window> Renderer<'window> { 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.set_transform(Matrix4::from_angle_y(angle)); + // model.set_transform(Matrix4::from_angle_x(angle) * Matrix4::from_angle_y(angle)); model.update(&self.queue); } @@ -587,6 +600,25 @@ impl<'window> Renderer<'window> { .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render Encoder"), }); + let fps_text = format!("FPS: {:.2}", self.fps); + self.font_state.section.text.clear(); + self.font_state.section.text.push( + OwnedText::new(fps_text) + .with_scale(self.font_state.scale) + .with_color([ + self.font_state.color.r as f32, + self.font_state.color.g as f32, + self.font_state.color.b as f32, + self.font_state.color.a as f32, + ]), + ); + if let Err(e) = self.font_state.brush.queue( + &self.device, + &self.queue, + &[self.font_state.section.clone()], + ) { + error!("Failed to queue text: {}", e); + } { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { @@ -622,15 +654,35 @@ impl<'window> Renderer<'window> { render_pass.draw_indexed(0..model.index_count, 0, 0..1); } } + { + let mut text_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Text Render Pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + occlusion_query_set: None, + timestamp_writes: None, + }); + + self.font_state.brush.draw(&mut text_pass); + } self.queue.submit(Some(encoder.finish())); surface_texture.present(); self.frame_count += 1; + let elapsed_secs = self.last_frame_instant.elapsed().as_secs_f32(); if elapsed_secs >= 1.0 { let fps = self.frame_count as f32 / elapsed_secs; - trace!("FPS: {:.2}", fps); + // trace!("Renderer FPS: {:.2}", fps); + self.fps = fps; self.frame_count = 0; self.last_frame_instant = Instant::now(); } @@ -640,8 +692,14 @@ impl<'window> Renderer<'window> { self.bg_color = color; } - pub fn bg_color(&self) -> wgpu::Color { - self.bg_color + pub fn bg_color(&self) -> &wgpu::Color { + &self.bg_color + } + pub fn text_color(&self) -> &wgpu::Color { + &self.font_state.color + } + pub fn set_text_color(&mut self, color: wgpu::Color) { + self.font_state.color = color; } } fn create_depth_texture( @@ -670,4 +728,4 @@ fn create_depth_texture( 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 72c6cc6..b6e54e1 100644 --- a/engine/src/core/render/mod.rs +++ b/engine/src/core/render/mod.rs @@ -1,9 +1,11 @@ -use std::collections::HashMap; use std::ops::Deref; use std::sync::Arc; use ctx::{Renderer, Vertex}; -use tobj::LoadOptions; +use std::env; +use std::fs; +use std::path::PathBuf; +use tobj::{LoadOptions, Model}; use tracing::{debug, error, info, trace, warn}; use wgpu::rwh::HasWindowHandle; use winit::application::ApplicationHandler; @@ -34,163 +36,51 @@ impl WindowContext<'_> { #[derive(Default)] pub struct App<'window> { - windows: HashMap>, + windows: ahash::AHashMap>, } -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, -]; +static CUBE_OBJ: &str = " +# Blender 4.2.3 LTS +# www.blender.org +mtllib cube.mtl +o Cube +v 1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 1.000000 1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 -1.000000 1.000000 +vn -0.0000 1.0000 -0.0000 +vn -0.0000 -0.0000 1.0000 +vn -1.0000 -0.0000 -0.0000 +vn -0.0000 -1.0000 -0.0000 +vn 1.0000 -0.0000 -0.0000 +vn -0.0000 -0.0000 -1.0000 +vt 0.625000 0.500000 +vt 0.875000 0.500000 +vt 0.875000 0.750000 +vt 0.625000 0.750000 +vt 0.375000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 1.000000 +vt 0.375000 0.000000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.375000 0.250000 +vt 0.125000 0.500000 +vt 0.375000 0.500000 +vt 0.125000 0.750000 +s 0 +usemtl Material +f 1/1/1 5/2/1 7/3/1 3/4/1 +f 4/5/2 3/4/2 7/6/2 8/7/2 +f 8/8/3 7/9/3 5/10/3 6/11/3 +f 6/12/4 2/13/4 4/5/4 8/14/4 +f 2/13/5 1/1/5 3/4/5 4/5/5 +f 6/11/6 5/10/6 1/1/6 2/13/6 +"; impl App<'_> { fn create_main_window(&mut self, event_loop: &ActiveEventLoop) { @@ -202,9 +92,9 @@ impl App<'_> { match Renderer::new_blocking(window.clone()) { Ok(mut wgpu_ctx) => { let obj = match tobj::load_obj( - "test.obj", + "Pumpkin.obj", &LoadOptions { - triangulate: true, + triangulate: true, single_index: true, ..Default::default() }, @@ -215,29 +105,10 @@ impl App<'_> { panic!() } }; - let mesh = &obj.0.get(0).unwrap().mesh; + let (combined_vertices, combined_indices) = parse_obj(&obj.0); - 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(&combined_vertices, &combined_indices); - wgpu_ctx.add_model(&vertices, &mesh.indices); - // wgpu_ctx.add_model(CUBE_VERTICES,CUBE_INDICES); self.windows.insert( window_id, WindowContext { @@ -289,12 +160,21 @@ impl App<'_> { fn toggle_background(&mut self, window_id: WindowId) { if let Some(window_context) = self.windows.get_mut(&window_id) { let current_color = window_context.ctx.bg_color(); + let new_color = match current_color { - wgpu::Color::WHITE => wgpu::Color::BLACK, - wgpu::Color::BLACK => wgpu::Color::WHITE, + &wgpu::Color::WHITE => wgpu::Color::BLACK, + &wgpu::Color::BLACK => wgpu::Color::WHITE, _ => wgpu::Color::WHITE, }; + let new_text_color = match window_context.ctx.text_color() { + &wgpu::Color::WHITE => wgpu::Color::BLACK, + &wgpu::Color::BLACK => wgpu::Color::WHITE, + _ => wgpu::Color::WHITE, + }; + + println!("new text color {new_text_color:#?}"); window_context.ctx.set_bg_color(new_color); + window_context.ctx.set_text_color(new_text_color); debug!("Toggled background color for window {:?}", window_id); } else { warn!("No window context for toggling background: {:?}", window_id); @@ -318,7 +198,29 @@ impl App<'_> { let window_id = window.id(); match Renderer::new_blocking(window.clone()) { Ok(mut wgpu_ctx) => { - wgpu_ctx.add_model(CUBE_VERTICES,CUBE_INDICES); + { + let mut tmp_path: PathBuf = env::temp_dir(); + tmp_path.push("cube.obj"); + if let Err(e) = fs::write(&tmp_path, CUBE_OBJ) { + error!("Failed to write cube OBJ to temp: {:?}", e); + } + + let load_options = tobj::LoadOptions { + triangulate: true, + single_index: true, + ..Default::default() + }; + match tobj::load_obj(tmp_path.to_str().unwrap(), &load_options) { + Ok(cube_model) => { + let (cube_vertices, cube_indices) = + parse_obj(&cube_model.0); + wgpu_ctx.add_model(&cube_vertices, &cube_indices); + } + Err(e) => { + error!("Failed to load cube OBJ from temp file: {:?}", e) + } + } + } self.windows.insert( window_id, WindowContext { @@ -375,6 +277,39 @@ impl App<'_> { } } +fn parse_obj(obj: &Vec) -> (Vec, Vec) { + let mut combined_vertices = Vec::new(); + let mut combined_indices = Vec::new(); + let mut vertex_offset = 0; + + for object in obj { + let mesh: &_ = &object.mesh; + 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(); + combined_vertices.extend(vertices); + combined_indices.extend(mesh.indices.iter().map(|&index| index + vertex_offset)); + vertex_offset += (mesh.positions.len() as u32) / 3; + } + + (combined_vertices, combined_indices) +} + impl ApplicationHandler for App<'_> { fn resumed(&mut self, event_loop: &ActiveEventLoop) { if self.windows.is_empty() { diff --git a/engine/src/core/render/shader.wgsl b/engine/src/core/render/shader.wgsl new file mode 100644 index 0000000..90780f1 --- /dev/null +++ b/engine/src/core/render/shader.wgsl @@ -0,0 +1,42 @@ +struct CameraUniform { + view: mat4x4, + proj: mat4x4, +}; + +struct ModelUniform { + model: mat4x4, +}; + +@group(0) @binding(0) +var camera: CameraUniform; + +@group(1) @binding(0) +var model: ModelUniform; + +struct VertexInput { + @location(0) position: vec3, + @location(1) normal: vec3, +}; + +struct VertexOutput { + @builtin(position) clip_position: vec4, + @location(0) normal: vec3, +}; + +@vertex +fn vs_main(input: VertexInput) -> VertexOutput { + var output: VertexOutput; + 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); + let brightness = ambient + (1.0 - ambient) * diffuse; + return vec4(0.7 * brightness, 0.7 * brightness, 0.9 * brightness, 1.0); +} \ No newline at end of file diff --git a/engine/src/main.rs b/engine/src/main.rs index ff47bb2..25413fe 100644 --- a/engine/src/main.rs +++ b/engine/src/main.rs @@ -5,9 +5,7 @@ use tokio::runtime; #[allow(unused_imports)] 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() { @@ -27,7 +25,6 @@ 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/flake.lock b/flake.lock index 59dab09..1c67c8f 100644 --- a/flake.lock +++ b/flake.lock @@ -77,11 +77,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1742422364, - "narHash": "sha256-mNqIplmEohk5jRkqYqG19GA8MbQ/D4gQSK0Mu4LvfRQ=", + "lastModified": 1743095683, + "narHash": "sha256-gWd4urRoLRe8GLVC/3rYRae1h+xfQzt09xOfb0PaHSk=", "owner": "nixos", "repo": "nixpkgs", - "rev": "a84ebe20c6bc2ecbcfb000a50776219f48d134cc", + "rev": "5e5402ecbcb27af32284d4a62553c019a3a49ea6", "type": "github" }, "original": { @@ -138,11 +138,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1742610648, - "narHash": "sha256-9jWi3gw3fEIgEslnFjH/s1I+Iyf1+4t5B1Ed1FOiy8o=", + "lastModified": 1743215516, + "narHash": "sha256-52qbrkG65U1hyrQWltgHTgH4nm0SJL+9TWv2UDCEPNI=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "c60d41987df3c853e2a842de2c63ded40400979b", + "rev": "524463199fdee49338006b049bc376b965a2cfed", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index fca13cb..49c15bc 100644 --- a/flake.nix +++ b/flake.nix @@ -52,7 +52,9 @@ devShells.default = pkgs.mkShell { name = "zenyx"; nativeBuildInputs = with pkgs; [ - rust-bin.stable.latest.default + (rust-bin.stable.latest.default.override { + extensions = ["rust-src" "cargo" "rustfmt" "clippy"]; + }) pkg-config ]; buildInputs = buildInputs; diff --git a/test.obj b/test.obj deleted file mode 100644 index 119d05f..0000000 --- a/test.obj +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f3b4f6fd5bd7fa4342ae261e90835debf2331af0a10bca44857318264587cbdf -size 63027