summaryrefslogtreecommitdiffstats
path: root/wgpu
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2019-10-05 05:12:36 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2019-10-05 05:12:36 +0200
commit0c3f78713d24b263e94cf6aebb8862926feaff23 (patch)
treefd7536e245228369dfb3300826002459c5a99ff3 /wgpu
parenta90f7fcb987f667a80038a5e72f379abbd59d932 (diff)
downloadiced-0c3f78713d24b263e94cf6aebb8862926feaff23.tar.gz
iced-0c3f78713d24b263e94cf6aebb8862926feaff23.tar.bz2
iced-0c3f78713d24b263e94cf6aebb8862926feaff23.zip
Draft basic text rendering using `wgpu_glyph`
Diffstat (limited to 'wgpu')
-rw-r--r--wgpu/Cargo.toml1
-rw-r--r--wgpu/src/lib.rs226
2 files changed, 186 insertions, 41 deletions
diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml
index 879def28..79661baa 100644
--- a/wgpu/Cargo.toml
+++ b/wgpu/Cargo.toml
@@ -13,4 +13,5 @@ vulkan = ["wgpu/vulkan"]
[dependencies]
iced_native = { version = "0.1.0-alpha", path = "../native" }
wgpu = "0.3"
+wgpu_glyph = "0.4"
raw-window-handle = "0.1"
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index 28964858..d8f727cd 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -1,7 +1,7 @@
use iced_native::{
button, checkbox, column, image, radio, renderer::Debugger, row, slider,
text, Button, Checkbox, Color, Column, Image, Layout, Node, Point, Radio,
- Row, Slider, Style, Text, Widget,
+ Rectangle, Row, Slider, Style, Text, Widget,
};
use raw_window_handle::HasRawWindowHandle;
@@ -10,28 +10,34 @@ use wgpu::{
Instance, Limits, PowerPreference, RequestAdapterOptions, Surface,
SwapChain, SwapChainDescriptor, TextureFormat, TextureUsage,
};
+use wgpu_glyph::{GlyphBrush, GlyphBrushBuilder, GlyphCruncher, Section};
+
+use std::f32;
+use std::{cell::RefCell, rc::Rc};
pub struct Renderer {
instance: Instance,
surface: Surface,
adapter: Adapter,
device: Device,
+ glyph_brush: Rc<RefCell<GlyphBrush<'static, ()>>>,
+}
+
+pub struct Target {
+ width: u16,
+ height: u16,
swap_chain: SwapChain,
}
impl Renderer {
- pub fn new<W: HasRawWindowHandle>(
- window: &W,
- width: u32,
- height: u32,
- ) -> Self {
+ pub fn new<W: HasRawWindowHandle>(window: &W) -> Self {
let instance = Instance::new();
let adapter = instance.request_adapter(&RequestAdapterOptions {
power_preference: PowerPreference::LowPower,
});
- let device = adapter.request_device(&DeviceDescriptor {
+ let mut device = adapter.request_device(&DeviceDescriptor {
extensions: Extensions {
anisotropic_filtering: false,
},
@@ -40,28 +46,40 @@ impl Renderer {
let surface = instance.create_surface(window.raw_window_handle());
- let swap_chain = device.create_swap_chain(
- &surface,
- &SwapChainDescriptor {
- usage: TextureUsage::OUTPUT_ATTACHMENT,
- format: TextureFormat::Bgra8UnormSrgb,
- width,
- height,
- present_mode: wgpu::PresentMode::Vsync,
- },
- );
+ let font: &[u8] =
+ include_bytes!("../../examples/tour/resources/Roboto-Regular.ttf");
+
+ let glyph_brush = GlyphBrushBuilder::using_font_bytes(font)
+ .build(&mut device, TextureFormat::Bgra8UnormSrgb);
Self {
instance,
surface,
adapter,
device,
- swap_chain,
+ glyph_brush: Rc::new(RefCell::new(glyph_brush)),
}
}
- pub fn draw(&mut self) {
- let frame = self.swap_chain.get_next_texture();
+ pub fn target(&self, width: u16, height: u16) -> Target {
+ Target {
+ width,
+ height,
+ swap_chain: self.device.create_swap_chain(
+ &self.surface,
+ &SwapChainDescriptor {
+ usage: TextureUsage::OUTPUT_ATTACHMENT,
+ format: TextureFormat::Bgra8UnormSrgb,
+ width: u32::from(width),
+ height: u32::from(height),
+ present_mode: wgpu::PresentMode::Vsync,
+ },
+ ),
+ }
+ }
+
+ pub fn draw(&mut self, target: &mut Target, primitive: &Primitive) {
+ let frame = target.swap_chain.get_next_texture();
let mut encoder = self
.device
@@ -83,39 +101,169 @@ impl Renderer {
depth_stencil_attachment: None,
});
+ self.draw_primitive(primitive);
+
+ self.glyph_brush
+ .borrow_mut()
+ .draw_queued(
+ &mut self.device,
+ &mut encoder,
+ &frame.view,
+ u32::from(target.width),
+ u32::from(target.height),
+ )
+ .expect("Draw text");
+
self.device.get_queue().submit(&[encoder.finish()]);
}
+
+ fn draw_primitive(&mut self, primitive: &Primitive) {
+ match primitive {
+ Primitive::None => {}
+ Primitive::Group { primitives } => {
+ for primitive in primitives {
+ self.draw_primitive(primitive)
+ }
+ }
+ Primitive::Text {
+ content,
+ bounds,
+ size,
+ } => self.glyph_brush.borrow_mut().queue(Section {
+ text: &content,
+ screen_position: (bounds.x, bounds.y),
+ bounds: (bounds.width, bounds.height),
+ scale: wgpu_glyph::Scale { x: *size, y: *size },
+ ..Default::default()
+ }),
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
+pub enum Primitive {
+ None,
+ Group {
+ primitives: Vec<Primitive>,
+ },
+ Text {
+ content: String,
+ bounds: Rectangle,
+ size: f32,
+ },
+}
+
+impl iced_native::Renderer for Renderer {
+ type Primitive = Primitive;
}
impl column::Renderer for Renderer {
fn draw<Message>(
&mut self,
- _column: &Column<'_, Message, Self>,
- _layout: Layout<'_>,
- _cursor_position: Point,
+ column: &Column<'_, Message, Self>,
+ layout: Layout<'_>,
+ cursor_position: Point,
) -> Self::Primitive {
- ()
+ Primitive::Group {
+ primitives: column
+ .children
+ .iter()
+ .zip(layout.children())
+ .map(|(child, layout)| {
+ child.draw(self, layout, cursor_position)
+ })
+ .collect(),
+ }
}
}
impl row::Renderer for Renderer {
fn draw<Message>(
&mut self,
- _column: &Row<'_, Message, Self>,
- _layout: Layout<'_>,
- _cursor_position: Point,
+ row: &Row<'_, Message, Self>,
+ layout: Layout<'_>,
+ cursor_position: Point,
) -> Self::Primitive {
- ()
+ Primitive::Group {
+ primitives: row
+ .children
+ .iter()
+ .zip(layout.children())
+ .map(|(child, layout)| {
+ child.draw(self, layout, cursor_position)
+ })
+ .collect(),
+ }
}
}
impl text::Renderer for Renderer {
- fn node(&self, _text: &Text) -> Node {
- Node::new(Style::default())
+ fn node(&self, text: &Text) -> Node {
+ let glyph_brush = self.glyph_brush.clone();
+ let content = text.content.clone();
+
+ // TODO: Investigate why stretch tries to measure this MANY times
+ // with every ancestor's bounds.
+ // Bug? Using the library wrong? I should probably open an issue on
+ // the stretch repository.
+ // I noticed that the first measure is the one that matters in
+ // practice. Here, we use a RefCell to store the cached measurement.
+ let measure = RefCell::new(None);
+ let size = text.size.map(f32::from).unwrap_or(20.0);
+
+ let style = Style::default().width(text.width);
+
+ iced_native::Node::with_measure(style, move |bounds| {
+ let mut measure = measure.borrow_mut();
+
+ if measure.is_none() {
+ let bounds = (
+ match bounds.width {
+ iced_native::Number::Undefined => f32::INFINITY,
+ iced_native::Number::Defined(w) => w,
+ },
+ match bounds.height {
+ iced_native::Number::Undefined => f32::INFINITY,
+ iced_native::Number::Defined(h) => h,
+ },
+ );
+
+ let text = Section {
+ text: &content,
+ scale: wgpu_glyph::Scale { x: size, y: size },
+ bounds,
+ ..Default::default()
+ };
+
+ let (width, height) = if let Some(bounds) =
+ glyph_brush.borrow_mut().glyph_bounds(&text)
+ {
+ (bounds.width(), bounds.height())
+ } else {
+ (0.0, 0.0)
+ };
+
+ let size = iced_native::Size { width, height };
+
+ // If the text has no width boundary we avoid caching as the
+ // layout engine may just be measuring text in a row.
+ if bounds.0 == f32::INFINITY {
+ return size;
+ } else {
+ *measure = Some(size);
+ }
+ }
+
+ measure.unwrap()
+ })
}
- fn draw(&mut self, _text: &Text, _layout: Layout<'_>) -> Self::Primitive {
- ()
+ fn draw(&mut self, text: &Text, layout: Layout<'_>) -> Self::Primitive {
+ Primitive::Text {
+ content: text.content.clone(),
+ size: f32::from(text.size.unwrap_or(20)),
+ bounds: layout.bounds(),
+ }
}
}
@@ -130,7 +278,7 @@ impl checkbox::Renderer for Renderer {
_layout: Layout<'_>,
_cursor_position: Point,
) -> Self::Primitive {
- ()
+ Primitive::None
}
}
@@ -145,7 +293,7 @@ impl radio::Renderer for Renderer {
_layout: Layout<'_>,
_cursor_position: Point,
) -> Self::Primitive {
- ()
+ Primitive::None
}
}
@@ -160,7 +308,7 @@ impl slider::Renderer for Renderer {
_layout: Layout<'_>,
_cursor_position: Point,
) -> Self::Primitive {
- ()
+ Primitive::None
}
}
@@ -174,7 +322,7 @@ impl image::Renderer<&str> for Renderer {
_checkbox: &Image<&str>,
_layout: Layout<'_>,
) -> Self::Primitive {
- ()
+ Primitive::None
}
}
@@ -189,14 +337,10 @@ impl button::Renderer for Renderer {
_layout: Layout<'_>,
_cursor_position: Point,
) -> Self::Primitive {
- ()
+ Primitive::None
}
}
-impl iced_native::Renderer for Renderer {
- type Primitive = ();
-}
-
impl Debugger for Renderer {
fn explain<Message>(
&mut self,