From 11dd39349d951d763a367555e66006ab03668d5d Mon Sep 17 00:00:00 2001
From: Caznix <caznix01@gmail.com>
Date: Sun, 1 Dec 2024 22:58:52 -0500
Subject: [PATCH] draw with wgpu

---
 engine/src/core/mod.rs          |   2 +-
 engine/src/core/renderer/ctx.rs | 100 ++++++++++++++++++++++++++++++++
 engine/src/core/renderer/mod.rs |  35 +++++++----
 engine/src/main.rs              |   8 +--
 4 files changed, 129 insertions(+), 16 deletions(-)
 create mode 100644 engine/src/core/renderer/ctx.rs

diff --git a/engine/src/core/mod.rs b/engine/src/core/mod.rs
index deea4b7..cebc91e 100644
--- a/engine/src/core/mod.rs
+++ b/engine/src/core/mod.rs
@@ -8,7 +8,7 @@ use winit::event_loop::{ControlFlow, EventLoop};
 
 
 
-pub fn init_render() -> Result<()> {
+pub fn init_renderer() -> Result<()> {
     let event_loop = EventLoop::new().unwrap();
     event_loop.set_control_flow(ControlFlow::Poll);
     let mut app = App::default();
diff --git a/engine/src/core/renderer/ctx.rs b/engine/src/core/renderer/ctx.rs
new file mode 100644
index 0000000..690ed0b
--- /dev/null
+++ b/engine/src/core/renderer/ctx.rs
@@ -0,0 +1,100 @@
+use std::sync::Arc;
+
+use anyhow::Result;
+use tokio::task::spawn_blocking;
+use winit::window::Window;
+
+pub struct WgpuCtx<'window> {
+    device: wgpu::Device,
+    queue: wgpu::Queue,
+    surface: wgpu::Surface<'window>,
+    surface_config: wgpu::SurfaceConfiguration,
+    adapter: wgpu::Adapter,
+}
+
+impl<'window> WgpuCtx<'window> {
+    pub async fn new(window: Arc<Window>) -> Result<WgpuCtx<'window>> {
+        let instnace = wgpu::Instance::default();
+        let surface = instnace.create_surface(Arc::clone(&window))?;
+        let adapter = instnace
+            .request_adapter(&wgpu::RequestAdapterOptions {
+                power_preference: wgpu::PowerPreference::default(),
+                force_fallback_adapter: false,
+                compatible_surface: Some(&surface),
+            })
+            .await
+            .expect("Failed to obtain render adapter");
+        let (device, queue) = adapter
+            .request_device(
+                &wgpu::DeviceDescriptor {
+                    label: None,
+                    required_features: wgpu::Features::empty(),
+                    required_limits: wgpu::Limits::downlevel_webgl2_defaults()
+                        .using_resolution(adapter.limits()),
+                    memory_hints: wgpu::MemoryHints::Performance,
+                },
+                None,
+            )
+            .await
+            .expect("Failed to create rendering device");
+
+        let size = window.inner_size();
+        let width = size.width.max(1);
+        let height = size.height.max(1);
+
+        let surface_config = surface.get_default_config(&adapter, width, height).unwrap();
+        surface.configure(&device, &surface_config);
+
+        Ok(WgpuCtx {
+            device: device,
+            queue: queue,
+            surface: surface,
+            surface_config: surface_config,
+            adapter: adapter,
+        })
+    }
+    pub fn new_blocking(window: Arc<Window>) -> Result<WgpuCtx<'window>> {
+        tokio::task::block_in_place(|| {
+            tokio::runtime::Runtime::new()
+                .unwrap()
+                .block_on(async { WgpuCtx::new(window).await })
+        })
+    }
+    pub fn resize(&mut self, new_size: (u32, u32)) {
+        let (width, height) = new_size;
+        self.surface_config.width = width.max(1);
+        self.surface_config.height = height.max(1);
+        self.surface.configure(&self.device, &self.surface_config);
+    }
+    pub fn draw(&mut self) {
+        let surface_texture = self
+        .surface
+        .get_current_texture()
+        .expect("Failed to get surface texture");
+    let view = surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default());
+    let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
+    {
+        let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
+            label: None,
+            color_attachments: &[Some(wgpu::RenderPassColorAttachment {
+                view: &view,
+                resolve_target: None,
+                ops: wgpu::Operations {
+                    load: wgpu::LoadOp::Clear(wgpu::Color {
+                        r: 0.1,
+                        g: 0.2,
+                        b: 0.3,
+                        a: 1.0,
+                    }),
+                    store: wgpu::StoreOp::Store,
+                },
+            })],
+            depth_stencil_attachment: None,
+            timestamp_writes: None,
+            occlusion_query_set: None,
+        });
+    }
+    self.queue.submit(Some(encoder.finish()));
+    surface_texture.present();
+    }
+}
diff --git a/engine/src/core/renderer/mod.rs b/engine/src/core/renderer/mod.rs
index 791f600..c6fcdab 100644
--- a/engine/src/core/renderer/mod.rs
+++ b/engine/src/core/renderer/mod.rs
@@ -1,22 +1,28 @@
-use log2::{debug, error};
+use std::sync::Arc;
+
+use ctx::WgpuCtx;
+use log2::{debug, error, trace};
 use winit::application::ApplicationHandler;
 use winit::event::WindowEvent;
 use winit::event_loop::ActiveEventLoop;
