| 1 | use nox_gfx::canvas::{Canvas, Paint}; |
| 2 | use nox_gfx::color::{hex, rgba, Color}; |
| 3 | use nox_gfx::geom::{pt, Rect}; |
| 4 | use nox_text::{draw_text, measure, Font, GlyphCache, TextStyle}; |
| 5 | |
| 6 | const BG: Color = hex(0x0e0e16); |
| 7 | const FG: Color = hex(0xe8e8f2); |
| 8 | const DIM: Color = hex(0x8a8aa5); |
| 9 | const ACCENT: Color = hex(0x7c5cff); |
| 10 | const CYAN: Color = hex(0x35d0ff); |
| 11 | |
| 12 | const SANS: &str = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"; |
| 13 | const SANS_BOLD: &str = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"; |
| 14 | const SERIF: &str = "/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf"; |
| 15 | const MONO: &str = "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf"; |
| 16 | const LIB: &str = "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf"; |
| 17 | |
| 18 | fn main() { |
| 19 | let (w, h) = (1180usize, 1000usize); |
| 20 | let mut c = Canvas::new(w, h); |
| 21 | c.fill( |
| 22 | &{ |
| 23 | let mut p = nox_gfx::path::Path::new(); |
| 24 | p.rect(c.full()); |
| 25 | p |
| 26 | }, |
| 27 | &nox_gfx::geom::IDENTITY, |
| 28 | &Paint::vgrad(c.full(), hex(0x14141f), BG), |
| 29 | ); |
| 30 | |
| 31 | let sans_b = std::fs::read(SANS).unwrap(); |
| 32 | let bold_b = std::fs::read(SANS_BOLD).unwrap(); |
| 33 | let serif_b = std::fs::read(SERIF).unwrap(); |
| 34 | let mono_b = std::fs::read(MONO).unwrap(); |
| 35 | let lib_b = std::fs::read(LIB).unwrap(); |
| 36 | let sans = Font::parse(&sans_b).unwrap(); |
| 37 | let bold = Font::parse(&bold_b).unwrap(); |
| 38 | let serif = Font::parse(&serif_b).unwrap(); |
| 39 | let mono = Font::parse(&mono_b).unwrap(); |
| 40 | let lib = Font::parse(&lib_b).unwrap(); |
| 41 | let mut cache = GlyphCache::new(); |
| 42 | cache.set_gamma(0.85); |
| 43 | |
| 44 | let mut y = 62.0; |
| 45 | draw_text(&mut c, &mut cache, &bold, "Noxstrap", 60.0, y, TextStyle::new(46.0), FG); |
| 46 | let wdt = measure(&bold, "Noxstrap", TextStyle::new(46.0)); |
| 47 | draw_text( |
| 48 | &mut c, |
| 49 | &mut cache, |
| 50 | &sans, |
| 51 | "every glyph here was parsed and rasterised by this repo", |
| 52 | 60.0 + wdt + 16.0, |
| 53 | y, |
| 54 | TextStyle::new(14.0), |
| 55 | DIM, |
| 56 | ); |
| 57 | |
| 58 | y += 40.0; |
| 59 | c.fill_rect(Rect::new(60.0, y, 1120.0, y + 1.0), rgba(255, 255, 255, 26)); |
| 60 | |
| 61 | y += 40.0; |
| 62 | draw_text(&mut c, &mut cache, &bold, "SIZE LADDER", 60.0, y, TextStyle { px: 11.0, letter_spacing: 1.6, kerning: true }, CYAN); |
| 63 | y += 26.0; |
| 64 | for px in [8.0f32, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 16.0, 18.0, 21.0, 24.0, 30.0] { |
| 65 | draw_text(&mut c, &mut cache, &sans, &format!("{px:.0}"), 60.0, y, TextStyle::new(10.0), DIM); |
| 66 | draw_text( |
| 67 | &mut c, |
| 68 | &mut cache, |
| 69 | &sans, |
| 70 | "Handgloves Roblox 0123 — the quick brown fox", |
| 71 | 92.0, |
| 72 | y, |
| 73 | TextStyle::new(px), |
| 74 | FG, |
| 75 | ); |
| 76 | y += px * 1.42 + 5.0; |
| 77 | } |
| 78 | |
| 79 | y += 18.0; |
| 80 | draw_text(&mut c, &mut cache, &bold, "KERNING", 60.0, y, TextStyle { px: 11.0, letter_spacing: 1.6, kerning: true }, CYAN); |
| 81 | y += 28.0; |
| 82 | for (label, kern) in [("off", false), ("on", true)] { |
| 83 | draw_text(&mut c, &mut cache, &sans, label, 60.0, y, TextStyle::new(11.0), DIM); |
| 84 | draw_text( |
| 85 | &mut c, |
| 86 | &mut cache, |
| 87 | &sans, |
| 88 | "AV Wa To LT V. Yo P, ff fi Type", |
| 89 | 92.0, |
| 90 | y, |
| 91 | TextStyle { px: 26.0, letter_spacing: 0.0, kerning: kern }, |
| 92 | if kern { FG } else { DIM }, |
| 93 | ); |
| 94 | y += 36.0; |
| 95 | } |
| 96 | |
| 97 | y += 20.0; |
| 98 | draw_text(&mut c, &mut cache, &bold, "FACES", 60.0, y, TextStyle { px: 11.0, letter_spacing: 1.6, kerning: true }, CYAN); |
| 99 | y += 28.0; |
| 100 | for (name, f) in [ |
| 101 | ("DejaVu Sans", &sans), |
| 102 | ("DejaVu Sans Bold", &bold), |
| 103 | ("DejaVu Serif", &serif), |
| 104 | ("DejaVu Sans Mono", &mono), |
| 105 | ("Liberation Sans", &lib), |
| 106 | ] { |
| 107 | draw_text(&mut c, &mut cache, &sans, name, 60.0, y, TextStyle::new(11.0), DIM); |
| 108 | draw_text(&mut c, &mut cache, f, "Bootstrapper — Ærøskøbing, naïve café 42%", 240.0, y, TextStyle::new(17.0), FG); |
| 109 | y += 30.0; |
| 110 | } |
| 111 | |
| 112 | y += 16.0; |
| 113 | draw_text(&mut c, &mut cache, &bold, "COMPOSITES & COVERAGE", 60.0, y, TextStyle { px: 11.0, letter_spacing: 1.6, kerning: true }, CYAN); |
| 114 | y += 30.0; |
| 115 | draw_text(&mut c, &mut cache, &sans, "ÀÁÂÃÄÅ Çéèêë ñÑ öÖ üÜ ýÿ Ω→ ‹›«» ①②③ ★☆♠♥ ¼½¾ ≈≠≤≥", 60.0, y, TextStyle::new(22.0), FG); |
| 116 | |
| 117 | y += 46.0; |
| 118 | let panel = Rect::new(60.0, y, 1120.0, y + 92.0); |
| 119 | let mut p = nox_gfx::path::Path::new(); |
| 120 | p.rrect(panel, 12.0); |
| 121 | c.shadow(&p, &nox_gfx::geom::IDENTITY, 14.0, rgba(0, 0, 0, 150), pt(0.0, 6.0)); |
| 122 | c.fill(&p, &nox_gfx::geom::IDENTITY, &Paint::vgrad(panel, hex(0x1b1b28), hex(0x15151f))); |
| 123 | c.stroke(&p, &nox_gfx::geom::IDENTITY, &Paint::Solid(rgba(255, 255, 255, 20)), &nox_gfx::canvas::Stroke::new(1.0)); |
| 124 | draw_text(&mut c, &mut cache, &bold, "Installing Roblox", 84.0, y + 34.0, TextStyle::new(17.0), FG); |
| 125 | draw_text(&mut c, &mut cache, &mono, "version-a1b2c3d4e5f6 · 184.2 MB / 271.9 MB", 84.0, y + 58.0, TextStyle::new(12.5), DIM); |
| 126 | let track = Rect::new(84.0, y + 70.0, 1096.0, y + 76.0); |
| 127 | c.fill_rrect(track, 3.0, &Paint::Solid(rgba(255, 255, 255, 22))); |
| 128 | let fill = Rect::new(track.x0, track.y0, track.x0 + (track.x1 - track.x0) * 0.677, track.y1); |
| 129 | c.fill_rrect(fill, 3.0, &Paint::hgrad(fill, ACCENT, CYAN)); |
| 130 | |
| 131 | let out = std::env::args().nth(1).unwrap_or_else(|| "specimen.png".into()); |
| 132 | std::fs::write(&out, c.to_png()).unwrap(); |
| 133 | println!( |
| 134 | "wrote {out} ({} glyphs cached, {} KB)", |
| 135 | cache.len(), |
| 136 | cache.bytes() / 1024 |
| 137 | ); |
| 138 | } |