diff --git a/editor/src/buffer.rs b/editor/src/buffer.rs index bb3c784055..860cf3d7d6 100644 --- a/editor/src/buffer.rs +++ b/editor/src/buffer.rs @@ -3,6 +3,7 @@ use crate::rect::Rect; use crate::util::size_of_slice; use crate::vertex::Vertex; +use cgmath::Vector3; use wgpu::util::{BufferInitDescriptor, DeviceExt}; pub struct QuadBufferBuilder { @@ -27,7 +28,7 @@ impl QuadBufferBuilder { coords.y - rect.height, coords.x + rect.width, coords.y, - rect.color, + rect.color.into(), ) } @@ -37,7 +38,7 @@ impl QuadBufferBuilder { min_y: f32, max_x: f32, max_y: f32, - color: [f32; 3], + color: Vector3, ) -> Self { self.vertex_data.extend(&[ Vertex { @@ -78,6 +79,71 @@ impl QuadBufferBuilder { } } +pub struct RectBuffers { + pub vertex_buffer: wgpu::Buffer, + pub index_buffer: wgpu::Buffer, + pub num_rects: u32, +} + +pub fn create_rect_buffers( + gpu_device: &wgpu::Device, + encoder: &mut wgpu::CommandEncoder, +) -> RectBuffers { + // Test Rectangles + let test_rect_1 = Rect { + top_left_coords: (-0.2, 0.6).into(), + width: 0.1, + height: 0.5, + color: [0.0, 0.0, 1.0], + }; + let test_rect_2 = Rect { + top_left_coords: (-0.5, 0.0).into(), + width: 0.5, + height: 0.5, + color: [0.0, 1.0, 0.0], + }; + let test_rect_3 = Rect { + top_left_coords: (0.3, 0.3).into(), + width: 0.6, + height: 0.1, + color: [1.0, 0.0, 0.0], + }; + + let vertex_buffer = gpu_device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: Vertex::SIZE * 4 * 3, + usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST, + mapped_at_creation: false, + }); + + let u32_size = std::mem::size_of::() as wgpu::BufferAddress; + + let index_buffer = gpu_device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: u32_size * 6 * 3, + usage: wgpu::BufferUsage::INDEX | wgpu::BufferUsage::COPY_DST, + mapped_at_creation: false, + }); + + let num_rects = { + let (stg_vertex, stg_index, num_indices) = QuadBufferBuilder::new() + .push_rect(&test_rect_1) + .push_rect(&test_rect_2) + .push_rect(&test_rect_3) + .build(&gpu_device); + + stg_vertex.copy_to_buffer(encoder, &vertex_buffer); + stg_index.copy_to_buffer(encoder, &index_buffer); + num_indices + }; + + RectBuffers { + vertex_buffer, + index_buffer, + num_rects, + } +} + pub struct StagingBuffer { buffer: wgpu::Buffer, size: wgpu::BufferAddress, diff --git a/editor/src/keyboard_input.rs b/editor/src/keyboard_input.rs new file mode 100644 index 0000000000..5cb21243c9 --- /dev/null +++ b/editor/src/keyboard_input.rs @@ -0,0 +1,153 @@ +use winit::event::{ElementState, ModifiersState, VirtualKeyCode}; + +pub fn handle_keydown( + elem_state: ElementState, + virtual_keycode: VirtualKeyCode, + _modifiers: ModifiersState, +) { + use winit::event::VirtualKeyCode::*; + + if let ElementState::Released = elem_state { + return; + } + + match virtual_keycode { + Copy => { + todo!("copy"); + } + Paste => { + todo!("paste"); + } + Cut => { + todo!("cut"); + } + _ => {} + } +} + +// pub fn handle_text_input( +// text_state: &mut String, +// elem_state: ElementState, +// virtual_keycode: VirtualKeyCode, +// _modifiers: ModifiersState, +// ) { +// use winit::event::VirtualKeyCode::*; + +// if let ElementState::Released = elem_state { +// return; +// } + +// match virtual_keycode { +// Key1 | Numpad1 => text_state.push('1'), +// Key2 | Numpad2 => text_state.push('2'), +// Key3 | Numpad3 => text_state.push('3'), +// Key4 | Numpad4 => text_state.push('4'), +// Key5 | Numpad5 => text_state.push('5'), +// Key6 | Numpad6 => text_state.push('6'), +// Key7 | Numpad7 => text_state.push('7'), +// Key8 | Numpad8 => text_state.push('8'), +// Key9 | Numpad9 => text_state.push('9'), +// Key0 | Numpad0 => text_state.push('0'), +// A => text_state.push('a'), +// B => text_state.push('b'), +// C => text_state.push('c'), +// D => text_state.push('d'), +// E => text_state.push('e'), +// F => text_state.push('f'), +// G => text_state.push('g'), +// H => text_state.push('h'), +// I => text_state.push('i'), +// J => text_state.push('j'), +// K => text_state.push('k'), +// L => text_state.push('l'), +// M => text_state.push('m'), +// N => text_state.push('n'), +// O => text_state.push('o'), +// P => text_state.push('p'), +// Q => text_state.push('q'), +// R => text_state.push('r'), +// S => text_state.push('s'), +// T => text_state.push('t'), +// U => text_state.push('u'), +// V => text_state.push('v'), +// W => text_state.push('w'), +// X => text_state.push('x'), +// Y => text_state.push('y'), +// Z => text_state.push('z'), +// Escape | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | F13 | F14 | F15 +// | F16 | F17 | F18 | F19 | F20 | F21 | F22 | F23 | F24 | Snapshot | Scroll | Pause +// | Insert | Home | Delete | End | PageDown | PageUp | Left | Up | Right | Down | Compose +// | Caret | Numlock | AbntC1 | AbntC2 | Ax | Calculator | Capital | Convert | Kana +// | Kanji | LAlt | LBracket | LControl | LShift | LWin | Mail | MediaSelect | PlayPause +// | Power | PrevTrack | MediaStop | Mute | MyComputer | NavigateForward +// | NavigateBackward | NextTrack | NoConvert | OEM102 | RAlt | Sysrq | RBracket +// | RControl | RShift | RWin | Sleep | Stop | Unlabeled | VolumeDown | VolumeUp | Wake +// | WebBack | WebFavorites | WebForward | WebHome | WebRefresh | WebSearch | Apps | Tab +// | WebStop => { +// // TODO handle +// } +// Back => { +// text_state.pop(); +// } +// Return | NumpadEnter => { +// text_state.push('\n'); +// } +// Space => { +// text_state.push(' '); +// } +// Comma | NumpadComma => { +// text_state.push(','); +// } +// Add => { +// text_state.push('+'); +// } +// Apostrophe => { +// text_state.push('\''); +// } +// At => { +// text_state.push('@'); +// } +// Backslash => { +// text_state.push('\\'); +// } +// Colon => { +// text_state.push(':'); +// } +// Period | Decimal => { +// text_state.push('.'); +// } +// Equals | NumpadEquals => { +// text_state.push('='); +// } +// Grave => { +// text_state.push('`'); +// } +// Minus | Subtract => { +// text_state.push('-'); +// } +// Multiply => { +// text_state.push('*'); +// } +// Semicolon => { +// text_state.push(';'); +// } +// Slash | Divide => { +// text_state.push('/'); +// } +// Underline => { +// text_state.push('_'); +// } +// Yen => { +// text_state.push('¥'); +// } +// Copy => { +// todo!("copy"); +// } +// Paste => { +// todo!("paste"); +// } +// Cut => { +// todo!("cut"); +// } +// } +// } diff --git a/editor/src/lib.rs b/editor/src/lib.rs index 14532c84e3..d21bc296ce 100644 --- a/editor/src/lib.rs +++ b/editor/src/lib.rs @@ -16,22 +16,22 @@ // See this link to learn wgpu: https://sotrh.github.io/learn-wgpu/ -use crate::buffer::QuadBufferBuilder; -use crate::rect::Rect; +use crate::buffer::create_rect_buffers; +use crate::text::{build_glyph_brush, Text}; use crate::vertex::Vertex; use std::error::Error; use std::io; use std::path::Path; -use wgpu_glyph::{ab_glyph, GlyphBrushBuilder, Section, Text}; use winit::event; -use winit::event::{ElementState, Event, ModifiersState, VirtualKeyCode}; +use winit::event::{Event, ModifiersState}; use winit::event_loop::ControlFlow; pub mod ast; mod buffer; pub mod file; +mod keyboard_input; mod rect; -pub mod text_state; +pub mod text; mod util; mod vertex; @@ -104,12 +104,7 @@ fn run_event_loop() -> Result<(), Box> { let rect_pipeline = make_rect_pipeline(&gpu_device, &swap_chain_descr); - // Prepare glyph_brush - let inconsolata = - ab_glyph::FontArc::try_from_slice(include_bytes!("../Inconsolata-Regular.ttf"))?; - - let mut glyph_brush = - GlyphBrushBuilder::using_font(inconsolata).build(&gpu_device, render_format); + let mut glyph_brush = build_glyph_brush(&gpu_device, render_format)?; let is_animating = true; let mut text_state = String::new(); @@ -161,7 +156,11 @@ fn run_event_loop() -> Result<(), Box> { .. } => { if let Some(virtual_keycode) = input.virtual_keycode { - handle_keydown(input.state, virtual_keycode, keyboard_modifiers); + keyboard_input::handle_keydown( + input.state, + virtual_keycode, + keyboard_modifiers, + ); } } Event::WindowEvent { @@ -203,7 +202,7 @@ fn run_event_loop() -> Result<(), Box> { drop(render_pass); - draw_text( + draw_all_text( &gpu_device, &mut staging_belt, &mut encoder, @@ -294,72 +293,7 @@ fn create_render_pipeline( }) } -struct RectBuffers { - vertex_buffer: wgpu::Buffer, - index_buffer: wgpu::Buffer, - num_rects: u32, -} - -fn create_rect_buffers( - gpu_device: &wgpu::Device, - encoder: &mut wgpu::CommandEncoder, -) -> RectBuffers { - // Test Rectangles - let test_rect_1 = Rect { - top_left_coords: (-0.2, 0.6).into(), - width: 0.1, - height: 0.5, - color: [0.0, 0.0, 1.0], - }; - let test_rect_2 = Rect { - top_left_coords: (-0.5, 0.0).into(), - width: 0.5, - height: 0.5, - color: [0.0, 1.0, 0.0], - }; - let test_rect_3 = Rect { - top_left_coords: (0.3, 0.3).into(), - width: 0.6, - height: 0.1, - color: [0.0, 0.0, 1.0], - }; - - let vertex_buffer = gpu_device.create_buffer(&wgpu::BufferDescriptor { - label: None, - size: Vertex::SIZE * 4 * 3, - usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST, - mapped_at_creation: false, - }); - - let u32_size = std::mem::size_of::() as wgpu::BufferAddress; - - let index_buffer = gpu_device.create_buffer(&wgpu::BufferDescriptor { - label: None, - size: u32_size * 6 * 3, - usage: wgpu::BufferUsage::INDEX | wgpu::BufferUsage::COPY_DST, - mapped_at_creation: false, - }); - - let num_rects = { - let (stg_vertex, stg_index, num_indices) = QuadBufferBuilder::new() - .push_rect(&test_rect_1) - .push_rect(&test_rect_2) - .push_rect(&test_rect_3) - .build(&gpu_device); - - stg_vertex.copy_to_buffer(encoder, &vertex_buffer); - stg_index.copy_to_buffer(encoder, &index_buffer); - num_indices - }; - - RectBuffers { - vertex_buffer, - index_buffer, - num_rects, - } -} - -fn draw_text( +fn draw_all_text( gpu_device: &wgpu::Device, staging_belt: &mut wgpu::util::StagingBelt, encoder: &mut wgpu::CommandEncoder, @@ -368,25 +302,30 @@ fn draw_text( text_state: &str, glyph_brush: &mut wgpu_glyph::GlyphBrush<()>, ) { - glyph_brush.queue(Section { - screen_position: (30.0, 30.0), - bounds: (size.width as f32, size.height as f32), - text: vec![Text::new("Enter some text:") - .with_color([0.4666, 0.2, 1.0, 1.0]) - .with_scale(40.0)], - ..Section::default() - }); + let bounds = (size.width as f32, size.height as f32).into(); - glyph_brush.queue(Section { - screen_position: (30.0, 90.0), - bounds: (size.width as f32, size.height as f32), - text: vec![Text::new(format!("{}|", text_state).as_str()) - .with_color([1.0, 1.0, 1.0, 1.0]) - .with_scale(40.0)], - ..Section::default() - }); + let main_label = Text { + position: (30.0, 30.0).into(), + bounds, + color: (0.4666, 0.2, 1.0, 1.0).into(), + text: String::from("Enter some text:"), + size: 40.0, + ..Default::default() + }; + + let code_text = Text { + position: (30.0, 90.0).into(), + bounds, + color: (1.0, 1.0, 1.0, 1.0).into(), + text: String::from(format!("{}|", text_state).as_str()), + size: 40.0, + ..Default::default() + }; + + text::queue_text_draw(&main_label, glyph_brush); + + text::queue_text_draw(&code_text, glyph_brush); - // Draw the text! glyph_brush .draw_queued( gpu_device, @@ -415,28 +354,3 @@ fn update_text_state(text_state: &mut String, received_char: &char) { } } } - -fn handle_keydown( - elem_state: ElementState, - virtual_keycode: VirtualKeyCode, - _modifiers: ModifiersState, -) { - use winit::event::VirtualKeyCode::*; - - if let ElementState::Released = elem_state { - return; - } - - match virtual_keycode { - Copy => { - todo!("copy"); - } - Paste => { - todo!("paste"); - } - Cut => { - todo!("cut"); - } - _ => {} - } -} diff --git a/editor/src/text.rs b/editor/src/text.rs new file mode 100644 index 0000000000..854522f063 --- /dev/null +++ b/editor/src/text.rs @@ -0,0 +1,62 @@ +// Adapted from https://github.com/sotrh/learn-wgpu +// by Benjamin Hansen, licensed under the MIT license + +use ab_glyph::{FontArc, InvalidFont}; +use cgmath::{Vector2, Vector4}; +use wgpu_glyph::{ab_glyph, GlyphBrush, GlyphBrushBuilder, Section}; + +#[derive(Debug)] +pub struct Text { + pub position: Vector2, + pub bounds: Vector2, + pub color: Vector4, + pub text: String, + pub size: f32, + pub visible: bool, + pub centered: bool, +} + +impl Default for Text { + fn default() -> Self { + Self { + position: (0.0, 0.0).into(), + bounds: (std::f32::INFINITY, std::f32::INFINITY).into(), + color: (1.0, 1.0, 1.0, 1.0).into(), + text: String::new(), + size: 16.0, + visible: true, + centered: false, + } + } +} + +pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) { + let layout = wgpu_glyph::Layout::default().h_align(if text.centered { + wgpu_glyph::HorizontalAlign::Center + } else { + wgpu_glyph::HorizontalAlign::Left + }); + + let section = Section { + screen_position: text.position.into(), + bounds: text.bounds.into(), + layout, + ..Section::default() + } + .add_text( + wgpu_glyph::Text::new(&text.text) + .with_color(text.color) + .with_scale(text.size), + ); + + glyph_brush.queue(section); +} + +pub fn build_glyph_brush( + gpu_device: &wgpu::Device, + render_format: wgpu::TextureFormat, +) -> Result, InvalidFont> { + let inconsolata = FontArc::try_from_slice(include_bytes!("../Inconsolata-Regular.ttf"))?; + + Ok(GlyphBrushBuilder::using_font(inconsolata).build(&gpu_device, render_format)) +} diff --git a/editor/src/text_state.rs b/editor/src/text_state.rs deleted file mode 100644 index f0b7de5f8c..0000000000 --- a/editor/src/text_state.rs +++ /dev/null @@ -1,128 +0,0 @@ -use winit::event::{ElementState, ModifiersState, VirtualKeyCode}; - -pub fn handle_text_input( - text_state: &mut String, - elem_state: ElementState, - virtual_keycode: VirtualKeyCode, - _modifiers: ModifiersState, -) { - use winit::event::VirtualKeyCode::*; - - if let ElementState::Released = elem_state { - return; - } - - match virtual_keycode { - Key1 | Numpad1 => text_state.push('1'), - Key2 | Numpad2 => text_state.push('2'), - Key3 | Numpad3 => text_state.push('3'), - Key4 | Numpad4 => text_state.push('4'), - Key5 | Numpad5 => text_state.push('5'), - Key6 | Numpad6 => text_state.push('6'), - Key7 | Numpad7 => text_state.push('7'), - Key8 | Numpad8 => text_state.push('8'), - Key9 | Numpad9 => text_state.push('9'), - Key0 | Numpad0 => text_state.push('0'), - A => text_state.push('a'), - B => text_state.push('b'), - C => text_state.push('c'), - D => text_state.push('d'), - E => text_state.push('e'), - F => text_state.push('f'), - G => text_state.push('g'), - H => text_state.push('h'), - I => text_state.push('i'), - J => text_state.push('j'), - K => text_state.push('k'), - L => text_state.push('l'), - M => text_state.push('m'), - N => text_state.push('n'), - O => text_state.push('o'), - P => text_state.push('p'), - Q => text_state.push('q'), - R => text_state.push('r'), - S => text_state.push('s'), - T => text_state.push('t'), - U => text_state.push('u'), - V => text_state.push('v'), - W => text_state.push('w'), - X => text_state.push('x'), - Y => text_state.push('y'), - Z => text_state.push('z'), - Escape | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | F13 | F14 | F15 - | F16 | F17 | F18 | F19 | F20 | F21 | F22 | F23 | F24 | Snapshot | Scroll | Pause - | Insert | Home | Delete | End | PageDown | PageUp | Left | Up | Right | Down | Compose - | Caret | Numlock | AbntC1 | AbntC2 | Ax | Calculator | Capital | Convert | Kana - | Kanji | LAlt | LBracket | LControl | LShift | LWin | Mail | MediaSelect | PlayPause - | Power | PrevTrack | MediaStop | Mute | MyComputer | NavigateForward - | NavigateBackward | NextTrack | NoConvert | OEM102 | RAlt | Sysrq | RBracket - | RControl | RShift | RWin | Sleep | Stop | Unlabeled | VolumeDown | VolumeUp | Wake - | WebBack | WebFavorites | WebForward | WebHome | WebRefresh | WebSearch | Apps | Tab - | WebStop => { - // TODO handle - } - Back => { - text_state.pop(); - } - Return | NumpadEnter => { - text_state.push('\n'); - } - Space => { - text_state.push(' '); - } - Comma | NumpadComma => { - text_state.push(','); - } - Add => { - text_state.push('+'); - } - Apostrophe => { - text_state.push('\''); - } - At => { - text_state.push('@'); - } - Backslash => { - text_state.push('\\'); - } - Colon => { - text_state.push(':'); - } - Period | Decimal => { - text_state.push('.'); - } - Equals | NumpadEquals => { - text_state.push('='); - } - Grave => { - text_state.push('`'); - } - Minus | Subtract => { - text_state.push('-'); - } - Multiply => { - text_state.push('*'); - } - Semicolon => { - text_state.push(';'); - } - Slash | Divide => { - text_state.push('/'); - } - Underline => { - text_state.push('_'); - } - Yen => { - text_state.push('¥'); - } - Copy => { - todo!("copy"); - } - Paste => { - todo!("paste"); - } - Cut => { - todo!("cut"); - } - } -} diff --git a/editor/src/vertex.rs b/editor/src/vertex.rs index 241ffc1da2..481fa2d9aa 100644 --- a/editor/src/vertex.rs +++ b/editor/src/vertex.rs @@ -1,12 +1,12 @@ // Taken from https://github.com/sotrh/learn-wgpu // by Benjamin Hansen, licensed under the MIT license -use cgmath::Vector2; +use cgmath::{Vector2, Vector3}; #[derive(Copy, Clone)] pub struct Vertex { #[allow(dead_code)] pub position: Vector2, - pub color: [f32; 3], + pub color: Vector3, } unsafe impl bytemuck::Pod for Vertex {} @@ -26,7 +26,7 @@ impl Vertex { }, // color wgpu::VertexAttributeDescriptor { - offset: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress, + offset: std::mem::size_of::<[f32; 2]>() as wgpu::BufferAddress, shader_location: 1, format: wgpu::VertexFormat::Float3, },