mirror of
https://github.com/danbulant/mangui
synced 2026-07-07 20:00:35 +00:00
improved text rendering, again
This commit is contained in:
parent
24481bed2a
commit
455fad5269
7 changed files with 115 additions and 188 deletions
|
|
@ -1,81 +0,0 @@
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
|
||||||
use mangui::{SharedNode, nodes::{layout::Layout, Style}, taffy::prelude::Size};
|
|
||||||
use rusalka::{component::Component, nodes::{primitives::{Rectangle, RectangleAttributes}, insert, detach}, SharedComponent, WeakSharedComponent, invalidator::Invalidator};
|
|
||||||
|
|
||||||
pub struct DemoComponent {
|
|
||||||
rect: SharedComponent<Rectangle>,
|
|
||||||
attrs: DemoComponentAttributes,
|
|
||||||
layout: Arc<RwLock<Layout>>,
|
|
||||||
selfref: WeakSharedComponent<Self>,
|
|
||||||
test: Arc<Mutex<Invalidator<bool>>>
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct DemoComponentAttributes {}
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct PartialDemoComponentAttributes {}
|
|
||||||
|
|
||||||
impl From<DemoComponentAttributes> for PartialDemoComponentAttributes {
|
|
||||||
fn from(_attrs: DemoComponentAttributes) -> Self {
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl Component for DemoComponent {
|
|
||||||
type ComponentAttrs = DemoComponentAttributes;
|
|
||||||
type PartialComponentAttrs = PartialDemoComponentAttributes;
|
|
||||||
fn new(attrs: Self::ComponentAttrs, selfref: WeakSharedComponent<Self>) -> Self {
|
|
||||||
let test = Arc::new(Mutex::new(Invalidator::new(false)));
|
|
||||||
let this = Self {
|
|
||||||
rect: Arc::new_cyclic(|selfref| Mutex::new(Rectangle::new(RectangleAttributes { ..Default::default() }, selfref.clone()))),
|
|
||||||
layout: Arc::new(RwLock::new(Layout {
|
|
||||||
style: Style {
|
|
||||||
layout: mangui::nodes::TaffyStyle {
|
|
||||||
min_size: Size {
|
|
||||||
width: mangui::taffy::style::Dimension::Length( if **test.lock().unwrap() { 50. } else { 100. }),
|
|
||||||
height: mangui::taffy::style::Dimension::Length(100.)
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
})),
|
|
||||||
attrs,
|
|
||||||
selfref,
|
|
||||||
test
|
|
||||||
};
|
|
||||||
let selfref = this.selfref.clone();
|
|
||||||
this.layout.write().unwrap().events.add_handler(Box::new(move |event| {
|
|
||||||
let selfref = selfref.upgrade().unwrap();
|
|
||||||
let this = selfref.lock().unwrap();
|
|
||||||
let attrs = &this.attrs;
|
|
||||||
let test = &this.test;
|
|
||||||
match event.event {
|
|
||||||
mangui::events::InnerEvent::MouseDown(_) => {
|
|
||||||
**test.lock().unwrap() = true;
|
|
||||||
},
|
|
||||||
mangui::events::InnerEvent::MouseUp(_) => {
|
|
||||||
**test.lock().unwrap() = false;
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
this
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set(&mut self, _attrs: Self::PartialComponentAttrs) { }
|
|
||||||
fn get(&self) -> &Self::ComponentAttrs { &self.attrs }
|
|
||||||
fn mount(&self, parent: &SharedNode, before: Option<&SharedNode>) {
|
|
||||||
insert(parent, &{self.layout.clone()}, before);
|
|
||||||
self.rect.lock().unwrap().mount(&{self.layout.clone()}, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unmount(&self) {
|
|
||||||
self.rect.lock().unwrap().unmount();
|
|
||||||
detach(&{self.layout.clone()});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&self, _bitmap: &[u32]) {}
|
|
||||||
}
|
|
||||||
|
|
@ -3,6 +3,7 @@ use std::default::Default;
|
||||||
use mangui::{femtovg::{ImageFlags, Color, Paint}, cosmic_text::Metrics, nodes::{layout::Layout, Style}, nodes::text::Text, nodes::image::Image, taffy::prelude::Size};
|
use mangui::{femtovg::{ImageFlags, Color, Paint}, cosmic_text::Metrics, nodes::{layout::Layout, Style}, nodes::text::Text, nodes::image::Image, taffy::prelude::Size};
|
||||||
use mangui::nodes::TaffyStyle;
|
use mangui::nodes::TaffyStyle;
|
||||||
use mangui::taffy::Display::Block;
|
use mangui::taffy::Display::Block;
|
||||||
|
use mangui::taffy::{FlexDirection, LengthPercentage, Rect};
|
||||||
|
|
||||||
use rusalka::nodes::primitives::{Rectangle, RectangleAttributes, PartialRectangleAttributes};
|
use rusalka::nodes::primitives::{Rectangle, RectangleAttributes, PartialRectangleAttributes};
|
||||||
|
|
||||||
|
|
@ -27,10 +28,27 @@ make_component!(
|
||||||
Component {
|
Component {
|
||||||
@layout {
|
@layout {
|
||||||
@Rectangle {
|
@Rectangle {
|
||||||
radius: if $test_ { attrs.radius } else { 0. },
|
radius: if $test_ { attrs.radius } else { 0. }
|
||||||
..Default::default()
|
|
||||||
}
|
}
|
||||||
@layout {
|
@layout {
|
||||||
|
@text {
|
||||||
|
text: String::from("Hello, World 🌎! And there's more text in here, as a single line"),
|
||||||
|
metrics: Metrics::new(20., 25.),
|
||||||
|
paint: Paint::color(Color::rgb(0, 255, 0)),
|
||||||
|
style: Style {
|
||||||
|
layout: TaffyStyle {
|
||||||
|
padding: Rect {
|
||||||
|
top: LengthPercentage::Length(10.),
|
||||||
|
left: LengthPercentage::Length(10.),
|
||||||
|
right: LengthPercentage::Length(10.),
|
||||||
|
bottom: LengthPercentage::Length(10.)
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
@image {
|
@image {
|
||||||
style: Style {
|
style: Style {
|
||||||
layout: TaffyStyle {
|
layout: TaffyStyle {
|
||||||
|
|
@ -46,16 +64,11 @@ make_component!(
|
||||||
radius: 5.,
|
radius: 5.,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
@text {
|
|
||||||
text: String::from("Hello, World!"),
|
|
||||||
metrics: Metrics::new(20., 25.),
|
|
||||||
paint: Paint::color(Color::rgb(0, 255, 0)),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
style: Style {
|
style: Style {
|
||||||
layout: TaffyStyle {
|
layout: TaffyStyle {
|
||||||
display: Block,
|
display: Block,
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
use std::sync::{RwLock, Arc, mpsc, Mutex};
|
use std::sync::{RwLock, Arc, mpsc, Mutex};
|
||||||
|
|
||||||
use mangui::{self, nodes::{layout::Layout, self, Style, TaffyStyle}, taffy::{self, prelude::Size, style::Dimension}, femtovg::{Paint, Color}, SharedNode, MainEntry, events::NodeEvent};
|
use mangui::{self, nodes::layout::Layout, SharedNode, MainEntry};
|
||||||
|
|
||||||
mod component_demo;
|
|
||||||
mod component_demo_syntax;
|
mod component_demo_syntax;
|
||||||
mod anilist;
|
mod anilist;
|
||||||
|
|
||||||
|
|
@ -11,38 +10,7 @@ use rusalka::component::Component;
|
||||||
fn main() {
|
fn main() {
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
let _tx = Arc::new(tx);
|
let _tx = Arc::new(tx);
|
||||||
let mut root = Layout::default();
|
let root = Layout::default();
|
||||||
root.style.layout.display = taffy::style::Display::Flex;
|
|
||||||
root.style.layout.flex_direction = taffy::style::FlexDirection::Row;
|
|
||||||
let right_node = Arc::new(RwLock::new(nodes::primitives::Rectangle {
|
|
||||||
style: Style {
|
|
||||||
layout: TaffyStyle {
|
|
||||||
min_size: Size {
|
|
||||||
width: Dimension::Length(50.),
|
|
||||||
height: Dimension::Length(100.)
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
cursor: Default::default()
|
|
||||||
},
|
|
||||||
fill: Paint::color(Color::rgb(0, 0, 255)),
|
|
||||||
radius: 0.,
|
|
||||||
events: Default::default(),
|
|
||||||
parent: None
|
|
||||||
}));
|
|
||||||
root.children.push(right_node.clone());
|
|
||||||
right_node.clone().write().unwrap().events.add_handler(Box::new(move |event| {
|
|
||||||
let NodeEvent { target, path, event } = event;
|
|
||||||
match event {
|
|
||||||
mangui::events::InnerEvent::MouseDown(_) => {
|
|
||||||
right_node.write().unwrap().fill = Paint::color(Color::rgb(255, 0, 255));
|
|
||||||
},
|
|
||||||
mangui::events::InnerEvent::MouseUp(_) => {
|
|
||||||
right_node.write().unwrap().fill = Paint::color(Color::rgb(0, 0, 255));
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
let groot: SharedNode = Arc::new(RwLock::new(root));
|
let groot: SharedNode = Arc::new(RwLock::new(root));
|
||||||
|
|
||||||
let cdemo: Arc<Mutex<component_demo_syntax::ComponentDemo>> = Arc::new_cyclic(|cself|
|
let cdemo: Arc<Mutex<component_demo_syntax::ComponentDemo>> = Arc::new_cyclic(|cself|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ use std::collections::HashMap;
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::{Arc, Mutex, RwLock, Weak};
|
use std::sync::{Arc, Mutex, RwLock, Weak};
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use cosmic_text::FontSystem;
|
use cosmic_text::FontSystem;
|
||||||
use events::{Location, MouseValue, NodeEvent, MouseEvent};
|
use events::{Location, MouseValue, NodeEvent, MouseEvent};
|
||||||
|
|
@ -14,7 +13,7 @@ use glutin_winit::DisplayBuilder;
|
||||||
use nodes::{get_element_at, run_event_handlers, run_single_event_handlers};
|
use nodes::{get_element_at, run_event_handlers, run_single_event_handlers};
|
||||||
use raw_window_handle::HasRawWindowHandle;
|
use raw_window_handle::HasRawWindowHandle;
|
||||||
use winit::event::{Event, WindowEvent, Modifiers, DeviceId};
|
use winit::event::{Event, WindowEvent, Modifiers, DeviceId};
|
||||||
use winit::event_loop::{ControlFlow, EventLoop};
|
use winit::event_loop::EventLoop;
|
||||||
use winit::window::WindowBuilder;
|
use winit::window::WindowBuilder;
|
||||||
use winit::{dpi::PhysicalSize, window::Window};
|
use winit::{dpi::PhysicalSize, window::Window};
|
||||||
|
|
||||||
|
|
@ -79,8 +78,8 @@ pub fn run_event_loop(entry: MainEntry) -> () {
|
||||||
let mut taffy = TaffyTree::new();
|
let mut taffy = TaffyTree::new();
|
||||||
let mut taffy_map = NodeLayoutMap::new();
|
let mut taffy_map = NodeLayoutMap::new();
|
||||||
{
|
{
|
||||||
let clonned = entry.root.clone();
|
let cloned = entry.root.clone();
|
||||||
let root = clonned.read().unwrap();
|
let root = cloned.read().unwrap();
|
||||||
let root_style = root.deref().style();
|
let root_style = root.deref().style();
|
||||||
let root_layout = root_style.layout.to_owned();
|
let root_layout = root_style.layout.to_owned();
|
||||||
let taffy_root_node = taffy.new_leaf(root_layout).unwrap();
|
let taffy_root_node = taffy.new_leaf(root_layout).unwrap();
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,7 @@ pub trait Node: Debug {
|
||||||
|
|
||||||
/// Render the node, called before rendering it's children
|
/// Render the node, called before rendering it's children
|
||||||
/// Canvas considers 0, 0 to be top left corner (for location after layouting happens)
|
/// Canvas considers 0, 0 to be top left corner (for location after layouting happens)
|
||||||
|
/// Top left corner is after margin and similar, but before padding and border.
|
||||||
fn render_pre_children(&mut self, _context: &mut RenderContext, _layout: Layout) {}
|
fn render_pre_children(&mut self, _context: &mut RenderContext, _layout: Layout) {}
|
||||||
/// Render the node, called after rendering it's children
|
/// Render the node, called after rendering it's children
|
||||||
/// Canvas considers 0, 0 to be top left corner (for location after layouting happens)
|
/// Canvas considers 0, 0 to be top left corner (for location after layouting happens)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use crate::{events::handler::EventHandlerDatabase, SharedNode, WeakNode, FONT_SYSTEM};
|
use crate::{events::handler::EventHandlerDatabase, SharedNode, WeakNode, FONT_SYSTEM};
|
||||||
use super::{text_render_cache::RENDER_CACHE, Node, NodeChildren, Style, MeasureContext, RenderContext};
|
use super::{text_render_cache::RENDER_CACHE, Node, NodeChildren, Style, MeasureContext, RenderContext};
|
||||||
use cosmic_text::{Attrs, Buffer, Metrics, Shaping};
|
use cosmic_text::{Attrs, Buffer, Family, Metrics, Shaping, Stretch};
|
||||||
use femtovg::{Color, Paint, Path};
|
use femtovg::{Color, Paint, Path};
|
||||||
use taffy::{AvailableSpace, Size};
|
use taffy::{AvailableSpace, Size};
|
||||||
|
use crate::nodes::text_render_cache::TextConfig;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Text {
|
pub struct Text {
|
||||||
|
|
@ -38,7 +39,12 @@ impl Node for Text {
|
||||||
// this can crash, but it should crash earlier during measure -> see the comment there.
|
// this can crash, but it should crash earlier during measure -> see the comment there.
|
||||||
let buf = self.buffer.as_mut().unwrap();
|
let buf = self.buffer.as_mut().unwrap();
|
||||||
let mut font = FONT_SYSTEM.lock().unwrap();
|
let mut font = FONT_SYSTEM.lock().unwrap();
|
||||||
buf.set_size(&mut font, layout.size.width, layout.size.height);
|
let offset_size = (
|
||||||
|
layout.padding.left + layout.padding.right + layout.border.left + layout.border.right,
|
||||||
|
layout.padding.top + layout.padding.bottom + layout.border.top + layout.border.bottom
|
||||||
|
);
|
||||||
|
// the height * scale factor is an ugly hack to fix height of the text... not sure why it's wrong in the first place
|
||||||
|
buf.set_size(&mut font, layout.content_size.width - offset_size.0, (layout.content_size.height * context.scale_factor) - offset_size.1);
|
||||||
buf.set_metrics(&mut font, self.metrics.scale(context.scale_factor));
|
buf.set_metrics(&mut font, self.metrics.scale(context.scale_factor));
|
||||||
// fill_to_cmds requires FONT_SYSTEM lock.
|
// fill_to_cmds requires FONT_SYSTEM lock.
|
||||||
drop(font);
|
drop(font);
|
||||||
|
|
@ -54,10 +60,26 @@ impl Node for Text {
|
||||||
&path,
|
&path,
|
||||||
&Paint::color(Color::rgb(255, 0, 0))
|
&Paint::color(Color::rgb(255, 0, 0))
|
||||||
);
|
);
|
||||||
|
let position = (
|
||||||
|
layout.padding.left + layout.border.left,
|
||||||
|
layout.padding.top + layout.border.top
|
||||||
|
);
|
||||||
|
let mut path = Path::new();
|
||||||
|
path.rounded_rect(
|
||||||
|
position.0,
|
||||||
|
position.1,
|
||||||
|
layout.content_size.width - offset_size.0,
|
||||||
|
layout.content_size.height - offset_size.1,
|
||||||
|
0.
|
||||||
|
);
|
||||||
|
context.canvas.fill_path(
|
||||||
|
&path,
|
||||||
|
&Paint::color(Color::rgb(0, 0, 255))
|
||||||
|
);
|
||||||
let cmds = RENDER_CACHE.lock().unwrap()
|
let cmds = RENDER_CACHE.lock().unwrap()
|
||||||
.fill_to_cmds(&mut context.canvas, buf, (0.0, 0.0), context.scale_factor)
|
.fill_to_cmds(&mut context.canvas, buf, position, context.scale_factor, TextConfig { hint: false, subpixel: false })
|
||||||
.unwrap();
|
.unwrap();
|
||||||
context.canvas.draw_glyph_commands(cmds, &self.paint, 1.0);
|
context.canvas.draw_glyph_commands(cmds, &self.paint, context.scale_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(&mut self, context: &mut MeasureContext, known_dimensions: Size<Option<f32>>, available_space: Size<AvailableSpace>) -> Size<f32> {
|
fn measure(&mut self, context: &mut MeasureContext, known_dimensions: Size<Option<f32>>, available_space: Size<AvailableSpace>) -> Size<f32> {
|
||||||
|
|
@ -74,7 +96,7 @@ impl Node for Text {
|
||||||
buf.set_metrics(&mut font, self.metrics.scale(context.scale_factor));
|
buf.set_metrics(&mut font, self.metrics.scale(context.scale_factor));
|
||||||
|
|
||||||
// Compute layout
|
// Compute layout
|
||||||
buf.shape_until_scroll(&mut font, false);
|
buf.shape_until_scroll(&mut font, true);
|
||||||
drop(font);
|
drop(font);
|
||||||
|
|
||||||
// Determine measured size of text
|
// Determine measured size of text
|
||||||
|
|
@ -82,7 +104,7 @@ impl Node for Text {
|
||||||
.layout_runs()
|
.layout_runs()
|
||||||
.fold((0.0, 0usize), |(width, total_lines), run| (run.line_w.max(width), total_lines + 1));
|
.fold((0.0, 0usize), |(width, total_lines), run| (run.line_w.max(width), total_lines + 1));
|
||||||
// fixes text not rendering in some cases (??????)
|
// fixes text not rendering in some cases (??????)
|
||||||
let height = total_lines as f32 * buf.metrics().line_height + 1.0;
|
let height = (total_lines as f32 * buf.metrics().line_height + 1.0) / context.scale_factor;
|
||||||
// fixes flickering of text on devices with non-integer scale factors due to loss of precision
|
// fixes flickering of text on devices with non-integer scale factors due to loss of precision
|
||||||
let width = width + 0.5;
|
let width = width + 0.5;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,12 @@ pub struct FontTexture {
|
||||||
image_id: ImageId
|
image_id: ImageId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, Copy)]
|
||||||
|
pub struct TextConfig {
|
||||||
|
pub hint: bool,
|
||||||
|
pub subpixel: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct RenderedGlyph {
|
pub struct RenderedGlyph {
|
||||||
texture_index: usize,
|
texture_index: usize,
|
||||||
|
|
@ -57,25 +63,19 @@ impl RenderCache {
|
||||||
buffer: &Buffer,
|
buffer: &Buffer,
|
||||||
position: (f32, f32),
|
position: (f32, f32),
|
||||||
scale: f32,
|
scale: f32,
|
||||||
|
config: TextConfig
|
||||||
) -> Result<GlyphDrawCommands, ErrorKind> {
|
) -> Result<GlyphDrawCommands, ErrorKind> {
|
||||||
let mut alpha_cmd_map = HashMap::new();
|
let mut alpha_cmd_map = HashMap::new();
|
||||||
let mut color_cmd_map = HashMap::new();
|
let mut color_cmd_map = HashMap::new();
|
||||||
|
|
||||||
//let total_height = buffer.layout_runs().len() as i32 * buffer.metrics().line_height;
|
let lines = buffer.layout_runs().filter(|run| run.line_w != 0.0).count();
|
||||||
|
let total_height = lines as f32 * buffer.metrics().line_height;
|
||||||
for run in buffer.layout_runs() {
|
for run in buffer.layout_runs() {
|
||||||
for glyph in run.glyphs.iter() {
|
for glyph in run.glyphs.iter() {
|
||||||
let physical = glyph.physical(position, scale);
|
let physical_glyph = glyph.physical(position, scale);
|
||||||
let mut cache_key = physical.cache_key;
|
let mut cache_key = physical_glyph.cache_key;
|
||||||
let position_x = position.0 + cache_key.x_bin.as_float();
|
|
||||||
let position_y = position.1 + cache_key.y_bin.as_float();
|
|
||||||
//let position_x = position_x - run.line_w * justify.0;
|
|
||||||
//let position_y = position_y - total_height as f32 * justify.1;
|
|
||||||
let (position_x, subpixel_x) = SubpixelBin::new(position_x);
|
|
||||||
let (position_y, subpixel_y) = SubpixelBin::new(position_y);
|
|
||||||
cache_key.x_bin = subpixel_x;
|
|
||||||
cache_key.y_bin = subpixel_y;
|
|
||||||
// perform cache lookup for rendered glyph
|
// perform cache lookup for rendered glyph
|
||||||
if let Some(rendered) = self.rendered_glyphs.entry(cache_key).or_insert_with(|| {
|
let Some(rendered) = self.rendered_glyphs.entry(cache_key).or_insert_with(|| {
|
||||||
// ...or insert it
|
// ...or insert it
|
||||||
|
|
||||||
// do the actual rasterization
|
// do the actual rasterization
|
||||||
|
|
@ -86,7 +86,7 @@ impl RenderCache {
|
||||||
.scale_context
|
.scale_context
|
||||||
.builder(font.as_swash())
|
.builder(font.as_swash())
|
||||||
.size(f32::from_bits(cache_key.font_size_bits))
|
.size(f32::from_bits(cache_key.font_size_bits))
|
||||||
.hint(true)
|
.hint(config.hint)
|
||||||
.build();
|
.build();
|
||||||
let offset = Vector::new(cache_key.x_bin.as_float(), cache_key.y_bin.as_float());
|
let offset = Vector::new(cache_key.x_bin.as_float(), cache_key.y_bin.as_float());
|
||||||
let rendered = Render::new(&[
|
let rendered = Render::new(&[
|
||||||
|
|
@ -94,7 +94,7 @@ impl RenderCache {
|
||||||
Source::ColorBitmap(StrikeWith::BestFit),
|
Source::ColorBitmap(StrikeWith::BestFit),
|
||||||
Source::Outline,
|
Source::Outline,
|
||||||
])
|
])
|
||||||
.format(Format::Alpha)
|
.format(if config.subpixel { Format::Subpixel } else { Format::Alpha })
|
||||||
.offset(offset)
|
.offset(offset)
|
||||||
.render(&mut scaler, cache_key.glyph_id);
|
.render(&mut scaler, cache_key.glyph_id);
|
||||||
|
|
||||||
|
|
@ -114,26 +114,32 @@ impl RenderCache {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (texture_index, atlas_alloc_x, atlas_alloc_y) = found.unwrap_or_else(|| {
|
|
||||||
// if no atlas could fit the texture, make a new atlas tyvm
|
let (texture_index, atlas_alloc_x, atlas_alloc_y) =
|
||||||
// TODO error handling
|
found.unwrap_or_else(|| {
|
||||||
let mut atlas = Atlas::new(TEXTURE_SIZE, TEXTURE_SIZE);
|
// if no atlas could fit the texture, make a new atlas tyvm
|
||||||
let image_id = canvas
|
// TODO error handling
|
||||||
.create_image(
|
let mut atlas = Atlas::new(TEXTURE_SIZE, TEXTURE_SIZE);
|
||||||
Img::new(
|
let image_id = canvas
|
||||||
vec![RGBA8::new(0, 0, 0, 0); TEXTURE_SIZE * TEXTURE_SIZE],
|
.create_image(
|
||||||
TEXTURE_SIZE,
|
Img::new(
|
||||||
TEXTURE_SIZE,
|
vec![
|
||||||
|
RGBA8::new(0, 0, 0, 0);
|
||||||
|
TEXTURE_SIZE * TEXTURE_SIZE
|
||||||
|
],
|
||||||
|
TEXTURE_SIZE,
|
||||||
|
TEXTURE_SIZE,
|
||||||
|
)
|
||||||
|
.as_ref(),
|
||||||
|
ImageFlags::empty(),
|
||||||
)
|
)
|
||||||
.as_ref(),
|
.unwrap();
|
||||||
ImageFlags::empty(),
|
let texture_index = self.glyph_textures.len();
|
||||||
)
|
let (x, y) =
|
||||||
.unwrap();
|
atlas.add_rect(alloc_w as usize, alloc_h as usize).unwrap();
|
||||||
let texture_index = self.glyph_textures.len();
|
self.glyph_textures.push(FontTexture { atlas, image_id });
|
||||||
let (x, y) = atlas.add_rect(alloc_w as usize, alloc_h as usize).unwrap();
|
(texture_index, x, y)
|
||||||
self.glyph_textures.push(FontTexture { atlas, image_id });
|
});
|
||||||
(texture_index, x, y)
|
|
||||||
});
|
|
||||||
|
|
||||||
let atlas_used_x = atlas_alloc_x as u32 + GLYPH_MARGIN;
|
let atlas_used_x = atlas_alloc_x as u32 + GLYPH_MARGIN;
|
||||||
let atlas_used_y = atlas_alloc_y as u32 + GLYPH_MARGIN;
|
let atlas_used_y = atlas_alloc_y as u32 + GLYPH_MARGIN;
|
||||||
|
|
@ -174,33 +180,32 @@ impl RenderCache {
|
||||||
color_glyph: matches!(rendered.content, Content::Color),
|
color_glyph: matches!(rendered.content, Content::Color),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}) {
|
}) else { continue };
|
||||||
let cmd_map = if rendered.color_glyph {
|
|
||||||
&mut color_cmd_map
|
|
||||||
} else {
|
|
||||||
&mut alpha_cmd_map
|
|
||||||
};
|
|
||||||
|
|
||||||
let cmd = cmd_map.entry(rendered.texture_index).or_insert_with(|| DrawCommand {
|
let cmd_map = if rendered.color_glyph {
|
||||||
image_id: self.glyph_textures[rendered.texture_index].image_id,
|
&mut color_cmd_map
|
||||||
quads: Vec::new(),
|
} else {
|
||||||
});
|
&mut alpha_cmd_map
|
||||||
|
};
|
||||||
|
|
||||||
let mut q = Quad::default();
|
let cmd = cmd_map.entry(rendered.texture_index).or_insert_with(|| DrawCommand {
|
||||||
let it = 1.0 / TEXTURE_SIZE as f32;
|
image_id: self.glyph_textures[rendered.texture_index].image_id,
|
||||||
|
quads: Vec::new(),
|
||||||
|
});
|
||||||
|
|
||||||
q.x0 = (position_x + glyph.x as i32 + rendered.offset_x - GLYPH_PADDING as i32) as f32;
|
let mut q = Quad::default();
|
||||||
q.y0 = (position_y + run.line_y as i32 + glyph.y as i32 - rendered.offset_y - GLYPH_PADDING as i32) as f32;
|
let it = 1.0 / TEXTURE_SIZE as f32;
|
||||||
q.x1 = q.x0 + rendered.width as f32;
|
q.x0 = (physical_glyph.x + rendered.offset_x - GLYPH_PADDING as i32) as f32;
|
||||||
q.y1 = q.y0 + rendered.height as f32;
|
q.y0 = (physical_glyph.y - rendered.offset_y - GLYPH_PADDING as i32) as f32 + run.line_y;
|
||||||
|
q.x1 = q.x0 + rendered.width as f32;
|
||||||
|
q.y1 = q.y0 + rendered.height as f32;
|
||||||
|
|
||||||
q.s0 = rendered.atlas_x as f32 * it;
|
q.s0 = rendered.atlas_x as f32 * it;
|
||||||
q.t0 = rendered.atlas_y as f32 * it;
|
q.t0 = rendered.atlas_y as f32 * it;
|
||||||
q.s1 = (rendered.atlas_x + rendered.width) as f32 * it;
|
q.s1 = (rendered.atlas_x + rendered.width) as f32 * it;
|
||||||
q.t1 = (rendered.atlas_y + rendered.height) as f32 * it;
|
q.t1 = (rendered.atlas_y + rendered.height) as f32 * it;
|
||||||
|
|
||||||
cmd.quads.push(q);
|
cmd.quads.push(q);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue