diff --git a/Cargo.toml b/Cargo.toml index b8fe097..0122018 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,9 +14,10 @@ exclude = [".gitignore", ".github"] [dependencies] cgmath = "0.14.1" gl = "0.10.0" -image = "0.19.0" +image = "0.24.7" keyframe = "1.0.4" stretch = "0.3.2" +ab_glyph = "0.2.23" [dev-dependencies] glfw = "0.42.0" diff --git a/examples/font.rs b/examples/font.rs new file mode 100644 index 0000000..e121ee4 --- /dev/null +++ b/examples/font.rs @@ -0,0 +1,114 @@ +//! Draws text into `image_example.png`. +//! +//! Use a custom font file: `cargo run --example image /path/to/font.otf` +//! https://github.com/alexheretic/ab-glyph/blob/main/dev/examples/image.rs +use ab_glyph::{point, Point, Font, Glyph, FontRef, FontVec, PxScale, ScaleFont}; +use image::{DynamicImage, Rgba}; + +const TEXT: &str = "This is ab_glyph rendered into a png!"; + +fn main() { + if let Some(font_path) = std::env::args().nth(1) { + let font_path = std::env::current_dir().unwrap().join(font_path); + let data = std::fs::read(&font_path).unwrap(); + let font = FontVec::try_from_vec(data).unwrap_or_else(|_| { + panic!("error constructing a Font from data at {:?}", font_path); + }); + if let Some(name) = font_path.file_name().and_then(|n| n.to_str()) { + eprintln!("Using font: {name}"); + } + draw_image(font); + } else { + eprintln!("No font specified ... using OpenSans-Italic.ttf"); + let font = FontRef::try_from_slice(include_bytes!("../fonts/DejaVuSansMono.ttf")).unwrap(); + draw_image(font); + }; +} + +pub fn layout_paragraph( + font: SF, + position: Point, + max_width: f32, + text: &str, + target: &mut Vec, +) where + F: Font, + SF: ScaleFont, +{ + let v_advance = font.height() + font.line_gap(); + let mut caret = position + point(0.0, font.ascent()); + let mut last_glyph: Option = None; + for c in text.chars() { + if c.is_control() { + if c == '\n' { + caret = point(position.x, caret.y + v_advance); + last_glyph = None; + } + continue; + } + let mut glyph = font.scaled_glyph(c); + if let Some(previous) = last_glyph.take() { + caret.x += font.kern(previous.id, glyph.id); + } + glyph.position = caret; + + last_glyph = Some(glyph.clone()); + caret.x += font.h_advance(glyph.id); + + if !c.is_whitespace() && caret.x > position.x + max_width { + caret = Point{x:position.x, y: caret.y + v_advance}; + glyph.position = caret; + last_glyph = None; + } + + target.push(glyph); + } +} + +fn draw_image(font: F) { + // The font size to use + let scale = PxScale::from(45.0); + + let scaled_font = font.as_scaled(scale); + + let mut glyphs = Vec::new(); + layout_paragraph(scaled_font, point(20.0, 20.0), 9999.0, TEXT, &mut glyphs); + + // Use a dark red colour + let colour = (255, 255, 255); + + // work out the layout size + let glyphs_height = scaled_font.height().ceil() as u32; + let glyphs_width = { + let min_x = glyphs.first().unwrap().position.x; + let last_glyph = glyphs.last().unwrap(); + let max_x = last_glyph.position.x + scaled_font.h_advance(last_glyph.id); + (max_x - min_x).ceil() as u32 + }; + + // Create a new rgba image with some padding + let mut image = DynamicImage::new_rgba8(glyphs_width + 40, glyphs_height + 40).to_rgba8(); + + // Loop through the glyphs in the text, positing each one on a line + for glyph in glyphs { + if let Some(outlined) = scaled_font.outline_glyph(glyph) { + let bounds = outlined.px_bounds(); + // Draw the glyph into the image per-pixel by using the draw closure + outlined.draw(|x, y, v| { + // Offset the position by the glyph bounding box + let px = image.get_pixel_mut(x + bounds.min.x as u32, y + bounds.min.y as u32); + // Turn the coverage into an alpha value (blended with any previous) + *px = Rgba([ + colour.0, + colour.1, + colour.2, + px.0[3].saturating_add((v * 255.0) as u8), + ]); + }); + } + } + + // Save the image to a png file + image.save("image_example.png").unwrap(); + println!("Generated: image_example.png"); +} \ No newline at end of file diff --git a/fonts/DejaVuSans.ttf b/fonts/DejaVuSans.ttf new file mode 100644 index 0000000..2fbbe69 Binary files /dev/null and b/fonts/DejaVuSans.ttf differ diff --git a/fonts/DejaVuSansMono.ttf b/fonts/DejaVuSansMono.ttf new file mode 100644 index 0000000..041cffc Binary files /dev/null and b/fonts/DejaVuSansMono.ttf differ diff --git a/src/actor.rs b/src/actor.rs index 0144600..9dc50a7 100644 --- a/src/actor.rs +++ b/src/actor.rs @@ -301,7 +301,7 @@ impl Actor { match image::open(&Path::new(&self.image_path)) { Ok(img) => { - let to_rgba = img.to_rgba(); + let to_rgba = img.to_rgba8(); let data = to_rgba.into_vec(); gl::TexImage2D( gl::TEXTURE_2D,