Last active
March 19, 2021 21:01
-
-
Save CryZe/d84854aef6adf13bd212079f28f01b08 to your computer and use it in GitHub Desktop.
fontemon.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] | |
| use std::{ | |
| io::Cursor, | |
| sync::{Arc, RwLock}, | |
| time::{Duration, Instant}, | |
| }; | |
| use minifb::{Key, KeyRepeat, ScaleMode, Window, WindowOptions}; | |
| use rustybuzz::UnicodeBuffer; | |
| use tiny_skia::{Color, FillRule, Paint, PathBuilder, Pixmap, Shader, Transform}; | |
| use ttf_parser::{GlyphId, OutlineBuilder}; | |
| const FONT: &[u8] = include_bytes!("../fontemon_small.otf"); | |
| const WIDTH: u32 = 500; | |
| const HEIGHT: u32 = 500; | |
| const FONT_SCALE: f32 = HEIGHT as f32 / 2500.0; | |
| const CHOICE_FRAMES: [u32; 55] = [ | |
| 269, 527, 554, 649, 677, 883, 913, 1026, 1114, 1207, 1400, 1406, 1457, 1463, 1532, 1538, 1689, | |
| 1720, 1752, 1753, 1754, 1755, 1929, 1945, 1986, 2132, 2168, 2327, 2328, 2329, 2330, 2423, 2463, | |
| 2580, 3003, 3045, 3193, 3236, 3409, 3452, 3601, 3637, 4703, // | |
| // Also game overs | |
| 370, 738, 1090, 1178, 1219, 4150, 4162, 4235, 4308, // | |
| // Also cycle frames | |
| 4777, // First secret | |
| 2722, // Credits | |
| // Also title screen | |
| 180, | |
| ]; | |
| struct SkiaBuilder(PathBuilder); | |
| impl OutlineBuilder for SkiaBuilder { | |
| fn move_to(&mut self, x: f32, y: f32) { | |
| self.0.move_to(x, y) | |
| } | |
| fn line_to(&mut self, x: f32, y: f32) { | |
| self.0.line_to(x, y) | |
| } | |
| fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) { | |
| self.0.quad_to(x1, y1, x, y) | |
| } | |
| fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) { | |
| self.0.cubic_to(x1, y1, x2, y2, x, y) | |
| } | |
| fn close(&mut self) { | |
| self.0.close() | |
| } | |
| } | |
| fn main() { | |
| let font = ttf_parser::Face::from_slice(FONT, 0).unwrap(); | |
| let rb_font = rustybuzz::Face::from_slice(FONT, 0).unwrap(); | |
| let mut fb = Pixmap::new(WIDTH, HEIGHT).unwrap(); | |
| let mut text = UnicodeBuffer::new(); | |
| let mut window = Window::new( | |
| "Fontemon", | |
| WIDTH as _, | |
| HEIGHT as _, | |
| WindowOptions { | |
| resize: true, | |
| scale_mode: ScaleMode::AspectRatioStretch, | |
| ..Default::default() | |
| }, | |
| ) | |
| .unwrap(); | |
| window.limit_update_rate(Some(Duration::from_secs(1) / 60)); | |
| window.set_key_repeat_delay(0.1); | |
| window.set_key_repeat_rate(0.25); | |
| let mut input = String::new(); | |
| let paint = Paint { | |
| shader: Shader::SolidColor(Color::from_rgba8(15, 56, 15, 255)), | |
| anti_alias: true, | |
| ..Default::default() | |
| }; | |
| let transform = Transform::from_scale(FONT_SCALE, -FONT_SCALE) | |
| .post_translate(HEIGHT as f32 / 250.0, 0.725 * HEIGHT as f32); | |
| let mut first_frame = true; | |
| let mut last_input = Instant::now(); | |
| let mut frame_id = 0; | |
| while window.is_open() { | |
| let mut pushed_any = first_frame; | |
| first_frame = false; | |
| for key in window.get_keys_pressed(KeyRepeat::Yes).iter().flatten() { | |
| let ch = match key { | |
| Key::A => 'a', | |
| Key::B => 'b', | |
| Key::C => 'c', | |
| Key::D => 'd', | |
| Key::Space => ' ', | |
| Key::Backspace => { | |
| pushed_any = true; | |
| input.pop(); | |
| continue; | |
| } | |
| Key::Escape => { | |
| pushed_any = true; | |
| input.clear(); | |
| input.push_str(" "); | |
| continue; | |
| } | |
| _ => continue, | |
| }; | |
| pushed_any = true; | |
| input.push(ch); | |
| } | |
| if !pushed_any | |
| && last_input.elapsed() > Duration::from_secs(1) / 2 | |
| && !CHOICE_FRAMES.contains(&frame_id) | |
| { | |
| pushed_any = true; | |
| input.push(' '); | |
| } | |
| if !pushed_any { | |
| window.update(); | |
| continue; | |
| } | |
| last_input = Instant::now(); | |
| text.push_str(&input); | |
| let glyphs = rustybuzz::shape(&rb_font, &[], text); | |
| fb.fill(Color::from_rgba8(15, 188, 155, 255)); | |
| for glyph in glyphs.glyph_infos() { | |
| if glyph.codepoint == 34 { | |
| continue; | |
| } | |
| frame_id = glyph.codepoint; | |
| let mut builder = SkiaBuilder(PathBuilder::new()); | |
| if font | |
| .outline_glyph(GlyphId(frame_id as _), &mut builder) | |
| .is_none() | |
| { | |
| continue; | |
| } | |
| if let Some(path) = builder.0.finish() { | |
| fb.fill_path(&path, &paint, FillRule::Winding, transform, None); | |
| } | |
| } | |
| text = glyphs.clear(); | |
| window | |
| .update_with_buffer(bytemuck::cast_slice(fb.data()), WIDTH as _, HEIGHT as _) | |
| .unwrap(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment