formatting
This commit is contained in:
parent
d0d0e7c016
commit
11194e863e
13 changed files with 515 additions and 2689 deletions
|
@ -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"
|
||||
|
|
|
@ -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<const N: usize> {
|
||||
bytes: [u8; N],
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl<const N: usize> BigInt<N> {
|
||||
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<const N: usize> Add for BigInt<N> {
|
||||
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<const N: usize> AddAssign for BigInt<N> {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self = *self + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Sub for BigInt<N> {
|
||||
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<const N: usize> SubAssign for BigInt<N> {
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self = *self - rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Mul for BigInt<N> {
|
||||
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<const N: usize> MulAssign for BigInt<N> {
|
||||
fn mul_assign(&mut self, rhs: Self) {
|
||||
*self = *self * rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Div for BigInt<N> {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: Self) -> Self {
|
||||
self.div_rem(&rhs).0
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> DivAssign for BigInt<N> {
|
||||
fn div_assign(&mut self, rhs: Self) {
|
||||
*self = *self / rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Rem for BigInt<N> {
|
||||
type Output = Self;
|
||||
fn rem(self, rhs: Self) -> Self {
|
||||
self.div_rem(&rhs).1
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> RemAssign for BigInt<N> {
|
||||
fn rem_assign(&mut self, rhs: Self) {
|
||||
*self = *self % rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> PartialEq for BigInt<N> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.bytes[..self.len] == other.bytes[..other.len]
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Eq for BigInt<N> {}
|
||||
|
||||
impl<const N: usize> Hash for BigInt<N> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.bytes[..self.len].hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> PartialOrd for BigInt<N> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Ord for BigInt<N> {
|
||||
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<const N: usize> Deref for BigInt<N> {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
&self.bytes[..self.len]
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> DerefMut for BigInt<N> {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.bytes[..self.len]
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_from_int {
|
||||
($($t:ty),*) => {$(
|
||||
impl<const N: usize> From<$t> for BigInt<N> {
|
||||
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<const N: usize> FromStr for BigInt<N> {
|
||||
type Err = &'static str;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
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<const N: usize> fmt::Display for BigInt<N> {
|
||||
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::<String>();
|
||||
write!(f, "{}", s)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
|
||||
struct Dint {
|
||||
bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
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}")
|
||||
}
|
BIN
engine/src/core/render/DejaVuSans.ttf
Normal file
BIN
engine/src/core/render/DejaVuSans.ttf
Normal file
Binary file not shown.
|
@ -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<wgpu::RequestDeviceError> for RenderContextError {
|
|||
}
|
||||
}
|
||||
|
||||
const SHADER_SRC: &str = r#"
|
||||
struct CameraUniform {
|
||||
view: mat4x4<f32>,
|
||||
proj: mat4x4<f32>,
|
||||
};
|
||||
|
||||
struct ModelUniform {
|
||||
model: mat4x4<f32>,
|
||||
};
|
||||
|
||||
@group(0) @binding(0)
|
||||
var<uniform> camera: CameraUniform;
|
||||
|
||||
@group(1) @binding(0)
|
||||
var<uniform> model: ModelUniform;
|
||||
|
||||
struct VertexInput {
|
||||
@location(0) position: vec3<f32>,
|
||||
@location(1) normal: vec3<f32>,
|
||||
};
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) clip_position: vec4<f32>,
|
||||
@location(0) normal: vec3<f32>,
|
||||
};
|
||||
|
||||
@vertex
|
||||
fn vs_main(input: VertexInput) -> VertexOutput {
|
||||
var output: VertexOutput;
|
||||
let model_pos = model.model * vec4<f32>(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<f32> {
|
||||
let ambient: f32 = 0.2;
|
||||
let light_dir = normalize(vec3<f32>(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<f32>(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<f32>,
|
||||
}
|
||||
|
||||
|
@ -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<FontRef<'static>>,
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<WindowId, WindowContext<'window>>,
|
||||
windows: ahash::AHashMap<WindowId, WindowContext<'window>>,
|
||||
}
|
||||
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<Vertex> = (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<Model>) -> (Vec<Vertex>, Vec<u32>) {
|
||||
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<Vertex> = (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() {
|
||||
|
|
42
engine/src/core/render/shader.wgsl
Normal file
42
engine/src/core/render/shader.wgsl
Normal file
|
@ -0,0 +1,42 @@
|
|||
struct CameraUniform {
|
||||
view: mat4x4<f32>,
|
||||
proj: mat4x4<f32>,
|
||||
};
|
||||
|
||||
struct ModelUniform {
|
||||
model: mat4x4<f32>,
|
||||
};
|
||||
|
||||
@group(0) @binding(0)
|
||||
var<uniform> camera: CameraUniform;
|
||||
|
||||
@group(1) @binding(0)
|
||||
var<uniform> model: ModelUniform;
|
||||
|
||||
struct VertexInput {
|
||||
@location(0) position: vec3<f32>,
|
||||
@location(1) normal: vec3<f32>,
|
||||
};
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) clip_position: vec4<f32>,
|
||||
@location(0) normal: vec3<f32>,
|
||||
};
|
||||
|
||||
@vertex
|
||||
fn vs_main(input: VertexInput) -> VertexOutput {
|
||||
var output: VertexOutput;
|
||||
let model_pos = model.model * vec4<f32>(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<f32> {
|
||||
let ambient: f32 = 0.2;
|
||||
let light_dir = normalize(vec3<f32>(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<f32>(0.7 * brightness, 0.7 * brightness, 0.9 * brightness, 1.0);
|
||||
}
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue