summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock126
-rw-r--r--Cargo.toml2
-rw-r--r--src/camera.rs9
-rw-r--r--src/main.rs629
-rw-r--r--src/shader.wgsl25
-rw-r--r--src/sim/materials/mod.rs2
6 files changed, 563 insertions, 230 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9a99a2c..6fd944d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -903,25 +903,89 @@ dependencies = [
]
[[package]]
+name = "futures"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
name = "futures-core"
-version = "0.3.33"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7"
+checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d"
[[package]]
name = "futures-task"
-version = "0.3.33"
+version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109"
+checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
[[package]]
name = "futures-util"
-version = "0.3.33"
+version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa"
+checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
dependencies = [
+ "futures-channel",
"futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
"futures-task",
+ "memchr",
"pin-project-lite",
"slab",
]
@@ -2032,20 +2096,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
-name = "pixels"
-version = "0.17.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27af78f16789b973b8b340fe3f68cc2ec9f5e6f4aea64e4d794d5833ac9ca52e"
-dependencies = [
- "bytemuck",
- "pollster",
- "raw-window-handle",
- "thiserror 2.0.19",
- "ultraviolet",
- "wgpu",
-]
-
-[[package]]
name = "pkg-config"
version = "0.3.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2085,12 +2135,6 @@ dependencies = [
]
[[package]]
-name = "pollster"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3"
-
-[[package]]
name = "polycool"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2196,7 +2240,7 @@ dependencies = [
"egui-wgpu",
"egui-winit",
"env_logger",
- "pixels",
+ "futures",
"puffin",
"puffin_http",
"rand",
@@ -2428,15 +2472,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
[[package]]
-name = "safe_arch"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323"
-dependencies = [
- "bytemuck",
-]
-
-[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2864,15 +2899,6 @@ dependencies = [
]
[[package]]
-name = "ultraviolet"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea519dad475ee0446b8172793c3c327e4fc81dafdaf05aaac510e630000b6296"
-dependencies = [
- "wide",
-]
-
-[[package]]
name = "unicode-general-category"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3390,16 +3416,6 @@ dependencies = [
]
[[package]]
-name = "wide"
-version = "0.7.33"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03"
-dependencies = [
- "bytemuck",
- "safe_arch",
-]
-
-[[package]]
name = "winapi-util"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 3172fcd..1d12c62 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.1.0"
edition = "2024"
[dependencies]
-pixels = "0.17.2"
wgpu = "29.0.4"
egui = {version = "0.35.0", features = ["default_fonts"]}
egui-winit = "0.35.0"
@@ -15,6 +14,7 @@ puffin = "0.20.0"
puffin_http = "0.17.0"
rand = "0.10.2"
rayon = "1.12.0"
+futures = "0.3.34"
[features]
profiler = []
diff --git a/src/camera.rs b/src/camera.rs
index df6a023..edb7f29 100644
--- a/src/camera.rs
+++ b/src/camera.rs
@@ -56,6 +56,15 @@ impl Camera {
pub fn write_frame_view(&self, frame: &mut [u8], world: &World) {
puffin::profile_function!();
+ for i in 0..frame.len() / 4 {
+ let idx = i * 4;
+ frame[idx] = 0xFF;
+ frame[idx + 1] = 0xAA;
+ frame[idx + 2] = 0xAA;
+ frame[idx + 3] = 0xFF;
+ }
+ return;
+
const BG: [u8; 4] = [0x00, 0x00, 0x00, 0xFF];
for px in frame.chunks_exact_mut(4) {
px.copy_from_slice(&BG);
diff --git a/src/main.rs b/src/main.rs
index 313a7a8..b5c19e0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,9 +6,12 @@ mod ui;
use egui::Id;
use egui_wgpu::{RendererOptions, ScreenDescriptor};
use egui_winit::egui::{self, Context};
-use pixels::{Pixels, ScalingMode, SurfaceTexture};
-use rand::random_range;
-use std::time::{Duration, Instant};
+use futures::executor;
+use std::{
+ sync::Arc,
+ time::{Duration, Instant},
+};
+use wgpu::{Origin3d, TextureUsages};
use winit::{
application::ApplicationHandler,
event::{
@@ -22,8 +25,8 @@ use winit::{
use crate::{
camera::Camera,
- config::{PIXEL_BUFFER_HEIGHT, PIXEL_BUFFER_WIDTH, WINDOW_TITLE},
- sim::{cell::Cell, materials::MaterialId, sim::sim_tick, world::World},
+ config::WINDOW_TITLE,
+ sim::{materials::MaterialId, sim::sim_tick, world::World},
ui::draw_egui,
};
@@ -53,13 +56,394 @@ struct Diagnostics {
fps: f32,
}
+struct RendererState {
+ window: Arc<Window>,
+ surface: wgpu::Surface<'static>,
+ device: wgpu::Device,
+ queue: wgpu::Queue,
+ config: wgpu::SurfaceConfiguration,
+ is_surface_configured: bool,
+
+ // egui
+ egui_context: egui::Context,
+ egui_state: egui_winit::State,
+ egui_renderer: egui_wgpu::Renderer,
+
+ pixels_pipeline: wgpu::RenderPipeline,
+ pixels_bind_group: wgpu::BindGroup,
+ texture: wgpu::Texture,
+ // TODO remove me
+ frame_view: Vec<u8>,
+}
+
+impl RendererState {
+ // https://sotrh.github.io/learn-wgpu/beginner/tutorial1-window
+ pub async fn new(window: Arc<Window>) -> Self {
+ let size = window.inner_size();
+ println!("Got window! ({}x{})", size.width, size.height);
+
+ let instance = wgpu::Instance::default();
+ let surface = instance.create_surface(window.clone()).unwrap();
+
+ let adapter = instance
+ .request_adapter(&wgpu::RequestAdapterOptions {
+ compatible_surface: Some(&surface),
+ ..wgpu::RequestAdapterOptions::default()
+ })
+ .await
+ .unwrap();
+
+ println!(
+ "Initialized adapter, using GPU '{}'",
+ adapter.get_info().name
+ );
+
+ let (device, queue) = adapter
+ .request_device(&wgpu::DeviceDescriptor::default())
+ .await
+ .unwrap();
+
+ let surface_caps = surface.get_capabilities(&adapter);
+ let surface_format = surface_caps
+ .formats
+ .iter()
+ .find(|f| f.is_srgb())
+ .copied()
+ .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: wgpu::PresentMode::AutoVsync,
+ alpha_mode: surface_caps.alpha_modes[0],
+ view_formats: vec![],
+ desired_maximum_frame_latency: 2,
+ };
+
+ let egui_context = Context::default();
+ let egui_state = egui_winit::State::new(
+ egui_context.clone(),
+ egui_context.viewport_id(),
+ &window,
+ None,
+ None,
+ None,
+ );
+ let egui_renderer = egui_wgpu::Renderer::new(&device, surface_format, {
+ RendererOptions {
+ msaa_samples: 1,
+ ..RendererOptions::default()
+ }
+ });
+
+ let texture = device.create_texture(&wgpu::TextureDescriptor {
+ label: None,
+ mip_level_count: 1,
+ sample_count: 1,
+ usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
+ format: surface_format,
+ size: wgpu::Extent3d {
+ width: size.width,
+ height: size.height,
+ depth_or_array_layers: 1,
+ },
+ dimension: wgpu::TextureDimension::D2,
+ view_formats: &[],
+ });
+
+ let pixels_bind_group_layout =
+ device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
+ label: None,
+ entries: &[wgpu::BindGroupLayoutEntry {
+ ty: wgpu::BindingType::Texture {
+ sample_type: wgpu::TextureSampleType::Float { filterable: true },
+ view_dimension: wgpu::TextureViewDimension::D2,
+ multisampled: false,
+ },
+ binding: 0,
+ count: None,
+ visibility: wgpu::ShaderStages::FRAGMENT,
+ }],
+ });
+
+ let pixels_pipeline_layout =
+ device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
+ label: None,
+ immediate_size: 0,
+ bind_group_layouts: &[Some(&pixels_bind_group_layout)],
+ });
+
+ let pixels_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
+ label: None,
+ layout: &pixels_bind_group_layout,
+ entries: &[wgpu::BindGroupEntry {
+ binding: 0,
+ resource: wgpu::BindingResource::TextureView(&texture.create_view(
+ &wgpu::TextureViewDescriptor {
+ dimension: Some(wgpu::TextureViewDimension::D2),
+ usage: Some(
+ wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
+ ),
+ ..wgpu::TextureViewDescriptor::default()
+ },
+ )),
+ }],
+ });
+
+ let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
+ label: Some("Shader"),
+ source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
+ });
+
+ let pixels_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
+ label: None,
+ layout: Some(&pixels_pipeline_layout),
+ vertex: wgpu::VertexState {
+ module: &shader,
+ entry_point: Some("vs_main"),
+ buffers: &[],
+ compilation_options: wgpu::PipelineCompilationOptions::default(),
+ },
+ fragment: Some(wgpu::FragmentState {
+ module: &shader,
+ entry_point: Some("fs_main"),
+ targets: &[Some(wgpu::ColorTargetState {
+ format: config.format,
+ blend: Some(wgpu::BlendState::REPLACE),
+ write_mask: wgpu::ColorWrites::ALL,
+ })],
+ compilation_options: wgpu::PipelineCompilationOptions::default(),
+ }),
+ primitive: wgpu::PrimitiveState {
+ topology: wgpu::PrimitiveTopology::TriangleList,
+ strip_index_format: None,
+ front_face: wgpu::FrontFace::Ccw,
+ cull_mode: None,
+ polygon_mode: wgpu::PolygonMode::Fill,
+ unclipped_depth: false,
+ conservative: false,
+ },
+ depth_stencil: None,
+ multisample: wgpu::MultisampleState::default(),
+ multiview_mask: None,
+ cache: None,
+ });
+
+ RendererState {
+ window,
+ surface,
+ device,
+ queue,
+ config,
+ is_surface_configured: false,
+
+ egui_context,
+ egui_state,
+ egui_renderer,
+
+ texture,
+ frame_view: vec![0; size.width as usize * size.height as usize * 4],
+ pixels_pipeline,
+ pixels_bind_group,
+ }
+ }
+
+ pub fn resize(&mut self, width: u32, height: u32) {
+ if width > 0 && height > 0 {
+ self.config.width = width;
+ self.config.height = height;
+ self.surface.configure(&self.device, &self.config);
+ self.is_surface_configured = true;
+ }
+ }
+
+ pub fn render(
+ &mut self,
+ config: &mut Config,
+ camera: &mut Camera,
+ diagnostics: &Diagnostics,
+ input: &Input,
+ ) {
+ puffin::profile_function!();
+
+ self.window.request_redraw();
+
+ if !self.is_surface_configured {
+ return;
+ }
+
+ let output = match self.surface.get_current_texture() {
+ wgpu::CurrentSurfaceTexture::Success(surface_texture) => surface_texture,
+ wgpu::CurrentSurfaceTexture::Suboptimal(surface_texture) => surface_texture,
+ wgpu::CurrentSurfaceTexture::Timeout
+ | wgpu::CurrentSurfaceTexture::Occluded
+ | wgpu::CurrentSurfaceTexture::Validation => {
+ // Skip this frame
+ return;
+ }
+ wgpu::CurrentSurfaceTexture::Outdated => {
+ self.surface.configure(&self.device, &self.config);
+ return;
+ }
+ wgpu::CurrentSurfaceTexture::Lost => {
+ panic!("Lost device?");
+ }
+ };
+
+ let view = output
+ .texture
+ .create_view(&wgpu::TextureViewDescriptor::default());
+
+ let mut encoder = self
+ .device
+ .create_command_encoder(&wgpu::CommandEncoderDescriptor {
+ label: Some("Render Encoder"),
+ });
+
+ let raw_input = self.egui_state.take_egui_input(&self.window);
+ let full_output = self.egui_context.run_ui(raw_input, |ui| {
+ let right_panel = egui::Panel::right(Id::new("right_panel"));
+ right_panel
+ .resizable(false)
+ // TODO collapse button
+ .show_collapsible(ui, &mut true, |panel_ui| {
+ draw_egui(panel_ui, config, camera, diagnostics, input)
+ });
+ });
+
+ self.egui_state
+ .handle_platform_output(&self.window, full_output.platform_output);
+
+ let clipped_primitives = self
+ .egui_context
+ .tessellate(full_output.shapes, full_output.pixels_per_point);
+
+ let pixels_per_point = full_output.pixels_per_point;
+
+ let size = self.window.inner_size();
+ let screen_descriptor = ScreenDescriptor {
+ size_in_pixels: [size.width, size.height],
+ pixels_per_point,
+ };
+
+ for (id, delta) in &full_output.textures_delta.set {
+ self.egui_renderer
+ .update_texture(&self.device, &self.queue, *id, delta);
+ }
+
+ self.egui_renderer.update_buffers(
+ &self.device,
+ &self.queue,
+ &mut encoder,
+ &clipped_primitives,
+ &screen_descriptor,
+ );
+
+ // let render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
+ // label: Some("Render Pass"),
+ // color_attachments: &[Some(wgpu::RenderPassColorAttachment {
+ // view: &view,
+ // resolve_target: None,
+ // depth_slice: 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,
+ // occlusion_query_set: None,
+ // timestamp_writes: None,
+ // multiview_mask: None,
+ // });
+
+ // drop(render_pass);
+
+ self.queue.write_texture(
+ wgpu::TexelCopyTextureInfo {
+ texture: &self.texture,
+ aspect: wgpu::TextureAspect::All,
+ mip_level: 0,
+ origin: Origin3d::ZERO,
+ },
+ &self.frame_view,
+ wgpu::TexelCopyBufferLayout {
+ bytes_per_row: Some(size.width * 4),
+ offset: 0,
+ rows_per_image: Some(size.height),
+ },
+ wgpu::Extent3d {
+ width: size.width,
+ height: size.height,
+ depth_or_array_layers: 1,
+ },
+ );
+
+ let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
+ label: Some("Render Pass"),
+ color_attachments: &[Some(wgpu::RenderPassColorAttachment {
+ view: &view,
+ resolve_target: None,
+ depth_slice: 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,
+ occlusion_query_set: None,
+ timestamp_writes: None,
+ multiview_mask: None,
+ });
+
+ render_pass.set_pipeline(&self.pixels_pipeline);
+ render_pass.set_bind_group(0, &self.pixels_bind_group, &[]);
+ render_pass.draw(0..3, 0..1);
+
+ drop(render_pass);
+
+ let mut egui_pass = encoder
+ .begin_render_pass(&wgpu::RenderPassDescriptor {
+ label: Some("egui pass"),
+ color_attachments: &[Some(wgpu::RenderPassColorAttachment {
+ view: &view,
+ resolve_target: None,
+ depth_slice: None,
+ ops: wgpu::Operations {
+ load: wgpu::LoadOp::Load,
+ store: wgpu::StoreOp::Store,
+ },
+ })],
+ depth_stencil_attachment: None,
+ timestamp_writes: None,
+ occlusion_query_set: None,
+ multiview_mask: None,
+ })
+ .forget_lifetime();
+
+ self.egui_renderer
+ .render(&mut egui_pass, &clipped_primitives, &screen_descriptor);
+ drop(egui_pass);
+
+ self.queue.submit(std::iter::once(encoder.finish()));
+ output.present();
+ }
+}
+
struct App {
- // core
- egui_renderer: Option<egui_wgpu::Renderer>,
- egui_state: Option<egui_winit::State>,
- egui_context: Option<egui::Context>,
- window: Option<&'static Window>,
- pixels: Option<Pixels<'static>>,
+ window: Option<Arc<Window>>,
+ renderer_state: Option<RendererState>,
input: Input,
@@ -85,11 +469,8 @@ struct App {
impl Default for App {
fn default() -> Self {
Self {
- egui_renderer: None,
- egui_state: None,
- egui_context: None,
window: None,
- pixels: None,
+ renderer_state: None,
input: Input {
last_mouse_pos_on_screen: None,
@@ -130,40 +511,20 @@ impl Default for App {
impl ApplicationHandler for App {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
- let window = event_loop
- .create_window(Window::default_attributes().with_title(WINDOW_TITLE))
- .unwrap();
-
- let size = window.inner_size();
- let window_ref: &'static Window = Box::leak(Box::new(window));
- let surface = SurfaceTexture::new(size.width, size.height, window_ref);
+ let window = Arc::new(
+ event_loop
+ .create_window(Window::default_attributes().with_title(WINDOW_TITLE))
+ .unwrap(),
+ );
- let mut pixels = Pixels::new(PIXEL_BUFFER_WIDTH, PIXEL_BUFFER_HEIGHT, surface).unwrap();
+ self.window = Some(window.clone());
+ self.renderer_state = Some(executor::block_on(RendererState::new(window.clone())));
- pixels.set_scaling_mode(ScalingMode::Fill);
+ // let surface = SurfaceTexture::new(size.width, size.height, window_ref);
- let egui_context = Context::default();
- let egui_state = egui_winit::State::new(
- egui_context.clone(),
- egui_context.viewport_id(),
- window_ref,
- None,
- None,
- None,
- );
- let egui_renderer =
- egui_wgpu::Renderer::new(pixels.device(), pixels.render_texture_format(), {
- RendererOptions {
- msaa_samples: 1,
- ..RendererOptions::default()
- }
- });
+ // let mut pixels = Pixels::new(PIXEL_BUFFER_WIDTH, PIXEL_BUFFER_HEIGHT, surface).unwrap();
- self.egui_context = Some(egui_context);
- self.egui_state = Some(egui_state);
- self.egui_renderer = Some(egui_renderer);
- self.window = Some(window_ref);
- self.pixels = Some(pixels);
+ // pixels.set_scaling_mode(ScalingMode::Fill);
}
fn window_event(
@@ -172,15 +533,12 @@ impl ApplicationHandler for App {
_: winit::window::WindowId,
event: WindowEvent,
) {
- if let Some(pixels) = &mut self.pixels
- && let Some(window) = self.window
- && let Some(egui_context) = &self.egui_context
- && let Some(egui_state) = &mut self.egui_state
- && let Some(egui_renderer) = &mut self.egui_renderer
+ if let Some(window) = &self.window
+ && let Some(renderer_state) = &mut self.renderer_state
&& let Some(world) = &mut self.world
&& let Some(camera) = &mut self.camera
{
- let egui_response = egui_state.on_window_event(window, &event);
+ let egui_response = renderer_state.egui_state.on_window_event(window, &event);
// if egui consumed the event, it means we shouldn't treat any e.g., mouse clicks
if egui_response.consumed {
return;
@@ -218,11 +576,11 @@ impl ApplicationHandler for App {
}
WindowEvent::CursorMoved { position, .. } => {
self.input.last_mouse_pos_on_screen = Some((position.x, position.y));
- self.input.last_mouse_pos_on_board = pixels
- .window_pos_to_pixel((position.x as f32, position.y as f32))
- .map(|v| camera.screen_position_to_world(v.0 as f64, v.1 as f64))
- .map(|v| (v.0 as i32, v.1 as i32))
- .ok();
+ // self.input.last_mouse_pos_on_board = pixels
+ // .window_pos_to_pixel((position.x as f32, position.y as f32))
+ // .map(|v| camera.screen_position_to_world(v.0 as f64, v.1 as f64))
+ // .map(|v| (v.0 as i32, v.1 as i32))
+ // .ok();
}
WindowEvent::MouseInput { state, button, .. } => {
if button == MouseButton::Left {
@@ -231,7 +589,7 @@ impl ApplicationHandler for App {
}
WindowEvent::Resized(size) => {
// Important: resize the surface when the window's size change
- pixels.resize_surface(size.width, size.height).unwrap();
+ renderer_state.resize(size.width, size.height);
}
WindowEvent::CloseRequested => {
event_loop.exit();
@@ -252,40 +610,36 @@ impl ApplicationHandler for App {
// apply inputs
camera.handle_camera_input(&self.input, delta_time);
- // pixels/camera logic
- let frame = pixels.frame_mut();
- frame.fill(0);
+ // // --TEST DRAWING--
+ // if self.input.is_lmb_pressed
+ // && let Some(lm) = self.input.last_mouse_pos_on_board
+ // {
+ // // start with the bounding box of the drawing brush circle + some margin
+ // // clamp the bounding box to the board sie
+ // // TODO better way to do this without unwrap?
+ // let bb_xl = lm.0 - self.config.brush_radius as i32;
+ // let bb_xu = lm.0 + self.config.brush_radius as i32;
+ // let bb_yl = lm.1 - self.config.brush_radius as i32;
+ // let bb_yu = lm.1 + self.config.brush_radius as i32;
- // --TEST DRAWING--
- if self.input.is_lmb_pressed
- && let Some(lm) = self.input.last_mouse_pos_on_board
- {
- // start with the bounding box of the drawing brush circle + some margin
- // clamp the bounding box to the board sie
- // TODO better way to do this without unwrap?
- let bb_xl = lm.0 - self.config.brush_radius as i32;
- let bb_xu = lm.0 + self.config.brush_radius as i32;
- let bb_yl = lm.1 - self.config.brush_radius as i32;
- let bb_yu = lm.1 + self.config.brush_radius as i32;
-
- // for each point, check if the distance is less than the brush size and write the pixel
- for x in bb_xl..bb_xu {
- for y in bb_yl..bb_yu {
- let r = random_range(0.0..1.0);
- if ((x - lm.0).pow(2) + (y - lm.1).pow(2))
- < (self.config.brush_radius as i32).pow(2)
- && r > 0.9
- {
- let mut cell = Cell::from_material(self.config.brush_material);
- cell.flags = (self.sim_seqno as u8) & 0b1;
- world.set_cell_from_game_position(
- x, y, cell, // wake the chunk
- false,
- );
- }
- }
- }
- }
+ // // for each point, check if the distance is less than the brush size and write the pixel
+ // for x in bb_xl..bb_xu {
+ // for y in bb_yl..bb_yu {
+ // let r = random_range(0.0..1.0);
+ // if ((x - lm.0).pow(2) + (y - lm.1).pow(2))
+ // < (self.config.brush_radius as i32).pow(2)
+ // && r > 0.9
+ // {
+ // let mut cell = Cell::from_material(self.config.brush_material);
+ // cell.flags = (self.sim_seqno as u8) & 0b1;
+ // world.set_cell_from_game_position(
+ // x, y, cell, // wake the chunk
+ // false,
+ // );
+ // }
+ // }
+ // }
+ // }
// TODO check if we need to run another sim tick given the sim speed + delta_time
// SIM logic
@@ -295,87 +649,14 @@ impl ApplicationHandler for App {
self.ignore_pause_next_tick = false;
}
- // let get_overlay =
- // create_compute_combined_overlay_offset(&world, &self.config, &self.input);
- camera.write_frame_view(frame, &world);
-
- // egui logic
- let raw_input = egui_state.take_egui_input(window);
- let full_output = egui_context.run_ui(raw_input, |ui| {
- let right_panel = egui::Panel::right(Id::new("right_panel"));
- right_panel
- .resizable(false)
- // TODO collapse button
- .show_collapsible(ui, &mut true, |panel_ui| {
- draw_egui(
- panel_ui,
- &mut self.config,
- camera,
- &self.diagnostics,
- &self.input,
- )
- });
- });
-
- egui_state.handle_platform_output(window, full_output.platform_output);
-
- let clipped_primitives =
- egui_context.tessellate(full_output.shapes, full_output.pixels_per_point);
-
- let pixels_per_point = full_output.pixels_per_point;
-
- let size = window.inner_size();
- let screen_descriptor = ScreenDescriptor {
- size_in_pixels: [size.width, size.height],
- pixels_per_point,
- };
-
- let queue = pixels.queue();
- let device = pixels.device();
-
- for (id, delta) in &full_output.textures_delta.set {
- egui_renderer.update_texture(&device, &queue, *id, delta);
- }
-
- let _ = pixels.render_with(|encoder, render_target, context| {
- context.scaling_renderer.render(encoder, render_target);
-
- egui_renderer.update_buffers(
- device,
- &queue,
- encoder,
- &clipped_primitives,
- &screen_descriptor,
- );
+ camera.write_frame_view(&mut renderer_state.frame_view, world);
- let mut egui_pass = encoder
- .begin_render_pass(&wgpu::RenderPassDescriptor {
- label: Some("egui pass"),
- color_attachments: &[Some(wgpu::RenderPassColorAttachment {
- view: render_target,
- resolve_target: None,
- ops: wgpu::Operations {
- load: wgpu::LoadOp::Load,
- store: wgpu::StoreOp::Store,
- },
- depth_slice: None,
- })],
- depth_stencil_attachment: None,
- timestamp_writes: None,
- occlusion_query_set: None,
- multiview_mask: None,
- })
- .forget_lifetime();
-
- egui_renderer.render(
- &mut egui_pass,
- &clipped_primitives,
- &screen_descriptor,
- );
- drop(egui_pass);
-
- Ok(())
- });
+ renderer_state.render(
+ &mut self.config,
+ camera,
+ &self.diagnostics,
+ &mut self.input,
+ );
}
_ => {}
}
@@ -388,9 +669,11 @@ impl ApplicationHandler for App {
// limit our internal redraw requests to (fps)
if now - self.last_frame_requested >= frame_duration {
self.last_frame_requested = now;
- self.window
- .expect("Bug - Window should exist")
- .request_redraw();
+ if let Some(window) = &self.window {
+ window.request_redraw();
+ } else {
+ panic!("No window!")
+ }
}
}
}
diff --git a/src/shader.wgsl b/src/shader.wgsl
new file mode 100644
index 0000000..e545dac
--- /dev/null
+++ b/src/shader.wgsl
@@ -0,0 +1,25 @@
+@group(0) @binding(0) var tex: texture_2d<f32>;
+
+struct VertexOutput {
+ @builtin(position) clip_position: vec4<f32>,
+ @location(0) uv: vec2<f32>,
+};
+
+@vertex
+fn vs_main(
+ @builtin(vertex_index) i: u32,
+) -> VertexOutput {
+ var out: VertexOutput;
+ let uv = vec2f(f32((i << 1u) & 2u), f32(i & 2u));
+ out.clip_position = vec4f(uv.x * 2.0 - 1.0, 1.0 - uv.y * 2.0, 0.0, 1.0);
+ out.uv = uv;
+
+ return out;
+}
+
+@fragment
+fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
+ let dims = vec2f(textureDimensions(tex));
+ return textureLoad(tex, vec2i(in.uv * dims), 0);
+ // return vec4f(0.0, 1.0, 0.0, 1.0);
+} \ No newline at end of file
diff --git a/src/sim/materials/mod.rs b/src/sim/materials/mod.rs
index 0cba5ff..581ce31 100644
--- a/src/sim/materials/mod.rs
+++ b/src/sim/materials/mod.rs
@@ -24,7 +24,7 @@ pub struct MaterialDef {
static MATERIALS: [MaterialDef; 5] = [
MaterialDef {
name: "Void",
- color: (0x00, 0x00, 0x00, 0xFF),
+ color: (0xFF, 0xFF, 0x00, 0xFF),
density: 0,
sim_update: None,
},