diff --git a/crates/epaint/src/text/font.rs b/crates/epaint/src/text/font.rs index dd095c443..c8504b159 100644 --- a/crates/epaint/src/text/font.rs +++ b/crates/epaint/src/text/font.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use emath::{GuiRounding as _, Vec2, vec2}; use crate::{ - TextureAtlas, + ColorImage, TextureAtlas, mutex::{Mutex, RwLock}, text::FontTweak, }; @@ -261,6 +261,49 @@ impl FontImpl { self.ascent } + pub fn allocate_custom_glyph(&self, c: char, image: ColorImage) -> GlyphInfo { + let glyph_pos = { + let atlas = &mut self.atlas.lock(); + let (glyph_pos, atlas_image) = atlas.allocate((image.width(), image.height())); + + for x in 0..image.width() { + for y in 0..image.height() { + let px = glyph_pos.0 + x; + let py = glyph_pos.1 + y; + atlas_image[(px, py)] = image[(x, y)]; + } + } + + glyph_pos + }; + + let glyph_width = image.width(); + let glyph_height = image.height(); + + let offset = vec2(0.0, -self.height_in_points / 1.3); + + let height = self.height_in_points; + let width = height * (glyph_width as f32 / glyph_height as f32); + + let uv_rect = UvRect { + offset, + size: vec2(width, height), + min: [glyph_pos.0 as u16, glyph_pos.1 as u16], + max: [ + (glyph_pos.0 + glyph_width) as u16, + (glyph_pos.1 + glyph_height) as u16, + ], + }; + + let advance_width = width; + + GlyphInfo { + id: ab_glyph::GlyphId(0), + advance_width: advance_width as f32, + uv_rect, + } + } + fn allocate_glyph(&self, glyph_id: ab_glyph::GlyphId) -> GlyphInfo { assert!(glyph_id.0 != 0, "Can't allocate glyph for id 0"); use ab_glyph::{Font as _, ScaleFont as _}; @@ -386,6 +429,16 @@ impl Font { } } + pub fn allocate_custom_glyph(&mut self, c: char, image: ColorImage) -> GlyphInfo { + if let Some(font_impl) = self.fonts.first() { + let glyph_info = font_impl.allocate_custom_glyph(c, image); + self.glyph_info_cache.insert(c, (0, glyph_info)); + glyph_info + } else { + GlyphInfo::default() + } + } + pub fn preload_common_characters(&mut self) { // Preload the printable ASCII characters [32, 126] (which excludes control codes): const FIRST_ASCII: usize = 32; // 32 == space diff --git a/examples/hello_world/src/main.rs b/examples/hello_world/src/main.rs index 6b85198a4..9cb5ab712 100644 --- a/examples/hello_world/src/main.rs +++ b/examples/hello_world/src/main.rs @@ -2,6 +2,10 @@ #![allow(rustdoc::missing_crate_level_docs)] // it's an example use eframe::egui; +use eframe::egui::{ + Color32, ColorImage, FontFamily, FontId, FontSelection, RichText, TextEdit, + global_theme_preference_switch, include_image, +}; fn main() -> eframe::Result { env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`). @@ -26,10 +30,14 @@ struct MyApp { age: u32, } +fn font_id() -> FontId { + FontId::new(30.0, FontFamily::Proportional) +} + impl Default for MyApp { fn default() -> Self { Self { - name: "Arthur".to_owned(), + name: "Ferris :crab:".to_owned(), age: 42, } } @@ -38,21 +46,28 @@ impl Default for MyApp { impl eframe::App for MyApp { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| { - ui.heading("My egui Application"); - ui.horizontal(|ui| { - let name_label = ui.label("Your name: "); - ui.text_edit_singleline(&mut self.name) - .labelled_by(name_label.id); - }); - ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age")); - if ui.button("Increment").clicked() { - self.age += 1; - } - ui.label(format!("Hello '{}', age {}", self.name, self.age)); + global_theme_preference_switch(ui); - ui.image(egui::include_image!( - "../../../crates/egui/assets/ferris.png" - )); + ctx.fonts(|f| { + let mut fonts = f.lock(); + let font = fonts.fonts.font(&font_id()); + if !font.has_glyph('🦀') { + let image = include_bytes!("../../../crates/egui/assets/ferris.png"); + + let image = egui_extras::image::load_image_bytes(image).unwrap(); + + font.allocate_custom_glyph('🦀', image); + } + }); + + TextEdit::singleline(&mut self.name) + .font(FontSelection::FontId(font_id())) + .text_color(Color32::WHITE) + .show(ui); + + self.name = self.name.replace(":crab:", "🦀"); + + ui.label(RichText::new(&self.name).font(font_id()).strong()); }); } }