From d89bf1c0afdbab959cf385a3fc010372d9cf4d8f Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 21 Dec 2020 19:49:15 +0100 Subject: [PATCH] highlight all text in editor --- editor/src/buffer.rs | 27 ++++-------- editor/src/lib.rs | 101 +++++++++++++++++++++++-------------------- editor/src/rect.rs | 10 +++++ editor/src/text.rs | 44 +++++++++++++++---- 4 files changed, 108 insertions(+), 74 deletions(-) diff --git a/editor/src/buffer.rs b/editor/src/buffer.rs index b13323bdd5..3b870681b9 100644 --- a/editor/src/buffer.rs +++ b/editor/src/buffer.rs @@ -87,21 +87,8 @@ pub struct RectBuffers { pub fn create_rect_buffers( gpu_device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, + rects: &[Rect] ) -> RectBuffers { - // Test Rectangles - let test_rect_1 = Rect { - top_left_coords: (0.0, 0.0).into(), - width: 400.0, - height: 300.0, - color: [1.0, 0.0, 0.0], - }; - let test_rect_2 = Rect { - top_left_coords: (400.0, 300.0).into(), - width: 400.0, - height: 300.0, - color: [0.0, 0.0, 1.0], - }; - let vertex_buffer = gpu_device.create_buffer(&wgpu::BufferDescriptor { label: None, size: Vertex::SIZE * 4 * 3, @@ -119,10 +106,14 @@ pub fn create_rect_buffers( }); let num_rects = { - let (stg_vertex, stg_index, num_indices) = QuadBufferBuilder::new() - .push_rect(&test_rect_1) - .push_rect(&test_rect_2) - .build(&gpu_device); + let mut quad_buffer_builder = QuadBufferBuilder::new(); + for rect in rects { + quad_buffer_builder = quad_buffer_builder.push_rect(&rect); + } + + + let (stg_vertex, stg_index, num_indices) = + quad_buffer_builder.build(&gpu_device); stg_vertex.copy_to_buffer(encoder, &vertex_buffer); stg_index.copy_to_buffer(encoder, &index_buffer); diff --git a/editor/src/lib.rs b/editor/src/lib.rs index f589e60b74..387a6736f9 100644 --- a/editor/src/lib.rs +++ b/editor/src/lib.rs @@ -11,6 +11,7 @@ use crate::buffer::create_rect_buffers; use crate::text::{build_glyph_brush, Text}; use crate::vertex::Vertex; +use crate::rect::{convert_rect}; use ortho::{init_ortho, update_ortho_buffer, OrthoResources}; use std::error::Error; use std::io; @@ -18,6 +19,7 @@ use std::path::Path; use winit::event; use winit::event::{Event, ModifiersState}; use winit::event_loop::ControlFlow; +use wgpu_glyph::{ab_glyph}; pub mod ast; mod buffer; @@ -189,42 +191,58 @@ fn run_event_loop() -> Result<(), Box> { label: Some("Redraw"), }); - let rect_buffers = create_rect_buffers(&gpu_device, &mut encoder); - - let frame = swap_chain + let frame = swap_chain .get_current_frame() .expect("Failed to acquire next SwapChainFrame") .output; - let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { - attachment: &frame.view, - resolve_target: None, - ops: wgpu::Operations::default(), - }], - depth_stencil_attachment: None, - }); - - if rect_buffers.num_rects > 0 { - render_pass.set_pipeline(&rect_pipeline); - render_pass.set_bind_group(0, &ortho.bind_group, &[]); - render_pass.set_vertex_buffer(0, rect_buffers.vertex_buffer.slice(..)); - render_pass.set_index_buffer(rect_buffers.index_buffer.slice(..)); - render_pass.draw_indexed(0..rect_buffers.num_rects, 0, 0..1); - } - - drop(render_pass); - - draw_all_text( - &gpu_device, - &mut staging_belt, - &mut encoder, - &frame, + let text_bounds_rect_opt = queue_all_text( &size, &text_state, &mut glyph_brush, ); + match text_bounds_rect_opt { + Some(ab_bounds_rect) => { + let rect_buffers = create_rect_buffers( + &gpu_device, + &mut encoder, + &[convert_rect(ab_bounds_rect, [255.0, 255.0, 255.0])], + ); + + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + ops: wgpu::Operations::default(), + }], + depth_stencil_attachment: None, + }); + + render_pass.set_pipeline(&rect_pipeline); + render_pass.set_bind_group(0, &ortho.bind_group, &[]); + render_pass.set_vertex_buffer(0, rect_buffers.vertex_buffer.slice(..)); + render_pass.set_index_buffer(rect_buffers.index_buffer.slice(..)); + render_pass.draw_indexed(0..rect_buffers.num_rects, 0, 0..1); + + drop(render_pass); + }, + None => + (), + }; + + // draw all text + glyph_brush + .draw_queued( + &gpu_device, + &mut staging_belt, + &mut encoder, + &frame.view, + size.width, + size.height, + ) + .expect("Draw queued"); + staging_belt.finish(); cmd_queue.submit(Some(encoder.finish())); @@ -308,20 +326,16 @@ fn create_render_pipeline( }) } -fn draw_all_text( - gpu_device: &wgpu::Device, - staging_belt: &mut wgpu::util::StagingBelt, - encoder: &mut wgpu::CommandEncoder, - frame: &wgpu::SwapChainTexture, +fn queue_all_text( size: &winit::dpi::PhysicalSize, text_state: &str, glyph_brush: &mut wgpu_glyph::GlyphBrush<()>, -) { - let bounds = (size.width as f32, size.height as f32).into(); +) -> Option { + let area_bounds = (size.width as f32, size.height as f32).into(); let main_label = Text { position: (30.0, 30.0).into(), - bounds, + area_bounds, color: (0.4666, 0.2, 1.0, 1.0).into(), text: String::from("Enter some text:"), size: 40.0, @@ -330,8 +344,8 @@ fn draw_all_text( let code_text = Text { position: (30.0, 90.0).into(), - bounds, - color: (1.0, 1.0, 1.0, 1.0).into(), + area_bounds, + color: (0.0, 0.05, 0.46, 1.0).into(), text: String::from(format!("{}|", text_state).as_str()), size: 40.0, ..Default::default() @@ -339,18 +353,9 @@ fn draw_all_text( text::queue_text_draw(&main_label, glyph_brush); - text::queue_text_draw(&code_text, glyph_brush); + let code_bounds_rect_opt = text::queue_text_draw(&code_text, glyph_brush); - glyph_brush - .draw_queued( - gpu_device, - staging_belt, - encoder, - &frame.view, - size.width, - size.height, - ) - .expect("Draw queued"); + code_bounds_rect_opt } fn update_text_state(text_state: &mut String, received_char: &char) { diff --git a/editor/src/rect.rs b/editor/src/rect.rs index e243a2289d..97b585ccbc 100644 --- a/editor/src/rect.rs +++ b/editor/src/rect.rs @@ -1,4 +1,5 @@ use cgmath::Vector2; +use wgpu_glyph::{ab_glyph}; pub struct Rect { pub top_left_coords: Vector2, @@ -6,3 +7,12 @@ pub struct Rect { pub height: f32, pub color: [f32; 3], } + +pub fn convert_rect(glyph_rect: ab_glyph::Rect, color: [f32; 3]) -> Rect { + Rect { + top_left_coords: [glyph_rect.min.x, glyph_rect.min.y].into(), + width: glyph_rect.width(), + height: glyph_rect.height(), + color + } +} diff --git a/editor/src/text.rs b/editor/src/text.rs index 854522f063..c2916f17c9 100644 --- a/editor/src/text.rs +++ b/editor/src/text.rs @@ -3,12 +3,12 @@ use ab_glyph::{FontArc, InvalidFont}; use cgmath::{Vector2, Vector4}; -use wgpu_glyph::{ab_glyph, GlyphBrush, GlyphBrushBuilder, Section}; +use wgpu_glyph::{ab_glyph, GlyphBrush, GlyphBrushBuilder, GlyphCruncher, Section}; #[derive(Debug)] pub struct Text { pub position: Vector2, - pub bounds: Vector2, + pub area_bounds: Vector2, pub color: Vector4, pub text: String, pub size: f32, @@ -20,7 +20,7 @@ impl Default for Text { fn default() -> Self { Self { position: (0.0, 0.0).into(), - bounds: (std::f32::INFINITY, std::f32::INFINITY).into(), + area_bounds: (std::f32::INFINITY, std::f32::INFINITY).into(), color: (1.0, 1.0, 1.0, 1.0).into(), text: String::new(), size: 16.0, @@ -30,7 +30,7 @@ impl Default for Text { } } -pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) { +pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) -> Option{ let layout = wgpu_glyph::Layout::default().h_align(if text.centered { wgpu_glyph::HorizontalAlign::Center } else { @@ -39,17 +39,18 @@ pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) { let section = Section { screen_position: text.position.into(), - bounds: text.bounds.into(), + bounds: text.area_bounds.into(), layout, ..Section::default() - } - .add_text( + }.add_text( wgpu_glyph::Text::new(&text.text) .with_color(text.color) .with_scale(text.size), ); - glyph_brush.queue(section); + glyph_brush.queue(section.clone()); + + glyph_brush.glyph_bounds_custom_layout(section, &layout) } pub fn build_glyph_brush( @@ -60,3 +61,30 @@ pub fn build_glyph_brush( Ok(GlyphBrushBuilder::using_font(inconsolata).build(&gpu_device, render_format)) } + +/*fn my_draw_text(&mut self, ...) { + let layout = ...; + let section = ...; + + // Avoid re-allocating new vec's every time by storing them internally + self.last_glyphs.clear(); + self.last_bounds.clear(); + + // Get all the glyphs for the current section to calculate their bounds. Due to + // mutable borrow, this must be stored first. + self.last_glyphs + .extend(self.brush.glyphs_custom_layout(&s, &layout).cloned()); + + // Calculate the bounds of each glyph + self.last_bounds + .extend(self.last_glyphs.iter().map(|glyph| { + let bounds = &fonts[glyph.font_id.0].glyph_bounds(&glyph.glyph); + Rect::new( + Vec2::new(bounds.min.x, bounds.min.y), + Vec2::new(bounds.max.x, bounds.max.y), + ) + })); + + // Queue the glyphs for drawing + self.brush.queue_custom_layout(s, &layout); +}*/