From 66c444371a19d398337df92c6a12668195ce2c18 Mon Sep 17 00:00:00 2001 From: lisk77 Date: Sun, 26 Oct 2025 15:21:26 +0100 Subject: [PATCH] refactor(renderer2d): modularized and abstracted away the render context --- crates/comet_renderer/src/camera.rs | 472 ++++----- crates/comet_renderer/src/lib.rs | 3 +- crates/comet_renderer/src/render_context.rs | 126 +++ crates/comet_renderer/src/renderer2d.rs | 948 +------------------ crates/comet_renderer/src/renderer2d_/mod.rs | 8 + 5 files changed, 412 insertions(+), 1145 deletions(-) create mode 100644 crates/comet_renderer/src/render_context.rs mode change 100755 => 100644 crates/comet_renderer/src/renderer2d.rs diff --git a/crates/comet_renderer/src/camera.rs b/crates/comet_renderer/src/camera.rs index 52a76d1..ac34622 100644 --- a/crates/comet_renderer/src/camera.rs +++ b/crates/comet_renderer/src/camera.rs @@ -1,3 +1,4 @@ +use comet_log::fatal; use comet_math::{m4, p3, v2, v3}; #[rustfmt::skip] @@ -10,63 +11,89 @@ pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4 = cgmath::Matrix4::new( const SAFE_FRAC_PI_2: f32 = std::f32::consts::FRAC_PI_2 - 0.0001; +pub struct CameraManager { + cameras: Vec, + active_camera: usize, +} + +impl CameraManager { + pub fn new() -> Self { + Self { + cameras: Vec::new(), + active_camera: 0, + } + } + + pub fn set_cameras(&mut self, cameras: Vec) { + self.cameras = cameras + } + + pub fn set_active(&mut self, active: usize) { + if active >= self.cameras.len() { + fatal!("Active camera index is out of range of the RenderCamera array!") + } + } + + pub fn get_camera(&self) -> &RenderCamera { + self.cameras.get(self.active_camera).unwrap() + } +} + pub struct RenderCamera { - zoom: f32, - dimension: v2, - position: v3 + zoom: f32, + dimension: v2, + position: v3, } impl RenderCamera { - pub fn new( - zoom: f32, - dimension: v2, - position: v3 - ) -> Self { - Self { - zoom, - dimension, - position - } - } + pub fn new(zoom: f32, dimension: v2, position: v3) -> Self { + Self { + zoom, + dimension, + position, + } + } - pub fn build_view_projection_matrix(&self) -> m4 { - let zoomed_width = self.dimension.x() / self.zoom; - let zoomed_height = self.dimension.y() / self.zoom; + pub fn build_view_projection_matrix(&self) -> m4 { + let zoomed_width = self.dimension.x() / self.zoom; + let zoomed_height = self.dimension.y() / self.zoom; - m4::OPENGL_CONV * m4::orthographic_projection(self.position.x() - zoomed_width / 2.0, - self.position.x() + zoomed_width / 2.0, - self.position.y() - zoomed_height / 2.0, - self.position.y() + zoomed_height / 2.0, - 1.0, - 0.0) + m4::OPENGL_CONV + * m4::orthographic_projection( + self.position.x() - zoomed_width / 2.0, + self.position.x() + zoomed_width / 2.0, + self.position.y() - zoomed_height / 2.0, + self.position.y() + zoomed_height / 2.0, + 1.0, + 0.0, + ) - /*OPENGL_TO_WGPU_MATRIX * cgmath::ortho(self.position.x() - zoomed_width / 2.0, - self.position.x() + zoomed_width / 2.0, - self.position.y() - zoomed_height / 2.0, - self.position.y() + zoomed_height / 2.0, - 1.0, - 0.0)*/ - } + /*OPENGL_TO_WGPU_MATRIX * cgmath::ortho(self.position.x() - zoomed_width / 2.0, + self.position.x() + zoomed_width / 2.0, + self.position.y() - zoomed_height / 2.0, + self.position.y() + zoomed_height / 2.0, + 1.0, + 0.0)*/ + } } - #[repr(C)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] pub struct CameraUniform { - view_proj: [[f32; 4]; 4], + view_proj: [[f32; 4]; 4], } impl CameraUniform { - pub fn new() -> Self { - use cgmath::SquareMatrix; - Self { - view_proj: cgmath::Matrix4::identity().into(), - } - } + pub fn new() -> Self { + use cgmath::SquareMatrix; + Self { + view_proj: cgmath::Matrix4::identity().into(), + } + } - pub fn update_view_proj(&mut self, camera: &RenderCamera) { - self.view_proj = camera.build_view_projection_matrix().into(); - } + pub fn update_view_proj(&mut self, camera: &RenderCamera) { + self.view_proj = camera.build_view_projection_matrix().into(); + } } /*use comet_math::{Mat4, Point3, Vec3}; @@ -79,52 +106,52 @@ pub const OPENGL_TO_WGPU_MATRIX: Mat4 = Mat4::new( ); pub struct Camera { - eye: Point3, - target: Point3, - up: Vec3, - aspect: f32, - fovy: f32, - znear: f32, - zfar: f32, + eye: Point3, + target: Point3, + up: Vec3, + aspect: f32, + fovy: f32, + znear: f32, + zfar: f32, } impl Camera { - pub fn new(eye: Point3, target: Point3, up: Vec3, aspect: f32, fovy: f32, znear: f32, zfar: f32) -> Self { - Self { - eye, - target, - up, - aspect, - fovy, - znear, - zfar, - } - } + pub fn new(eye: Point3, target: Point3, up: Vec3, aspect: f32, fovy: f32, znear: f32, zfar: f32) -> Self { + Self { + eye, + target, + up, + aspect, + fovy, + znear, + zfar, + } + } - pub fn build_view_projection_matrix(&self) -> Mat4 { - let view = Mat4::look_at_rh(self.eye, self.target, self.up); - let proj = Mat4::perspective_matrix(self.fovy, self.aspect, self.znear, self.zfar); + pub fn build_view_projection_matrix(&self) -> Mat4 { + let view = Mat4::look_at_rh(self.eye, self.target, self.up); + let proj = Mat4::perspective_matrix(self.fovy, self.aspect, self.znear, self.zfar); - (OPENGL_TO_WGPU_MATRIX * proj * view).transpose() - } + (OPENGL_TO_WGPU_MATRIX * proj * view).transpose() + } } #[repr(C)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] pub struct CameraUniform { - view_proj: [[f32; 4]; 4], + view_proj: [[f32; 4]; 4], } impl CameraUniform { - pub fn new() -> Self { - Self { - view_proj: Mat4::IDENTITY.into(), - } - } + pub fn new() -> Self { + Self { + view_proj: Mat4::IDENTITY.into(), + } + } - pub fn update_view_proj(&mut self, camera: &Camera) { - self.view_proj = camera.build_view_projection_matrix().into(); - } + pub fn update_view_proj(&mut self, camera: &Camera) { + self.view_proj = camera.build_view_projection_matrix().into(); + } }*/ /*use std::f32::consts::FRAC_PI_2; @@ -137,182 +164,183 @@ const SAFE_FRAC_PI_2: f32 = FRAC_PI_2 - 0.0001; #[derive(Debug)] pub struct Camera3D { - pub position: Point3, - yaw: f32, - pitch: f32, + pub position: Point3, + yaw: f32, + pitch: f32, } impl Camera3D { - pub fn new( - position: Point3, - yaw: f32, - pitch: f32, - ) -> Self { - Self { - position: position.into(), - yaw: yaw.into(), - pitch: pitch.into(), - } - } + pub fn new( + position: Point3, + yaw: f32, + pitch: f32, + ) -> Self { + Self { + position: position.into(), + yaw: yaw.into(), + pitch: pitch.into(), + } + } - pub fn calc_matrix(&self) -> Mat4 { - let (sin_pitch, cos_pitch) = self.pitch.0.sin_cos(); - let (sin_yaw, cos_yaw) = self.yaw.0.sin_cos(); + pub fn calc_matrix(&self) -> Mat4 { + let (sin_pitch, cos_pitch) = self.pitch.0.sin_cos(); + let (sin_yaw, cos_yaw) = self.yaw.0.sin_cos(); - Mat4::look_to_rh( - self.position, - Vec3::new(cos_pitch * cos_yaw, sin_pitch, cos_pitch * sin_yaw).normalize(), - Vec3::unit_y(), - ) - } + Mat4::look_to_rh( + self.position, + Vec3::new(cos_pitch * cos_yaw, sin_pitch, cos_pitch * sin_yaw).normalize(), + Vec3::unit_y(), + ) + } } pub struct Projection { - aspect: f32, - fovy: Rad, - znear: f32, - zfar: f32, + aspect: f32, + fovy: Rad, + znear: f32, + zfar: f32, } impl Projection { - pub fn new>>(width: u32, height: u32, fovy: F, znear: f32, zfar: f32) -> Self { - Self { - aspect: width as f32 / height as f32, - fovy: fovy.into(), - znear, - zfar, - } - } + pub fn new>>(width: u32, height: u32, fovy: F, znear: f32, zfar: f32) -> Self { + Self { + aspect: width as f32 / height as f32, + fovy: fovy.into(), + znear, + zfar, + } + } - pub fn resize(&mut self, width: u32, height: u32) { - self.aspect = width as f32 / height as f32; - } + pub fn resize(&mut self, width: u32, height: u32) { + self.aspect = width as f32 / height as f32; + } - pub fn calc_matrix(&self) -> Matrix4 { - // UDPATE - perspective(self.fovy, self.aspect, self.znear, self.zfar) - } + pub fn calc_matrix(&self) -> Matrix4 { + // UDPATE + perspective(self.fovy, self.aspect, self.znear, self.zfar) + } } #[derive(Debug)] pub struct CameraController { - amount_left: f32, - amount_right: f32, - amount_forward: f32, - amount_backward: f32, - amount_up: f32, - amount_down: f32, - rotate_horizontal: f32, - rotate_vertical: f32, - scroll: f32, - speed: f32, - sensitivity: f32, + amount_left: f32, + amount_right: f32, + amount_forward: f32, + amount_backward: f32, + amount_up: f32, + amount_down: f32, + rotate_horizontal: f32, + rotate_vertical: f32, + scroll: f32, + speed: f32, + sensitivity: f32, } impl CameraController { - pub fn new(speed: f32, sensitivity: f32) -> Self { - Self { - amount_left: 0.0, - amount_right: 0.0, - amount_forward: 0.0, - amount_backward: 0.0, - amount_up: 0.0, - amount_down: 0.0, - rotate_horizontal: 0.0, - rotate_vertical: 0.0, - scroll: 0.0, - speed, - sensitivity, - } - } + pub fn new(speed: f32, sensitivity: f32) -> Self { + Self { + amount_left: 0.0, + amount_right: 0.0, + amount_forward: 0.0, + amount_backward: 0.0, + amount_up: 0.0, + amount_down: 0.0, + rotate_horizontal: 0.0, + rotate_vertical: 0.0, + scroll: 0.0, + speed, + sensitivity, + } + } - pub fn process_keyboard(&mut self, key: KeyCode, state: ElementState) -> bool { - let amount = if state == ElementState::Pressed { - 1.0 - } else { - 0.0 - }; - match key { - KeyCode::KeyW | KeyCode::ArrowUp => { - self.amount_forward = amount; - true - } - KeyCode::KeyS | KeyCode::ArrowDown => { - self.amount_backward = amount; - true - } - KeyCode::KeyA | KeyCode::ArrowLeft => { - self.amount_left = amount; - true - } - KeyCode::KeyD | KeyCode::ArrowRight => { - self.amount_right = amount; - true - } - KeyCode::Space => { - self.amount_up = amount; - true - } - KeyCode::ShiftLeft => { - self.amount_down = amount; - true - } - _ => false, - } - } + pub fn process_keyboard(&mut self, key: KeyCode, state: ElementState) -> bool { + let amount = if state == ElementState::Pressed { + 1.0 + } else { + 0.0 + }; + match key { + KeyCode::KeyW | KeyCode::ArrowUp => { + self.amount_forward = amount; + true + } + KeyCode::KeyS | KeyCode::ArrowDown => { + self.amount_backward = amount; + true + } + KeyCode::KeyA | KeyCode::ArrowLeft => { + self.amount_left = amount; + true + } + KeyCode::KeyD | KeyCode::ArrowRight => { + self.amount_right = amount; + true + } + KeyCode::Space => { + self.amount_up = amount; + true + } + KeyCode::ShiftLeft => { + self.amount_down = amount; + true + } + _ => false, + } + } - pub fn process_mouse(&mut self, mouse_dx: f64, mouse_dy: f64) { - self.rotate_horizontal = mouse_dx as f32; - self.rotate_vertical = mouse_dy as f32; - } + pub fn process_mouse(&mut self, mouse_dx: f64, mouse_dy: f64) { + self.rotate_horizontal = mouse_dx as f32; + self.rotate_vertical = mouse_dy as f32; + } - pub fn process_scroll(&mut self, delta: &MouseScrollDelta) { - self.scroll = match delta { - // I'm assuming a line is about 100 pixels - MouseScrollDelta::LineDelta(_, scroll) => -scroll * 0.5, - MouseScrollDelta::PixelDelta(PhysicalPosition { y: scroll, .. }) => -*scroll as f32, - }; - } + pub fn process_scroll(&mut self, delta: &MouseScrollDelta) { + self.scroll = match delta { + // I'm assuming a line is about 100 pixels + MouseScrollDelta::LineDelta(_, scroll) => -scroll * 0.5, + MouseScrollDelta::PixelDelta(PhysicalPosition { y: scroll, .. }) => -*scroll as f32, + }; + } - pub fn update_camera(&mut self, camera: &mut Camera, dt: Duration) { - let dt = dt.as_secs_f32(); + pub fn update_camera(&mut self, camera: &mut Camera, dt: Duration) { + let dt = dt.as_secs_f32(); - // Move forward/backward and left/right - let (yaw_sin, yaw_cos) = camera.yaw.0.sin_cos(); - let forward = Vector3::new(yaw_cos, 0.0, yaw_sin).normalize(); - let right = Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize(); - camera.position += forward * (self.amount_forward - self.amount_backward) * self.speed * dt; - camera.position += right * (self.amount_right - self.amount_left) * self.speed * dt; + // Move forward/backward and left/right + let (yaw_sin, yaw_cos) = camera.yaw.0.sin_cos(); + let forward = Vector3::new(yaw_cos, 0.0, yaw_sin).normalize(); + let right = Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize(); + camera.position += forward * (self.amount_forward - self.amount_backward) * self.speed * dt; + camera.position += right * (self.amount_right - self.amount_left) * self.speed * dt; - // Move in/out (aka. "zoom") - // Note: this isn't an actual zoom. The camera's position - // changes when zooming. I've added this to make it easier - // to get closer to an object you want to focus on. - let (pitch_sin, pitch_cos) = camera.pitch.0.sin_cos(); - let scrollward = - Vector3::new(pitch_cos * yaw_cos, pitch_sin, pitch_cos * yaw_sin).normalize(); - camera.position += scrollward * self.scroll * self.speed * self.sensitivity * dt; - self.scroll = 0.0; + // Move in/out (aka. "zoom") + // Note: this isn't an actual zoom. The camera's position + // changes when zooming. I've added this to make it easier + // to get closer to an object you want to focus on. + let (pitch_sin, pitch_cos) = camera.pitch.0.sin_cos(); + let scrollward = + Vector3::new(pitch_cos * yaw_cos, pitch_sin, pitch_cos * yaw_sin).normalize(); + camera.position += scrollward * self.scroll * self.speed * self.sensitivity * dt; + self.scroll = 0.0; - // Move up/down. Since we don't use roll, we can just - // modify the y coordinate directly. - camera.position.y += (self.amount_up - self.amount_down) * self.speed * dt; + // Move up/down. Since we don't use roll, we can just + // modify the y coordinate directly. + camera.position.y += (self.amount_up - self.amount_down) * self.speed * dt; - // Rotate - camera.yaw += Rad(self.rotate_horizontal) * self.sensitivity * dt; - camera.pitch += Rad(-self.rotate_vertical) * self.sensitivity * dt; + // Rotate + camera.yaw += Rad(self.rotate_horizontal) * self.sensitivity * dt; + camera.pitch += Rad(-self.rotate_vertical) * self.sensitivity * dt; - // If process_mouse isn't called every frame, these values - // will not get set to zero, and the camera will rotate - // when moving in a non cardinal direction. - self.rotate_horizontal = 0.0; - self.rotate_vertical = 0.0; + // If process_mouse isn't called every frame, these values + // will not get set to zero, and the camera will rotate + // when moving in a non cardinal direction. + self.rotate_horizontal = 0.0; + self.rotate_vertical = 0.0; + + // Keep the camera's angle from going too high/low. + if camera.pitch < -Rad(SAFE_FRAC_PI_2) { + camera.pitch = -Rad(SAFE_FRAC_PI_2); + } else if camera.pitch > Rad(SAFE_FRAC_PI_2) { + camera.pitch = Rad(SAFE_FRAC_PI_2); + } + } +}*/ - // Keep the camera's angle from going too high/low. - if camera.pitch < -Rad(SAFE_FRAC_PI_2) { - camera.pitch = -Rad(SAFE_FRAC_PI_2); - } else if camera.pitch > Rad(SAFE_FRAC_PI_2) { - camera.pitch = Rad(SAFE_FRAC_PI_2); - } - } -}*/ \ No newline at end of file diff --git a/crates/comet_renderer/src/lib.rs b/crates/comet_renderer/src/lib.rs index f9667c2..44e7918 100644 --- a/crates/comet_renderer/src/lib.rs +++ b/crates/comet_renderer/src/lib.rs @@ -1,7 +1,6 @@ mod camera; mod draw_info; +pub mod render_context; mod render_group; -mod render_pass; pub mod renderer; pub mod renderer2d; -pub mod renderer2d_; diff --git a/crates/comet_renderer/src/render_context.rs b/crates/comet_renderer/src/render_context.rs new file mode 100644 index 0000000..6ba7e9f --- /dev/null +++ b/crates/comet_renderer/src/render_context.rs @@ -0,0 +1,126 @@ +use comet_colors::Color; +use std::sync::Arc; +use winit::{dpi::PhysicalSize, window::Window}; + +pub struct RenderContext<'a> { + device: wgpu::Device, + queue: wgpu::Queue, + surface: wgpu::Surface<'a>, + config: wgpu::SurfaceConfiguration, + size: PhysicalSize, + scale_factor: f64, + clear_color: wgpu::Color, +} + +impl<'a> RenderContext<'a> { + pub fn new(window: Arc, clear_color: Option) -> Self { + let size = window.inner_size(); + let scale_factor = window.scale_factor(); + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: wgpu::Backends::PRIMARY, + ..Default::default() + }); + + let surface = instance.create_surface(window).unwrap(); + + let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::default(), + compatible_surface: Some(&surface), + force_fallback_adapter: false, + })) + .unwrap(); + + let (device, queue) = pollster::block_on(adapter.request_device( + &wgpu::DeviceDescriptor { + label: None, + required_features: wgpu::Features::empty(), + required_limits: wgpu::Limits::default(), + memory_hints: Default::default(), + }, + None, // Trace path + )) + .unwrap(); + + let surface_caps = surface.get_capabilities(&adapter); + let surface_format = surface_caps + .formats + .iter() + .copied() + .find(|f| f.is_srgb()) + .unwrap_or(surface_caps.formats[0]); + let config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: surface_format, + width: size.width, + height: size.height, + present_mode: surface_caps.present_modes[0], + alpha_mode: surface_caps.alpha_modes[0], + view_formats: vec![], + desired_maximum_frame_latency: 2, + }; + + let clear_color = match clear_color { + Some(color) => color.to_wgpu(), + None => wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 1.0, + }, + }; + + Self { + device, + queue, + surface, + config, + size, + scale_factor, + clear_color, + } + } + + pub fn device(&self) -> &wgpu::Device { + &self.device + } + + pub fn queue(&self) -> &wgpu::Queue { + &self.queue + } + + pub fn surface(&self) -> &wgpu::Surface { + &self.surface + } + + pub fn configure_surface(&mut self) { + self.surface.configure(&self.device, &self.config); + } + + pub fn config(&self) -> &wgpu::SurfaceConfiguration { + &self.config + } + + pub fn config_mut(&mut self) -> &mut wgpu::SurfaceConfiguration { + &mut self.config + } + + pub fn size(&self) -> PhysicalSize { + self.size + } + + pub fn set_size(&mut self, new_size: PhysicalSize) { + self.size = new_size + } + + pub fn scale_factor(&self) -> f64 { + self.scale_factor + } + + pub fn set_scale_factor(&mut self, scale_factor: f64) { + self.scale_factor = scale_factor + } + + pub fn clear_color(&self) -> wgpu::Color { + self.clear_color + } +} diff --git a/crates/comet_renderer/src/renderer2d.rs b/crates/comet_renderer/src/renderer2d.rs old mode 100755 new mode 100644 index 93b78f5..f95cc4f --- a/crates/comet_renderer/src/renderer2d.rs +++ b/crates/comet_renderer/src/renderer2d.rs @@ -1,948 +1,54 @@ -use crate::{ - camera::{CameraUniform, RenderCamera}, - draw_info::DrawInfo, - renderer::Renderer, -}; +use crate::renderer::Renderer; +use crate::{camera::CameraManager, render_context::RenderContext}; use comet_colors::Color; -use comet_ecs::{Camera2D, Component, Position2D, Render, Render2D, Scene, Text, Transform2D}; -use comet_log::*; -use comet_math::{p2, v2, v3}; -use comet_resources::texture_atlas::TextureRegion; -use comet_resources::{graphic_resource_manager::GraphicResourceManager, Texture, Vertex}; -use comet_structs::ComponentSet; -use std::iter; -use std::path::PathBuf; +use comet_resources::graphic_resource_manager::GraphicResourceManager; use std::sync::Arc; -use std::time::Instant; -use wgpu::naga::ShaderStage; -use wgpu::util::DeviceExt; -use wgpu::BufferUsages; -use winit::dpi::PhysicalSize; -use winit::window::Window; +use winit::{dpi::PhysicalSize, window::Window}; pub struct Renderer2D<'a> { - surface: wgpu::Surface<'a>, - device: wgpu::Device, - queue: wgpu::Queue, - config: wgpu::SurfaceConfiguration, - size: PhysicalSize, - scale_factor: f64, - universal_render_pipeline: wgpu::RenderPipeline, - texture_bind_group_layout: wgpu::BindGroupLayout, - texture_sampler: wgpu::Sampler, - camera: RenderCamera, - camera_uniform: CameraUniform, - camera_buffer: wgpu::Buffer, - camera_bind_group: wgpu::BindGroup, - draw_info: Vec, - graphic_resource_manager: GraphicResourceManager, + render_context: RenderContext<'a>, + resource_manager: GraphicResourceManager, + camera_manager: CameraManager, delta_time: f32, - last_frame_time: Instant, - clear_color: wgpu::Color, -} - -impl<'a> Renderer2D<'a> { - pub fn new(window: Arc, clear_color: Option) -> Renderer2D<'a> { - let size = window.inner_size(); //PhysicalSize::::new(1920, 1080); - let scale_factor = window.scale_factor(); - - let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { - backends: wgpu::Backends::PRIMARY, - ..Default::default() - }); - - let surface = instance.create_surface(window).unwrap(); - - let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { - power_preference: wgpu::PowerPreference::default(), - compatible_surface: Some(&surface), - force_fallback_adapter: false, - })) - .unwrap(); - - let (device, queue) = pollster::block_on(adapter.request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: wgpu::Features::empty(), - required_limits: wgpu::Limits::default(), - memory_hints: Default::default(), - }, - None, // Trace path - )) - .unwrap(); - - let surface_caps = surface.get_capabilities(&adapter); - let surface_format = surface_caps - .formats - .iter() - .copied() - .find(|f| f.is_srgb()) - .unwrap_or(surface_caps.formats[0]); - let config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: surface_format, - width: size.width, - height: size.height, - present_mode: surface_caps.present_modes[0], - alpha_mode: surface_caps.alpha_modes[0], - view_formats: vec![], - desired_maximum_frame_latency: 2, - }; - - let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("Universal Shader"), - source: wgpu::ShaderSource::Wgsl(include_str!("base2d.wgsl").into()), - }); - - let graphic_resource_manager = GraphicResourceManager::new(); - - let texture_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D2, - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), - count: None, - }, - ], - label: Some("Universal Texture Bind Group Layout"), - }); - - let camera = RenderCamera::new(1.0, v2::new(2.0, 2.0), v3::new(0.0, 0.0, 0.0)); - - let mut camera_uniform = CameraUniform::new(); - camera_uniform.update_view_proj(&camera); - - let camera_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Camera Buffer"), - contents: bytemuck::cast_slice(&[camera_uniform]), - usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST, - }); - - let camera_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }], - label: Some("Universal Camera Bind Group Layout"), - }); - - let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &camera_bind_group_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: camera_buffer.as_entire_binding(), - }], - label: Some("Universal Camera Bind Group"), - }); - - let render_pipeline_layout = - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Universal Render Pipeline Layout"), - bind_group_layouts: &[&texture_bind_group_layout, &camera_bind_group_layout], - push_constant_ranges: &[], - }); - - let universal_render_pipeline = - device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Universal Render Pipeline"), - layout: Some(&render_pipeline_layout), - vertex: wgpu::VertexState { - module: &shader, - entry_point: "vs_main", - buffers: &[Vertex::desc()], - compilation_options: Default::default(), - }, - fragment: Some(wgpu::FragmentState { - module: &shader, - entry_point: "fs_main", - targets: &[Some(wgpu::ColorTargetState { - format: config.format, - blend: Some(wgpu::BlendState { - color: wgpu::BlendComponent { - src_factor: wgpu::BlendFactor::SrcAlpha, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - alpha: wgpu::BlendComponent { - src_factor: wgpu::BlendFactor::One, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - }), - write_mask: wgpu::ColorWrites::ALL, - })], - 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), - polygon_mode: wgpu::PolygonMode::Fill, - unclipped_depth: false, - conservative: false, - }, - depth_stencil: None, - multisample: wgpu::MultisampleState { - count: 1, - mask: !0, - alpha_to_coverage_enabled: false, - }, - multiview: None, - cache: None, - }); - - let clear_color = match clear_color { - Some(color) => color.to_wgpu(), - None => wgpu::Color { - r: 0.0, - g: 0.0, - b: 0.0, - a: 1.0, - }, - }; - - let texture_sampler = device.create_sampler(&wgpu::SamplerDescriptor { - address_mode_u: wgpu::AddressMode::ClampToEdge, - address_mode_v: wgpu::AddressMode::ClampToEdge, - address_mode_w: wgpu::AddressMode::ClampToEdge, - mag_filter: wgpu::FilterMode::Linear, - min_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::FilterMode::Linear, - lod_min_clamp: 0.0, - lod_max_clamp: 100.0, - compare: None, - anisotropy_clamp: 16, - border_color: None, - ..Default::default() - }); - - let mut draw_info: Vec = Vec::new(); - draw_info.push(DrawInfo::new( - "Universal Draw".to_string(), - &device, - &Texture::from_image( - &device, - &queue, - &image::DynamicImage::new(1, 1, image::ColorType::Rgba8), - None, - false, - ) - .unwrap(), - &texture_bind_group_layout, - &texture_sampler, - vec![], - vec![], - )); - - Self { - surface, - device, - queue, - config, - size, - scale_factor, - universal_render_pipeline, - texture_bind_group_layout, - texture_sampler, - camera, - camera_uniform, - camera_buffer, - camera_bind_group, - draw_info, - graphic_resource_manager, - delta_time: 0.0, - last_frame_time: Instant::now(), - clear_color, - } - } - - pub fn dt(&self) -> f32 { - self.delta_time - } - - pub fn config(&self) -> &wgpu::SurfaceConfiguration { - &self.config - } - - pub fn size(&self) -> PhysicalSize { - self.size - } - - pub fn resize(&mut self, new_size: PhysicalSize) { - if new_size.width > 0 && new_size.height > 0 { - self.size = new_size; - self.config.width = new_size.width; - self.config.height = new_size.height; - self.surface.configure(&self.device, &self.config); - } - } - - pub fn scale_factor(&self) -> f64 { - self.scale_factor - } - - pub fn set_scale_factor(&mut self, scale_factor: f64) { - self.scale_factor = scale_factor - } - - pub fn add_draw_call(&mut self, draw_call: String, texture: Texture) { - let draw_info = DrawInfo::new( - draw_call, - &self.device, - &texture, - &self.texture_bind_group_layout, - &self.texture_sampler, - vec![], - vec![], - ); - self.draw_info.push(draw_info); - } - - /// A function that loads a shader from the resources/shaders dir given the full name of the shader file. - pub fn load_shader(&mut self, file_name: &str, shader_stage: Option) { - self.graphic_resource_manager - .load_shader( - shader_stage, - ((Self::get_project_root() - .unwrap() - .as_os_str() - .to_str() - .unwrap() - .to_string() - + "/res/shaders/") - .as_str() - .to_string() - + file_name) - .as_str(), - &self.device, - ) - .unwrap(); - info!("Shader ({}) loaded successfully", file_name); - } - - /// A function that loads a list of shaders from the given filenames out of the resources/shaders dir - pub fn load_shaders(&mut self, shader_stages: Vec>, file_names: Vec<&str>) { - for (i, file_name) in file_names.iter().enumerate() { - self.load_shader(file_name, shader_stages[i].clone()); - info!("Shader ({}) loaded successfully", file_name); - } - } - - /// A function that applies a shader to the entire surface of the `Renderer2D` if the shader is loaded. - pub fn apply_shader(&mut self, shader: &str) { - let module = match self.graphic_resource_manager.get_shader(shader) { - Some(module) => module, - None => { - error!("Shader not found"); - return; - } - }; - } - - /// A function to revert back to the base shader of the `Renderer2D` - pub fn apply_base_shader(&mut self) { - todo!() - } - - /// A function to load a TTF font from the specified path - pub fn load_font(&mut self, path: &str, size: f32) { - self.graphic_resource_manager.load_font(path, size); - let atlas = self - .graphic_resource_manager - .fonts() - .iter() - .find(|f| f.name() == path) - .unwrap() - .glyphs() - .atlas(); - let font_info = DrawInfo::new( - format!("{}", path), - &self.device, - &Texture::from_image(&self.device, &self.queue, atlas, None, false).unwrap(), - &self.texture_bind_group_layout, - &self.texture_sampler, - vec![], - vec![], - ); - - self.draw_info.push(font_info); - } - - /// An interface for getting the location of the texture in the texture atlas. - pub fn get_texture_region(&self, texture_path: String) -> Option<&TextureRegion> { - if !self - .graphic_resource_manager - .texture_atlas() - .textures() - .contains_key(&texture_path) - { - error!("Texture {} not found in atlas", &texture_path); - } - self.graphic_resource_manager - .texture_atlas() - .textures() - .get(&texture_path) - } - - /// A function to get the `TextureRegion` of a specified glyph - pub fn get_glyph_region(&self, glyph: char, font: String) -> &TextureRegion { - let font_atlas = self - .graphic_resource_manager - .fonts() - .iter() - .find(|f| f.name() == font) - .unwrap(); - font_atlas.get_glyph(glyph).unwrap() - } - - /// A function that allows you to set the texture atlas with a list of paths to the textures. - /// The old texture atlas will be replaced with the new one. - pub fn set_texture_atlas_by_paths(&mut self, paths: Vec) { - self.graphic_resource_manager.create_texture_atlas(paths); - self.draw_info[0].set_texture( - &self.device, - &self.texture_bind_group_layout, - &Texture::from_image( - &self.device, - &self.queue, - self.graphic_resource_manager.texture_atlas().atlas(), - None, - false, - ) - .unwrap(), - ); - } - - fn set_texture_atlas(&mut self, texture_atlas: Texture) { - self.draw_info[0].set_texture( - &self.device, - &self.texture_bind_group_layout, - &texture_atlas, - ); - } - - fn get_project_root() -> std::io::Result { - let path = std::env::current_dir()?; - let mut path_ancestors = path.as_path().ancestors(); - - while let Some(p) = path_ancestors.next() { - let has_cargo = std::fs::read_dir(p)? - .into_iter() - .any(|p| p.unwrap().file_name() == std::ffi::OsString::from("Cargo.lock")); - if has_cargo { - return Ok(PathBuf::from(p)); - } - } - Err(std::io::Error::new( - std::io::ErrorKind::NotFound, - "Ran out of places to find Cargo.toml", - )) - } - - /// A function that takes all the textures inside the resources/textures folder and creates a texture atlas from them. - pub fn initialize_atlas(&mut self) { - let texture_path = "res/textures/".to_string(); - let mut paths: Vec = Vec::new(); - - for path in std::fs::read_dir( - Self::get_project_root() - .unwrap() - .as_os_str() - .to_str() - .unwrap() - .to_string() - + "/res/textures", - ) - .unwrap() - { - paths.push(texture_path.clone() + path.unwrap().file_name().to_str().unwrap()); - } - - self.set_texture_atlas_by_paths(paths); - } - - /// A function that writes on the buffers and sets the geometry and index buffer of the `Renderer2D` with the given data. - fn set_buffers(&mut self, new_geometry_buffer: Vec, new_index_buffer: Vec) { - self.draw_info[0].update_vertex_buffer(&self.device, &self.queue, new_geometry_buffer); - self.draw_info[0].update_index_buffer(&self.device, &self.queue, new_index_buffer); - } - - fn add_text_to_buffers( - &self, - text: String, - font: String, - size: f32, - position: p2, - color: wgpu::Color, - bounds: &mut v2, - ) -> (Vec, Vec) { - let vert_color = [ - color.r as f32, - color.g as f32, - color.b as f32, - color.a as f32, - ]; - - let screen_position = p2::new( - position.x() / self.config.width as f32, - position.y() / self.config.height as f32, - ); - - let font_data = self - .graphic_resource_manager - .fonts() - .iter() - .find(|f| f.name() == font) - .unwrap(); - - let scale_factor = size / font_data.size(); - - let line_height = (font_data.line_height() / self.config.height as f32) * scale_factor; - - let lines = text - .split("\n") - .map(|s| { - s.split("") - .map(|escape| match escape { - _ if escape == "\t" => " ", - _ => escape, - }) - .collect::() - }) - .collect::>(); - - let mut max_line_width_px = 0.0; - let mut total_height_px = 0.0; - - for line in &lines { - let mut line_width_px = 0.0; - for c in line.chars() { - if let Some(region) = font_data.get_glyph(c) { - line_width_px += region.advance(); - } - } - if line_width_px > max_line_width_px { - max_line_width_px = line_width_px; - } - total_height_px += font_data.line_height(); - } - - bounds.set_x((max_line_width_px / self.config.width as f32) * scale_factor); - bounds.set_y((total_height_px / self.config.height as f32) * scale_factor); - - let mut x_offset = 0.0; - let mut y_offset = 0.0; - let mut vertex_data = Vec::new(); - let mut index_data = Vec::new(); - - for line in lines { - for c in line.chars() { - let region = self.get_glyph_region(c, font.clone()); - let (dim_x, dim_y) = region.dimensions(); - - let w = (dim_x as f32 / self.config.width as f32) * scale_factor; - let h = (dim_y as f32 / self.config.height as f32) * scale_factor; - - let offset_x_px = (region.offset_x() / self.config.width as f32) * scale_factor; - let offset_y_px = (region.offset_y() / self.config.height as f32) * scale_factor; - - let glyph_left = screen_position.x() + x_offset + offset_x_px; - let glyph_top = screen_position.y() - offset_y_px - y_offset; - let glyph_right = glyph_left + w; - let glyph_bottom = glyph_top - h; - - let vertices: &mut Vec = &mut vec![ - Vertex::new( - [glyph_left, glyph_top, 0.0], - [region.u0(), region.v0()], - vert_color, - ), - Vertex::new( - [glyph_left, glyph_bottom, 0.0], - [region.u0(), region.v1()], - vert_color, - ), - Vertex::new( - [glyph_right, glyph_bottom, 0.0], - [region.u1(), region.v1()], - vert_color, - ), - Vertex::new( - [glyph_right, glyph_top, 0.0], - [region.u1(), region.v0()], - vert_color, - ), - ]; - - let buffer_size = vertex_data.len() as u16; - let indices: &mut Vec = &mut vec![ - buffer_size, - buffer_size + 1, - buffer_size + 3, - buffer_size + 1, - buffer_size + 2, - buffer_size + 3, - ]; - - x_offset += (region.advance() / self.config.width as f32) * scale_factor; - - vertex_data.append(vertices); - index_data.append(indices); - } - - y_offset += line_height; - x_offset = 0.0; - } - - (vertex_data, index_data) - } - - fn find_priority_camera(&self, cameras: Vec) -> usize { - let mut priority = 0; - let mut position = 0; - for (i, camera) in cameras.iter().enumerate() { - if camera.priority() < priority { - priority = camera.priority(); - position = i; - } - } - position - } - - fn setup_camera<'b>( - &mut self, - cameras: Vec, - scene: &'b Scene, - ) -> (&'b Position2D, &'b Camera2D) { - let cam = cameras - .get( - self.find_priority_camera( - cameras - .iter() - .map(|e| *scene.get_component::(*e).unwrap()) - .collect::>(), - ), - ) - .unwrap(); - - let camera_component = scene.get_component::(*cam).unwrap(); - let camera_position = scene.get_component::(*cam).unwrap().position(); - - let camera = RenderCamera::new( - camera_component.zoom(), - camera_component.dimensions(), - v3::new( - camera_position.as_vec().x(), - camera_position.as_vec().y(), - 0.0, - ), - ); - let mut camera_uniform = CameraUniform::new(); - camera_uniform.update_view_proj(&camera); - - let camera_buffer = self - .device - .create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Universal Camera Buffer"), - contents: bytemuck::cast_slice(&[camera_uniform]), - usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST, - }); - - let camera_bind_group_layout = - self.device - .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }], - label: Some("Universal Camera Bind Group Layout"), - }); - - let camera_bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &camera_bind_group_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: camera_buffer.as_entire_binding(), - }], - label: Some("Universal Camera Bind Group"), - }); - - self.camera = camera; - self.camera_buffer = camera_buffer; - self.camera_uniform = camera_uniform; - self.camera_bind_group = camera_bind_group; - - (camera_position, camera_component) - } - - /// A function to automatically render all the entities of the `Scene` struct. - /// The entities must have the `Render2D` and `Transform2D` components to be rendered as well as set visible. - pub fn render_scene_2d(&mut self, scene: &mut Scene) { - let cameras = scene.get_entities_with(vec![Transform2D::type_id(), Camera2D::type_id()]); - - if cameras.is_empty() { - return; - } - - let mut entities = - scene.get_entities_with(vec![Transform2D::type_id(), Render2D::type_id()]); - - entities.sort_by(|&a, &b| { - let ra = scene.get_component::(a).unwrap(); - let rb = scene.get_component::(b).unwrap(); - ra.draw_index().cmp(&rb.draw_index()) - }); - - let texts = - scene.get_entities_with(vec![Transform2D::type_id(), comet_ecs::Text::type_id()]); - - self.setup_camera(cameras, scene); - - let mut vertex_buffer: Vec = Vec::new(); - let mut index_buffer: Vec = Vec::new(); - - for entity in entities { - let renderer_component = scene.get_component::(entity).unwrap(); - let transform_component = scene.get_component::(entity).unwrap(); - - if renderer_component.is_visible() { - let world_position = transform_component.position().clone(); - let rotation_angle = transform_component.rotation().to_radians(); - - let mut t_region: Option<&TextureRegion> = None; - match self.get_texture_region(renderer_component.get_texture().to_string()) { - Some(texture_region) => { - t_region = Some(texture_region); - } - None => continue, - } - let region = t_region.unwrap(); - let (dim_x, dim_y) = region.dimensions(); - - let scale = renderer_component.scale(); - let half_width = dim_x as f32 * 0.5 * scale.x(); - let half_height = dim_y as f32 * 0.5 * scale.y(); - - let buffer_size = vertex_buffer.len() as u16; - - let world_corners = [ - (-half_width, half_height), - (-half_width, -half_height), - (half_width, -half_height), - (half_width, half_height), - ]; - - let cos_angle = rotation_angle.cos(); - let sin_angle = rotation_angle.sin(); - - let mut rotated_world_corners = [(0.0f32, 0.0f32); 4]; - for i in 0..4 { - let (x, y) = world_corners[i]; - rotated_world_corners[i] = ( - x * cos_angle - y * sin_angle + world_position.x(), - x * sin_angle + y * cos_angle + world_position.y(), - ); - } - - let mut screen_corners = [(0.0f32, 0.0f32); 4]; - for i in 0..4 { - screen_corners[i] = ( - rotated_world_corners[i].0 / self.config().width as f32, - rotated_world_corners[i].1 / self.config().height as f32, - ); - } - - vertex_buffer.append(&mut vec![ - Vertex::new( - [screen_corners[0].0, screen_corners[0].1, 0.0], - [region.u0(), region.v0()], - [1.0, 1.0, 1.0, 1.0], - ), - Vertex::new( - [screen_corners[1].0, screen_corners[1].1, 0.0], - [region.u0(), region.v1()], - [1.0, 1.0, 1.0, 1.0], - ), - Vertex::new( - [screen_corners[2].0, screen_corners[2].1, 0.0], - [region.u1(), region.v1()], - [1.0, 1.0, 1.0, 1.0], - ), - Vertex::new( - [screen_corners[3].0, screen_corners[3].1, 0.0], - [region.u1(), region.v0()], - [1.0, 1.0, 1.0, 1.0], - ), - ]); - - index_buffer.append(&mut vec![ - 0 + buffer_size, - 1 + buffer_size, - 3 + buffer_size, - 1 + buffer_size, - 2 + buffer_size, - 3 + buffer_size, - ]); - } - } - - for text in texts { - if let Some(component) = scene.get_component_mut::(text) { - if component.is_visible() { - let font = component.font().to_string(); - let size = component.font_size(); - let color = component.color().to_wgpu(); - let content = component.content().to_string(); - - let transform = scene.get_component::(text).unwrap(); - - let mut bounds = v2::ZERO; - let (vertices, indices) = self.add_text_to_buffers( - content, - font.clone(), - size, - p2::from_vec(transform.position().as_vec()), - color, - &mut bounds, - ); - - let component = scene.get_component_mut::(text).unwrap(); - component.set_bounds(bounds); - - let draw = self - .draw_info - .iter_mut() - .find(|d| d.name() == &format!("{}", font)) - .unwrap(); - draw.update_vertex_buffer(&self.device, &self.queue, vertices); - draw.update_index_buffer(&self.device, &self.queue, indices); - } - } - } - - self.set_buffers(vertex_buffer, index_buffer); - } - - fn sort_entities_by_position(&self, entity_data: Vec<(usize, Position2D)>) -> Vec { - let mut sorted_entities: Vec = vec![]; - - let mut entity_data = entity_data.clone(); - entity_data.sort_by(|a, b| a.1.x().partial_cmp(&b.1.x()).unwrap()); - - for (i, _) in entity_data { - sorted_entities.push(i); - } - - sorted_entities - } - - pub fn update(&mut self) -> f32 { - let now = Instant::now(); - self.delta_time = now.duration_since(self.last_frame_time).as_secs_f32(); // Time delta in seconds - self.last_frame_time = now; - self.delta_time - } - - pub fn render(&mut self) -> Result<(), wgpu::SurfaceError> { - let output = self.surface.get_current_texture()?; - let output_view = output - .texture - .create_view(&wgpu::TextureViewDescriptor::default()); - - let mut encoder = self - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("Render Encoder"), - }); - - { - let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Universal Render Pass"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &output_view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(self.clear_color), - store: wgpu::StoreOp::Store, - }, - })], - depth_stencil_attachment: None, - occlusion_query_set: None, - timestamp_writes: None, - }); - - render_pass.set_pipeline(&self.universal_render_pipeline); - - for i in 0..self.draw_info.len() { - render_pass.set_bind_group(0, self.draw_info[i].texture(), &[]); - render_pass.set_bind_group(1, &self.camera_bind_group, &[]); - render_pass.set_vertex_buffer(0, self.draw_info[i].vertex_buffer().slice(..)); - render_pass.set_index_buffer( - self.draw_info[i].index_buffer().slice(..), - wgpu::IndexFormat::Uint16, - ); - render_pass.draw_indexed(0..self.draw_info[i].num_indices(), 0, 0..1); - } - } - - self.queue.submit(iter::once(encoder.finish())); - output.present(); - Ok(()) - } } impl<'a> Renderer for Renderer2D<'a> { - fn new(window: Arc, clear_color: Option) -> Renderer2D<'a> { - Self::new(window, clear_color) + fn new(window: Arc, clear_color: Option) -> Self { + Self { + render_context: RenderContext::new(window, clear_color), + resource_manager: GraphicResourceManager::new(), + camera_manager: CameraManager::new(), + delta_time: 0.0, + } } fn size(&self) -> PhysicalSize { - self.size() + self.render_context.size() } - fn resize(&mut self, new_size: PhysicalSize) { - self.resize(new_size) + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { + if new_size.width > 0 && new_size.height > 0 { + self.render_context.set_size(new_size); + self.render_context.config_mut().width = new_size.width; + self.render_context.config_mut().height = new_size.height; + self.render_context.configure_surface(); + } } fn scale_factor(&self) -> f64 { - self.scale_factor() + self.render_context.scale_factor() } fn set_scale_factor(&mut self, scale_factor: f64) { - self.set_scale_factor(scale_factor); + self.render_context.set_scale_factor(scale_factor); } fn update(&mut self) -> f32 { - self.update() + todo!() } fn render(&mut self) -> Result<(), wgpu::SurfaceError> { - self.render() + todo!() } } + diff --git a/crates/comet_renderer/src/renderer2d_/mod.rs b/crates/comet_renderer/src/renderer2d_/mod.rs index 8531d4c..827b129 100644 --- a/crates/comet_renderer/src/renderer2d_/mod.rs +++ b/crates/comet_renderer/src/renderer2d_/mod.rs @@ -140,6 +140,14 @@ impl<'a> Renderer for Renderer2D_<'a> { self.render_context.resize(new_size) } + fn scale_factor(&self) -> f64 { + todo!() + } + + fn set_scale_factor(&mut self, scale_factor: f64) { + todo!() + } + fn update(&mut self) -> f32 { self.render_context.update() }