-use winit::window::{Window, WindowId};
-
+use winit::window::{self, Window, WindowId};
+pub mod ctx;
 #[derive(Default)]
-pub struct App {
-    window: Option<Window>,
+pub struct App<'window> {
+    window: Option<Arc<Window>>,
+    ctx: Option<WgpuCtx<'window>>,
 }
 
-impl ApplicationHandler for App {
+impl ApplicationHandler for App<'_> {
     fn resumed(&mut self, event_loop: &ActiveEventLoop) {
         if self.window.is_none() {
             let win_attr = Window::default_attributes().with_title("Zenyx");
-            let window = event_loop
+            let window = Arc::new(event_loop
                 .create_window(win_attr)
-                .expect("create window err.");
-            self.window = Some(window);
+                .expect("create window err."));
+            self.window = Some(window.clone());
+            let wgpu_ctx = WgpuCtx::new_blocking(window.clone()).unwrap();
+            self.ctx = Some(wgpu_ctx)
         }
     }
 
@@ -32,12 +38,21 @@ impl ApplicationHandler for App {
                 debug!("Window closed, exiting");
                 std::process::exit(0)
             }
+            WindowEvent::RedrawRequested => {
+                if let Some(ctx) = &mut self.ctx {
+                    ctx.draw();
+                }
+            }
             WindowEvent::Resized(size) => {
+                if let (Some(wgpu_ctx),Some(window)) = (&mut self.ctx, &self.window) {
+                    wgpu_ctx.resize(size.into());
+                    window.request_redraw();
                 let size_str: String = size.height.to_string() + "x" + &size.width.to_string();
                 //self.window.as_ref().unwrap().set_title(&format!("you reszed the window to {size_str}"));
                 debug!("Window resized to {:?}", size_str);
             }
-            _ => error!("Unhandled window event"),
+        }
+            _ => trace!("Unhandled window event"),
         }
     }
 }
\ No newline at end of file
diff --git a/engine/src/main.rs b/engine/src/main.rs
index c5e5729..5baa920 100644
--- a/engine/src/main.rs
+++ b/engine/src/main.rs
@@ -1,4 +1,3 @@
-
 use anyhow::Result;
 use log2::info;
 
@@ -6,17 +5,16 @@ pub mod core;
 
 #[tokio::main]
 async fn main() -> Result<()> {
-    let _log2 = log2::open("z.log").tee(true).level("trace").start();
+    let _log2 = log2::open("z.log").tee(true).level("debug").start();
     info!("Initalizing Engine");
     let shell_thread = tokio::task::spawn(async {
         info!("Shell thread started");
         core::repl::handle_repl().await;
-    }
-);
+    });
 
     core::splash::print_splash();
     info!("Engine Initalized");
-    core::init_render()?;
+    core::init_renderer()?;
     shell_thread.await?;
     Ok(())
 }