diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..057ed93 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,64 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in library 'bezier'", + "cargo": { + "args": [ + "test", + "--no-run", + "--lib", + "--package=bezier" + ], + "filter": { + "name": "bezier", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'bezier'", + "cargo": { + "args": [ + "build", + "--bin=bezier", + "--package=bezier" + ], + "filter": { + "name": "bezier", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'bezier'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=bezier", + "--package=bezier" + ], + "filter": { + "name": "bezier", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index f10d8e4..a49e716 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,6 +131,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "approx" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" +dependencies = [ + "num-traits", +] + [[package]] name = "arrayref" version = "0.3.7" @@ -175,7 +184,9 @@ name = "bezier" version = "0.1.0" dependencies = [ "bytemuck", + "cgmath", "env_logger", + "geo", "log", "pollster", "wgpu", @@ -260,6 +271,12 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.6.0" @@ -321,6 +338,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cgmath" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317" +dependencies = [ + "approx", + "num-traits", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -471,6 +498,22 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "earcutr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79127ed59a85d7687c409e9978547cffb7dc79675355ed22da6b66fd5f6ead01" +dependencies = [ + "itertools", + "num-traits", +] + +[[package]] +name = "either" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" + [[package]] name = "env_filter" version = "0.1.0" @@ -510,6 +553,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "float_next_after" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" + [[package]] name = "foreign-types" version = "0.5.0" @@ -537,6 +586,44 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +[[package]] +name = "geo" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f811f663912a69249fa620dcd2a005db7254529da2d8a0b23942e81f47084501" +dependencies = [ + "earcutr", + "float_next_after", + "geo-types", + "geographiclib-rs", + "log", + "num-traits", + "robust", + "rstar", + "spade", +] + +[[package]] +name = "geo-types" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff16065e5720f376fbced200a5ae0f47ace85fd70b7e54269790281353b6d61" +dependencies = [ + "approx", + "num-traits", + "rstar", + "serde", +] + +[[package]] +name = "geographiclib-rs" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e5ed84f8089c70234b0a8e0aedb6dc733671612ddc0d37c6066052f9781960" +dependencies = [ + "libm", +] + [[package]] name = "gethostname" version = "0.4.3" @@ -642,6 +729,15 @@ dependencies = [ "bitflags 2.5.0", ] +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -667,6 +763,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + [[package]] name = "hermit-abi" version = "0.3.9" @@ -712,6 +818,15 @@ version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "jni" version = "0.21.1" @@ -795,6 +910,12 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libredox" version = "0.0.2" @@ -925,6 +1046,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1209,6 +1331,23 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" +[[package]] +name = "robust" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf4a6aa5f6d6888f39e980649f3ad6b666acdce1d78e95b8a2cb076e687ae30" + +[[package]] +name = "rstar" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133315eb94c7b1e8d0cb097e5a710d850263372fd028fff18969de708afc7008" +dependencies = [ + "heapless", + "num-traits", + "smallvec", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -1340,6 +1479,18 @@ dependencies = [ "serde", ] +[[package]] +name = "spade" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b20a809169ae442497e41a997fc5f14e2eea04e6ac590816a910d5d8068c8c0" +dependencies = [ + "hashbrown", + "num-traits", + "robust", + "smallvec", +] + [[package]] name = "spirv" version = "0.3.0+sdk-1.3.268.0" @@ -1349,6 +1500,12 @@ dependencies = [ "bitflags 2.5.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 817d798..608dd32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,5 @@ env_logger = "*" pollster = "*" log = "0.4.21" bytemuck = { version = "1.12", features = [ "derive" ] } +cgmath = "0.18" +geo = "0.28.0" diff --git a/src/curve.rs b/src/curve.rs new file mode 100644 index 0000000..5fe0acc --- /dev/null +++ b/src/curve.rs @@ -0,0 +1,199 @@ +use cgmath::InnerSpace; + +use crate::{vertex::RenderData, Vertex}; + +type Vector2 = cgmath::Vector2; + +fn vec2(x: f64, y: f64) -> Vector2 { + cgmath::vec2(x, y) +} + +pub struct Bezier { + pub start: Vector2, + pub middle: Vector2, + pub end: Vector2, +} + +impl Bezier { + pub fn subdivide(&self, count: usize) -> PolyLine { + PolyLine { + points: (0..count) + .map(|i| self.eval((i as f64) / (count - 1) as f64)) + .collect(), + } + } + + pub fn new(start: Vector2, middle: Vector2, end: Vector2) -> Self { + Self { start, middle, end } + } + + fn eval(&self, t: f64) -> Vector2 { + let a = Self::lerp(self.start, self.middle, t); + let b = Self::lerp(self.middle, self.end, t); + Self::lerp(a, b, t) + } + + fn lerp(start: Vector2, end: Vector2, t: f64) -> Vector2 { + end * t + start * (1.0 - t) + } +} + +pub struct PolyLine { + pub points: Vec, +} + +impl PolyLine { + pub fn new() -> Self { + Self { points: Vec::new() } + } + + pub fn get_render_data(&self, width: f64) -> RenderData { + let mut result = RenderData::new(); + + for i in 1..self.points.len() { + result = result.merge(self.get_segment_render_data(i, width)); + } + + for i in 1..self.points.len() - 1 { + result = result.merge(self.get_connection_render_data(i, width)); + } + + result + } + + fn get_segment_render_data(&self, i: usize, width: f64) -> RenderData { + let start_points = self.get_adjusted_start_points(i - 1, width); + let end_points = self.get_adjusted_end_points(i, width); + let vertices: Vec = [start_points.0, start_points.1, end_points.0, end_points.1] + .map(Vector2::into) + .map(Vertex::new_f64) + .into_iter() + .collect(); + let indices: Vec<_> = vec![0, 2, 3, 0, 3, 1]; + RenderData { vertices, indices } + } + + fn get_connection_render_data(&self, i: usize, width: f64) -> RenderData { + let vertices: Vec<_> = match self.get_connection(i, width) { + Some((intersection, false)) => { + vec![ + self.get_end_points(i, width).1, + intersection, + self.get_start_points(i, width).1, + ] + } + Some((intersection, true)) => { + vec![ + self.get_end_points(i, width).0, + intersection, + self.get_start_points(i, width).0, + ] + } + None => vec![], + } + .into_iter() + .map(Vector2::into) + .map(Vertex::new_f64) + .into_iter() + .collect(); + let indices = if vertices.is_empty() { + vec![] + } else { + vec![0, 1, 2] + }; + RenderData { vertices, indices } + } + + fn get_adjusted_start_points(&self, i: usize, width: f64) -> (Vector2, Vector2) { + let start_points = self.get_start_points(i, width); + if i == 0 { + return start_points; + } + match self.get_connection(i, width) { + Some((intersection, false)) => (intersection, start_points.1), + Some((intersection, true)) => (start_points.0, intersection), + None => start_points, + } + } + + fn get_adjusted_end_points(&self, i: usize, width: f64) -> (Vector2, Vector2) { + let end_points = self.get_end_points(i, width); + if i + 1 == self.points.len() { + return end_points; + } + match self.get_connection(i, width) { + Some((intersection, false)) => (intersection, end_points.1), + Some((intersection, true)) => (end_points.0, intersection), + None => end_points, + } + } + + fn get_connection(&self, i: usize, width: f64) -> Option<(Vector2, bool)> { + let start_points = self.get_start_points(i - 1, width); + let end_points = self.get_end_points(i, width); + let next_start_points = self.get_start_points(i, width); + let next_end_points = self.get_end_points(i + 1, width); + let lines = ( + Self::line(start_points.0, end_points.0), + Self::line(start_points.1, end_points.1), + ); + let next_lines = ( + Self::line(next_start_points.0, next_end_points.0), + Self::line(next_start_points.1, next_end_points.1), + ); + + use geo::algorithm::line_intersection::{line_intersection, LineIntersection}; + + let intersections = ( + line_intersection(lines.0, next_lines.0), + line_intersection(lines.1, next_lines.1), + ); + + match intersections { + (Some(LineIntersection::SinglePoint { intersection, .. }), None) => { + Some((Vector2::new(intersection.x, intersection.y), false)) + } + (None, Some(LineIntersection::SinglePoint { intersection, .. })) => { + Some((Vector2::new(intersection.x, intersection.y), true)) + } + _ => None, + } + } + + fn get_start_points(&self, i: usize, width: f64) -> (Vector2, Vector2) { + if i + 1 == self.points.len() { + panic!(); + } + Self::offset_by_direction( + self.points[i], + (self.points[i + 1] - self.points[i]).normalize() * width, + ) + } + + fn get_end_points(&self, i: usize, width: f64) -> (Vector2, Vector2) { + if i == 0 { + panic!(); + } + Self::offset_by_direction( + self.points[i], + (self.points[i] - self.points[i - 1]).normalize() * width, + ) + } + + fn line(start: Vector2, end: Vector2) -> geo::Line { + geo::Line { + start: geo::Coord { + x: start.x, + y: start.y, + }, + end: geo::Coord { x: end.x, y: end.y }, + } + } + + fn offset_by_direction(point: Vector2, direction: Vector2) -> (Vector2, Vector2) { + ( + point + vec2(direction.y, -direction.x), + point + vec2(-direction.y, direction.x), + ) + } +} diff --git a/src/lib.rs b/src/lib.rs index f98c177..7a9fe19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,11 @@ -pub mod vertex; +pub mod curve; mod state; +pub mod vertex; + +use std::time::SystemTime; -pub use vertex::Vertex; use state::State; +pub use vertex::Vertex; use winit::{ event::{Event, KeyEvent, WindowEvent}, @@ -22,6 +25,8 @@ pub async fn run() { let mut state = State::new(&window).await; + let start_time = SystemTime::now(); + let _ = event_loop.run(move |mut event, control_flow| match event { Event::WindowEvent { ref mut event, @@ -42,7 +47,7 @@ pub async fn run() { state.resize(*physical_size); } WindowEvent::RedrawRequested => { - state.update(); + state.update(start_time.elapsed().unwrap()); match state.render() { Ok(_) => {} Err(wgpu::SurfaceError::Lost) => {} /*state.resize(state.size)*/, diff --git a/src/shader.wgsl b/src/shader.wgsl index 5694a97..a875635 100644 --- a/src/shader.wgsl +++ b/src/shader.wgsl @@ -4,20 +4,20 @@ struct VertexInput { struct VertexOutput { @builtin(position) clip_position: vec4, + @location(0) color: vec3, } @vertex fn vs_main( - @builtin(vertex_index) in_vertex_index: u32, + model: VertexInput ) -> VertexOutput { var out: VertexOutput; - let x = f32(1 - i32(in_vertex_index)) * 0.5; - let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5; - out.clip_position = vec4(x, y, 0.0, 1.0); + out.color = vec3(1.0, 1.0, 1.0); + out.clip_position = vec4(model.position, 0.0, 1.0); return out; } @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4 { - return vec4(0.3, 0.2, 0.1, 1.0); + return vec4(in.color, 1.0); } diff --git a/src/state.rs b/src/state.rs index d08e67e..6be3dba 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,5 +1,7 @@ -use wgpu::{util::DeviceExt, ColorTargetState}; -use crate::Vertex; +use std::time::Duration; + +use crate::{curve::Bezier, Vertex}; +use wgpu::ColorTargetState; pub struct State<'window> { window: &'window winit::window::Window, @@ -8,9 +10,13 @@ pub struct State<'window> { device: wgpu::Device, queue: wgpu::Queue, - render_pipeline: wgpu::RenderPipeline, + pipelines: [wgpu::RenderPipeline; 2], + current_pipeline: usize, vertex_buffer: wgpu::Buffer, + index_buffer: wgpu::Buffer, + + num_indices: u32, } impl<'window> State<'window> { @@ -37,7 +43,7 @@ impl<'window> State<'window> { .request_device( &wgpu::DeviceDescriptor { label: Some("Wgpu device"), - required_features: wgpu::Features::empty(), + required_features: wgpu::Features::POLYGON_MODE_LINE, required_limits: wgpu::Limits::default(), }, None, @@ -50,19 +56,26 @@ impl<'window> State<'window> { let shader_module = device.create_shader_module(wgpu::include_wgsl!("shader.wgsl")); - let vertices = [ - Vertex::new_white([0.0, 0.0]), - Vertex::new_white([1.0, 0.0]), - Vertex::new_white([1.0, 1.0]), - ]; - - let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: Some("Vertex Buffer"), - contents: bytemuck::cast_slice(&vertices), - usage: wgpu::BufferUsages::VERTEX, + usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + size: 10 * 2048, + mapped_at_creation: false, }); - let render_pipeline = Self::create_render_pipeline(&device, &shader_module, &surface_config); + let index_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Index Buffer"), + usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST, + size: 10 * 1024, + mapped_at_creation: false, + }); + + // println!("{:#?} {:#?}", vertices[0], vertices[1]); + + let pipelines = [ + Self::create_fill_render_pipeline(&device, &shader_module, &surface_config), + Self::create_line_render_pipeline(&device, &shader_module, &surface_config), + ]; Self { window, @@ -70,8 +83,11 @@ impl<'window> State<'window> { surface, device, queue, - render_pipeline, - vertex_buffer + pipelines, + current_pipeline: 0, + vertex_buffer, + index_buffer, + num_indices: 0, } } @@ -116,17 +132,34 @@ impl<'window> State<'window> { occlusion_query_set: None, }); - render_pass.set_pipeline(&self.render_pipeline); + render_pass.set_pipeline(&self.pipelines[self.current_pipeline]); render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); - render_pass.draw(0..3, 0..1); - } + render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint32); + render_pass.draw_indexed(0..self.num_indices, 0, 0..1); + } pub fn window(&self) -> &winit::window::Window { self.window } pub fn input(&mut self, _event: &mut winit::event::WindowEvent) -> bool { - false + use winit::event::{ElementState, KeyEvent, WindowEvent}; + use winit::keyboard::{KeyCode, PhysicalKey}; + match _event { + WindowEvent::KeyboardInput { + event: + KeyEvent { + physical_key: PhysicalKey::Code(KeyCode::Space), + state: ElementState::Pressed, + .. + }, + .. + } => { + self.current_pipeline = self.current_pipeline ^ 1; + false + } + _ => false, + } } pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { @@ -138,13 +171,71 @@ impl<'window> State<'window> { self.surface.configure(&self.device, &self.surface_config); } - pub fn update(&mut self) {} + pub fn update(&mut self, since_start: Duration) { + let width = 0.01; + let count = 30; - fn create_render_pipeline(device: &wgpu::Device, shader_module: &wgpu::ShaderModule, surface_config: &wgpu::SurfaceConfiguration) -> wgpu::RenderPipeline { + let speed = 1000.0; + + let start_y = ((since_start.as_millis() as f64) / speed).sin() * 0.5; + let middle_y = ((since_start.as_millis() as f64) / speed * 2.0).sin(); + let end_y = ((since_start.as_millis() as f64) / speed * 1.5).sin() * 0.5; + + let poly_line = Bezier::new( + cgmath::Vector2 { + x: -0.5, + y: start_y, + }, + cgmath::Vector2 { + x: 0.0, + y: middle_y, + }, + cgmath::Vector2 { x: 0.5, y: end_y }, + ) + .subdivide(count); + + let data = poly_line.get_render_data(width); + + self.queue + .write_buffer(&self.vertex_buffer, 0, bytemuck::cast_slice(&data.vertices)); + self.queue + .write_buffer(&self.index_buffer, 0, bytemuck::cast_slice(&data.indices)); + self.num_indices = data.indices.len() as u32; + } + + fn create_fill_render_pipeline( + device: &wgpu::Device, + shader_module: &wgpu::ShaderModule, + surface_config: &wgpu::SurfaceConfiguration, + ) -> wgpu::RenderPipeline { let vertex = Self::create_vertex_state(shader_module); let color_targets = Self::create_color_targets(surface_config); let fragment = Self::create_fragment_state(shader_module, &color_targets); - let primitive = Self::create_primitive_state(); + let primitive = Self::create_fill_primitive_state(); + let multisample = Self::create_multisample_state(); + + let render_pipeline_layout = Self::create_pipeline_layout(device); + device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("Render Pipeline"), + layout: Some(&render_pipeline_layout), + vertex, + fragment: Some(fragment), + primitive, + depth_stencil: None, + multisample, + multiview: None, + }) + } + + fn create_line_render_pipeline( + device: &wgpu::Device, + shader_module: &wgpu::ShaderModule, + surface_config: &wgpu::SurfaceConfiguration, + ) -> wgpu::RenderPipeline { + let vertex = Self::create_vertex_state(shader_module); + let color_targets = Self::create_color_targets(surface_config); + let fragment = Self::create_fragment_state(shader_module, &color_targets); + let primitive = Self::create_line_primitive_state(); let multisample = Self::create_multisample_state(); let render_pipeline_layout = Self::create_pipeline_layout(device); @@ -168,7 +259,11 @@ impl<'window> State<'window> { }) } - fn create_surface_config(surface: &wgpu::Surface, adapter: &wgpu::Adapter, size: &winit::dpi::PhysicalSize) -> wgpu::SurfaceConfiguration { + fn create_surface_config( + surface: &wgpu::Surface, + adapter: &wgpu::Adapter, + size: &winit::dpi::PhysicalSize, + ) -> wgpu::SurfaceConfiguration { let surface_capabilities = surface.get_capabilities(adapter); let surface_format = surface_capabilities .formats @@ -181,7 +276,7 @@ impl<'window> State<'window> { format: surface_format, width: size.width, height: size.height, - present_mode: wgpu::PresentMode::Fifo, + present_mode: wgpu::PresentMode::AutoNoVsync, desired_maximum_frame_latency: 2, alpha_mode: surface_capabilities.alpha_modes[0], view_formats: vec![], @@ -198,7 +293,10 @@ impl<'window> State<'window> { } } - fn create_fragment_state<'a>(shader_module: &'a wgpu::ShaderModule, targets: &'a [Option]) -> wgpu::FragmentState<'a> { + fn create_fragment_state<'a>( + shader_module: &'a wgpu::ShaderModule, + targets: &'a [Option], + ) -> wgpu::FragmentState<'a> { wgpu::FragmentState { module: shader_module, entry_point: "fs_main", @@ -206,7 +304,9 @@ impl<'window> State<'window> { } } - fn create_color_targets(surface_config: &wgpu::SurfaceConfiguration) -> Vec> { + fn create_color_targets( + surface_config: &wgpu::SurfaceConfiguration, + ) -> Vec> { vec![Some(wgpu::ColorTargetState { format: surface_config.format, blend: Some(wgpu::BlendState::REPLACE), @@ -214,19 +314,35 @@ impl<'window> State<'window> { })] } - fn create_primitive_state() -> wgpu::PrimitiveState { + fn create_fill_primitive_state() -> wgpu::PrimitiveState { wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, strip_index_format: None, front_face: wgpu::FrontFace::Ccw, - cull_mode: Some(wgpu::Face::Back), + cull_mode: None, polygon_mode: wgpu::PolygonMode::Fill, unclipped_depth: false, conservative: false, } } + fn create_line_primitive_state() -> wgpu::PrimitiveState { + wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: None, + polygon_mode: wgpu::PolygonMode::Line, + unclipped_depth: false, + conservative: false, + } + } + fn create_multisample_state() -> wgpu::MultisampleState { - wgpu::MultisampleState { count: 1, mask: !0, alpha_to_coverage_enabled: false } + wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + } } } diff --git a/src/vertex.rs b/src/vertex.rs index e4571b4..9f38a5c 100644 --- a/src/vertex.rs +++ b/src/vertex.rs @@ -2,19 +2,21 @@ #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] pub struct Vertex { position: [f32; 2], - color: [f32; 3], } impl Vertex { - pub fn new(position: [f32; 2], color: [f32; 3]) -> Vertex { - Vertex {position, color} + pub fn new(position: [f32; 2]) -> Vertex { + Vertex { position } } - pub fn new_white(position: [f32; 2]) -> Vertex { - Vertex {position, color: [1.0, 1.0, 1.0]} + pub fn new_f64(position: [f64; 2]) -> Vertex { + Vertex { + position: position.map(|x| x as f32), + } } - const ATTRIBS: [wgpu::VertexAttribute; 2] = wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x3]; + const ATTRIBS: [wgpu::VertexAttribute; 2] = + wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x3]; pub const fn desc() -> wgpu::VertexBufferLayout<'static> { use std::mem; @@ -26,3 +28,28 @@ impl Vertex { } } +pub struct RenderData { + pub vertices: Vec, + pub indices: Vec, +} + +impl RenderData { + pub fn new() -> RenderData { + RenderData { + vertices: vec![], + indices: vec![], + } + } + + pub fn merge(self: RenderData, other: RenderData) -> RenderData { + let vertices_len = self.vertices.len() as u32; + RenderData { + vertices: self.vertices.into_iter().chain(other.vertices).collect(), + indices: self + .indices + .into_iter() + .chain(other.indices.into_iter().map(|i| i + vertices_len)) + .collect(), + } + } +}