diff --git a/Cargo.lock b/Cargo.lock index f2cf769..0b4a944 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,14 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + [[package]] name = "ansi_term" version = "0.11.0" @@ -263,6 +272,12 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + [[package]] name = "num" version = "0.1.42" @@ -547,6 +562,23 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "sdl2" version = "0.32.2" @@ -709,6 +741,7 @@ dependencies = [ "itertools", "rand 0.8.4", "rand_xoshiro", + "regex", "sdl2", "structopt", ] diff --git a/Cargo.toml b/Cargo.toml index 4d4b7a5..ccc9a24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,3 +19,4 @@ structopt = "0.3" itertools = "0.10" rand = "0.8" rand_xoshiro = "0.6" +regex = "1.5" diff --git a/src/gui.rs b/src/gui.rs new file mode 100644 index 0000000..221a9e4 --- /dev/null +++ b/src/gui.rs @@ -0,0 +1,215 @@ +use super::Result; + +use std::fs::File; +use std::io::Read; +use std::collections::HashMap; + +use sdl2::pixels::{Color, PixelFormatEnum}; +use sdl2::surface::{Surface, SurfaceRef}; +use sdl2::image::ImageRWops; +use sdl2::rect::{Rect, Point}; + +use regex::Regex; + +pub const BG_COLOR: Color = Color { r: 65, g: 44, b: 130, a: 255 }; +pub const LIFONT_PNG: &'static [u8] = include_bytes!("lifont.png"); +pub const MOUSE_PNG: &'static [u8] = include_bytes!("zmouse.png"); +pub const MOUSE_SHADOW_PNG: &'static [u8] = include_bytes!("zmouse-shadow.png"); + +const FONT_ROWS: usize = 16; +const FONT_COLS: usize = 16; +const FONT_MAX_W: usize = 8; +const FONT_MAX_H: usize = 8; + +pub struct SurfaceFont<'a> { + char_rects: HashMap, + pub surf: Surface<'a>, + line_height: u32, +} + +impl<'a> SurfaceFont<'a> { + pub fn load_lifont() -> Result> { + let surf = surface_asset(LIFONT_PNG)?; + let surf_rect = surf.rect(); + let canvas = surf.into_canvas()?; + + let mut char_rects = HashMap::new(); + let mut src_rect = Rect::new(0, 0, 8, 8); + for name in include_str!("lifont.txt").lines() { + let pixel_bytes = canvas.read_pixels(src_rect, PixelFormatEnum::ARGB1555)?; + let pixel_shorts = unsafe { std::slice::from_raw_parts( + pixel_bytes.as_ptr() as *const u16, + pixel_bytes.len() / 2, + )}; + let mut pixel_points = Vec::new(); + for y in 0..8 { + for x in 0..8 { + if (pixel_shorts[y * 8 + x] & 0x8000) != 0 { + pixel_points.push(Point::new(x as i32, y as i32)); + } + } + } + let crop = Rect::from_enclose_points(&pixel_points, None) + .unwrap_or(Rect::new(0, 0, 8, 8)); + let mut rect = src_rect; + rect.set_x(crop.x() + src_rect.x()); + rect.set_width(crop.width()); + char_rects.insert(name.to_string(), rect); + + // position for next char + src_rect.set_x(src_rect.x() + 8); + if !surf_rect.contains_rect(src_rect) { + src_rect.set_x(0); + src_rect.set_y(src_rect.y() + 8); + } + } + Ok(SurfaceFont { + char_rects, + surf: canvas.into_surface(), + line_height: 8, + }) + } + pub fn load_zfont() -> Result> { + let mut zfont_txt = String::new(); + + // max 8x8 fonts, 16*16=256 characters + let mut canvas = Surface::new( + (FONT_MAX_W * FONT_COLS) as u32, + (FONT_MAX_H * FONT_ROWS) as u32, + PixelFormatEnum::ARGB1555, + )?.into_canvas()?; + canvas.set_draw_color(Color { r: 255, g: 255, b: 255, a: 255 }); + + File::open("zfont.txt") + .and_then(|mut f| { + f.read_to_string(&mut zfont_txt).map(|_| {}) + }) + .unwrap_or_else(|_| { + zfont_txt = String::from(include_str!("zfont.txt")); + }); + + let lines: Vec<_> = zfont_txt.lines().map(str::trim).collect(); + let mut char_rects = HashMap::new(); + let mut max_height = 0; + let mut line_num = 0; + while line_num < lines.len() { + let char_hdr = lines[line_num]; + if char_hdr == "EOF" { + break; + } + let r = Regex::new(r"^; (.*) 0x([0123456789abcdefABCDEF]{2})( \^\^)?$").unwrap(); + let groups = r.captures(char_hdr).ok_or_else(|| + format!("zfont.txt:{} character descriptor invalid:\n\t{}", line_num, char_hdr) + )?; + let mut name = groups.get(1) + .ok_or_else(|| format!("zfont.txt:{} missing character name:\n\t{}", line_num, char_hdr))? + .as_str() + .to_string(); + let hex_match = groups.get(2) + .ok_or_else(|| format!("zfont.txt:{} missing hex code:\n\t{}", line_num, char_hdr))?; + let index = usize::from_str_radix(hex_match.as_str(), 16)?; + if char_rects.len() != index { + return Err(format!( + "zfont.txt:{} code 0x{} out of order (expecting {:x})", + line_num, index, char_rects.len() + ).into()); + } + let x0 = ((index % FONT_COLS) * FONT_MAX_W) as i32; + let y0 = ((index / FONT_COLS) * FONT_MAX_H) as i32; + let mut y = y0; + let mut max_x = 0; + for row in &lines[line_num + 1..=(line_num + FONT_MAX_H).min(lines.len() - 1)] { + if let Some(';') = row.chars().next() { + break; + } + if *row == "EOF" { + break; + } + let mut x = x0; + if let Ok(mut row_bits) = u16::from_str_radix(row, 2) { + row_bits <<= 16 - FONT_MAX_W; + while row_bits != 0 { + if (row_bits & (1 << 15)) != 0 { + canvas.draw_point(Point::new(x, y))?; + if x > max_x { + max_x = x; + } + } + row_bits <<= 1; + x += 1; + } + } else { + return Err(format!("zfont.txt:{} invalid bit map in character {:?}", line_num, name).into()) + } + y += 1; + } + let mut width = 1 + (max_x - x0) as u32; + let height = (y - y0) as u32; + if height > max_height { + max_height = height; + } + if width == 1 { + width = height; + name = " ".to_string(); + } + char_rects.insert(name, Rect::new(x0, y0, width, height)); + line_num += 1 + height as usize; + } + Ok(SurfaceFont { + char_rects, + surf: canvas.into_surface(), + line_height: max_height, + }) + } + + pub fn blit_text(&self, target: &mut impl AsMut, text: impl AsRef, dest_rect: Rect) -> Result<()> { + let target = target.as_mut(); + let text = text.as_ref(); + let mut cursor_x = dest_rect.x(); + let mut cursor_y = dest_rect.y(); + for i in 0..text.len() { + let c = &text[i..=i]; + if c == "\n" { + cursor_x = dest_rect.x(); + cursor_y += self.line_height as i32 + 1; + } else if let Some(src_char_rect) = self.char_rects.get(c) { + let mut dst_char_rect = src_char_rect.clone(); + dst_char_rect.set_x(cursor_x); + dst_char_rect.set_y(cursor_y); + if dest_rect.contains_rect(dst_char_rect) { + cursor_x += src_char_rect.width() as i32 + 1; + self.surf.blit(*src_char_rect, target, dst_char_rect)?; + } else { + return Err("out of bounds text rendering".into()); + } + } + } + Ok(()) + } +} + + +pub fn surface_asset(asset: &'static [u8]) -> Result> { + let rwops = sdl2::rwops::RWops::from_bytes(asset)?; + let surf_shortlived = rwops.load_png()?; + // there's a nonsemantic inheritance of lifetime from ImageRWops::load_png. TODO: pr + unsafe { + let ptr = surf_shortlived.raw(); + std::mem::forget(surf_shortlived); + Ok(Surface::from_ll(ptr)) + } +} + +pub enum GuiState { + Menus, + Game +} + +impl GuiState { + pub fn toggle(&mut self) { + match self { + GuiState::Menus => *self = GuiState::Game, + GuiState::Game => *self = GuiState::Menus, + } + } +} diff --git a/src/lifont.txt b/src/lifont.txt new file mode 100644 index 0000000..5dadc30 --- /dev/null +++ b/src/lifont.txt @@ -0,0 +1,256 @@ +frame-top-left +frame-top +frame-top-right +frame-left +frame-right +frame-bottom-left +frame-bottom +frame-bottom-right +cursor-right +cursor-left +cursor-down +cursor-up +cancel +ok +no +back +arrow-up +arrow-down +arrow-left +arrow-right +arrow-up-left +arrow-up-right +arrow-down-left +arrow-down-right +square-big +square-medium +square-small +circle-big +circle-medium +circle-small +diamond +dot + +! +" +# +$ +% +& +' +( +) +* ++ +, +- +. +/ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +: +; +< += +> +? +@ +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +X +Y +Z +[ +\ +] +^ +_ +` +a +b +c +d +e +f +g +h +i +j +k +l +m +n +o +p +q +r +s +t +u +v +w +x +y +z +{ +| +} +~ +... +potion-empty +potion-red +potion-yellow +potion-green +potion-blue +potion-purple +coffee +black-tea +green-tea +coffee-to-go +shield-blue + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +pad-usb-button-1 +pad-usb-button-2 +pad-usb-button-3 +pad-usb-button-4 +pad-usb-button-5 +pad-usb-button-6 +pad-usb-button-7 +pad-usb-button-8 +pad-usb-button-9 +pad-usb-button-10 +pad-usb-button-11 +pad-usb-button-12 +pad-usb-hat +pad-usb-stick +pad-usb-lefthalf +pad-usb-righthalf +pad-xbox-button-1 +pad-xbox-button-2 +pad-xbox-button-3 +pad-xbox-button-4 +pad-xbox-button-5 +pad-xbox-button-6 +pad-xbox-button-7 +pad-xbox-button-8 +pad-xbox-button-9 +pad-xbox-button-10 +pad-xbox-button-11 +pad-xbox-button-12 +pad-xbox-hat +pad-xbox-stick +pad-xbox-lefthalf +pad-xbox-righthalf +pad-ps2-button-1 +pad-ps2-button-2 +pad-ps2-button-3 +pad-ps2-button-4 +pad-ps2-button-5 +pad-ps2-button-6 +pad-ps2-button-7 +pad-ps2-button-8 +pad-ps2-button-9 +pad-ps2-button-10 +pad-ps2-button-11 +pad-ps2-button-12 +pad-ps2-hat +pad-ps2-stick +pad-ps2-lefthalf +pad-ps2-righthalf +pad-wii-button-1 +pad-wii-button-2 +pad-wii-button-3 +pad-wii-button-4 +pad-wii-button-5 +pad-wii-button-6 +pad-wii-button-7 +pad-wii-button-8 +pad-wii-button-9 +pad-wii-button-10 +pad-wii-button-11 +pad-wii-button-12 +pad-wii-hat +pad-wii-stick +pad-wii-lefthalf +pad-wii-righthalf diff --git a/src/main.rs b/src/main.rs index a59f36f..18f3733 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,11 +7,11 @@ use std::pin::Pin; use sdl2::{ EventPump, - event::Event, - image::ImageRWops, + event::{Event, WindowEvent}, keyboard::Keycode, + mouse::{Cursor, MouseUtil}, pixels::{Color, PixelFormatEnum}, - rect::Point, + rect::{Point, Rect}, render::{WindowCanvas, BlendMode}, surface::Surface, }; @@ -20,6 +20,7 @@ use rand::{SeedableRng, Rng}; use rand_xoshiro::Xoshiro128Plus; use structopt::StructOpt; +use itertools::Itertools; use ferretro_components::base::ControlFlow; use ferretro_components::prelude::*; @@ -27,12 +28,12 @@ use ferretro_components::provided::{ sdl2::{Sdl2SurfaceComponent, SimpleSdl2AudioComponent}, stdlib::{SleepFramerateLimitComponent, PathBufComponent}, }; -use sdl2::mouse::{Cursor, MouseUtil}; -use sdl2::rect::Rect; -use itertools::Itertools; -use sdl2::event::WindowEvent; -type Result = std::result::Result>; +use crate::gui::*; + +pub type Result = std::result::Result>; + +mod gui; #[derive(StructOpt)] struct Opt { @@ -47,24 +48,10 @@ struct Opt { system: Option, } -enum GuiState { - Menus, - Game -} - -impl GuiState { - fn toggle(&mut self) { - match self { - GuiState::Menus => *self = GuiState::Game, - GuiState::Game => *self = GuiState::Menus, - } - } -} - struct Zretro { emu: Pin>, canvas: WindowCanvas, - font_surf: Surface<'static>, + font: SurfaceFont<'static>, mouse_util: MouseUtil, mouse_cursor: Cursor, mouse_shadow_surf: Surface<'static>, @@ -76,22 +63,6 @@ struct Zretro { event_pump: EventPump, } -const BG_COLOR: Color = Color { r: 65, g: 44, b: 130, a: 255 }; -const FONT_PNG: &'static [u8] = include_bytes!("lifont.png"); -const MOUSE_PNG: &'static [u8] = include_bytes!("zmouse.png"); -const MOUSE_SHADOW_PNG: &'static [u8] = include_bytes!("zmouse-shadow.png"); - -fn surface_asset(asset: &'static [u8]) -> Result> { - let rwops = sdl2::rwops::RWops::from_bytes(asset)?; - let surf_shortlived = rwops.load_png()?; - // there's a nonsemantic inheritance of lifetime from ImageRWops::load_png. TODO: pr - unsafe { - let ptr = surf_shortlived.raw(); - std::mem::forget(surf_shortlived); - Ok(Surface::from_ll(ptr)) - } -} - impl Zretro { fn new(opt: Opt) -> Result { let mut emu = RetroComponentBase::new(&opt.core); @@ -133,7 +104,8 @@ impl Zretro { emu.init().unwrap(); emu.load_game(&opt.rom).unwrap(); // TODO: optional via CLI positional arg, menu-browsable - let font_surf = surface_asset(FONT_PNG)?; + let font = SurfaceFont::load_lifont()?; + let mouse_surf = surface_asset(MOUSE_PNG)?; let mouse_shadow_surf = surface_asset(MOUSE_SHADOW_PNG)?; @@ -155,7 +127,7 @@ impl Zretro { Ok(Zretro { emu, canvas, - font_surf, + font, mouse_util, mouse_cursor, mouse_shadow_surf, @@ -213,9 +185,8 @@ impl Zretro { fn run(&mut self) -> Result<()> { let tc = self.canvas.texture_creator(); - let font_tx = tc.create_texture_from_surface(&self.font_surf)?; - let mut font_rect = self.font_surf.rect(); - font_rect.set_height(64); + let font_tx = tc.create_texture_from_surface(&self.font.surf)?; + let font_rect = self.font.surf.rect(); 'outer: loop { let events = self.event_pump.poll_iter().collect_vec(); for event in events { @@ -263,6 +234,12 @@ impl Zretro { let ui_bg_mut = self.ui_bg.as_mut().ok_or("no bg?")?; let _ = self.mouse_shadow_surf.blit(None, ui_bg_mut, self.mouse_shadow_pos); + + self.font.blit_text( + ui_bg_mut, + "Hello world\nfrom lifont", + Rect::new(144, 32, 100, 20) + )?; let mut ui_tx = tc.create_texture_from_surface(ui_bg_mut)?; ui_tx.set_blend_mode(BlendMode::Blend); self.canvas.copy(&ui_tx, None, None)?; diff --git a/src/zfont.txt b/src/zfont.txt new file mode 100644 index 0000000..f376e28 --- /dev/null +++ b/src/zfont.txt @@ -0,0 +1,847 @@ +; empty space 0x00 +00000000 +00000000 +00000000 +00000000 +00000000 +; 0 0x01 +01110000 +10011000 +10101000 +11001000 +01110000 +; 1 0x02 +00100000 +01100000 +00100000 +00100000 +01110000 +; 2 0x03 +01110000 +10001000 +00110000 +01000000 +11111000 +; 3 0x04 +01110000 +10001000 +00110000 +10001000 +01110000 +; 4 0x05 +01010000 +10010000 +11111000 +00010000 +00010000 +; 5 0x06 +11111000 +10000000 +11110000 +00001000 +11110000 +; 6 0x07 +01110000 +10000000 +11110000 +10001000 +01110000 +; 7 0x08 +11111000 +00001000 +00010000 +00010000 +00010000 +; 8 0x09 +01110000 +10001000 +01110000 +10001000 +01110000 +; 9 0x0A +01110000 +10001000 +01111000 +00001000 +01110000 +; A 0x0B +01110000 +10001000 +11111000 +10001000 +10001000 +; B 0x0C +11110000 +10001000 +11110000 +10001000 +11110000 +; C 0x0D +01110000 +10001000 +10000000 +10001000 +01110000 +; D 0x0E +11110000 +10001000 +10001000 +10001000 +11110000 +; E 0x0F +11111000 +10000000 +11110000 +10000000 +11111000 +; F 0x10 +11111000 +10000000 +11110000 +10000000 +10000000 +; G 0x11 +01111000 +10000000 +10011000 +10001000 +01110000 +; H 0x12 +10001000 +10001000 +11111000 +10001000 +10001000 +; I 0x13 +11111000 +00100000 +00100000 +00100000 +11111000 +; J 0x14 +01111000 +00010000 +00010000 +10010000 +01100000 +; K 0x15 +10010000 +10100000 +11100000 +10010000 +10001000 +; L 0x16 +10000000 +10000000 +10000000 +10000000 +11111000 +; M 0x17 +11011000 +10101000 +10101000 +10101000 +10001000 +; N 0x18 +11001000 +10101000 +10101000 +10101000 +10011000 +; O 0x19 +01110000 +10001000 +10001000 +10001000 +01110000 +; P 0x1A +11110000 +10001000 +11110000 +10000000 +10000000 +; Q 0x1B +01110000 +10001000 +10101000 +10010000 +01101000 +; R 0x1C +11110000 +10001000 +11110000 +10010000 +10001000 +; S 0x1D +01111000 +10000000 +01110000 +00001000 +11110000 +; T 0x1E +11111000 +00100000 +00100000 +00100000 +00100000 +; U 0x1F +10001000 +10001000 +10001000 +10001000 +01110000 +; V 0x20 +10001000 +10001000 +01010000 +01010000 +00100000 +; W 0x21 +10001000 +10101000 +10101000 +10101000 +01010000 +; X 0x22 +10001000 +01010000 +00100000 +01010000 +10001000 +; Y 0x23 +10001000 +01010000 +00100000 +00100000 +00100000 +; Z 0x24 +11111000 +00010000 +00100000 +01000000 +11111000 +; - 0x25 +00000000 +00000000 +11111000 +00000000 +00000000 +; _ 0x26 +00000000 +00000000 +00000000 +00000000 +11111000 +; ~ 0x27 +01101000 +10010000 +00000000 +00000000 +00000000 +; . 0x28 +00000000 +00000000 +00000000 +00000000 +00100000 +; / 0x29 +00001000 +00010000 +00100000 +01000000 +10000000 +; < 0x2A +00010000 +00100000 +01000000 +00100000 +00010000 +; > 0x2B +01000000 +00100000 +00010000 +00100000 +01000000 +; [ 0x2C +01110000 +01000000 +01000000 +01000000 +01110000 +; ] 0x2D +01110000 +00010000 +00010000 +00010000 +01110000 +; : 0x2E +00000000 +00100000 +00000000 +00100000 +00000000 +; & 0x2F +01100000 +10011000 +01110000 +10011000 +01101000 +; arrow down 0x30 +00100000 +00100000 +10101000 +01110000 +00100000 +; # 0x31 +01010000 +11111000 +01010000 +11111000 +01010000 +; = 0x32 +00000000 +11111000 +00000000 +11111000 +00000000 +; " 0x33 +01001000 +10010000 +00000000 +00000000 +00000000 +; \ 0x34 +10000000 +01000000 +00100000 +00010000 +00001000 +; * 0x35 +10101000 +01110000 +11111000 +01110000 +10101000 +; ? 0x36 +01110000 +10001000 +00110000 +00000000 +00100000 +; % 0x37 +10001000 +00010000 +00100000 +01000000 +10001000 +; + 0x38 +00100000 +00100000 +11111000 +00100000 +00100000 +; , 0x39 +00000000 +00000000 +00000000 +00100000 +01000000 +; ( 0x3A +00110000 +01000000 +01000000 +01000000 +00110000 +; ) 0x3B +01100000 +00010000 +00010000 +00010000 +01100000 +; @ 0x3C +01110000 +10011000 +10111000 +10000000 +01110000 +; ' 0x3D +00100000 +01000000 +00000000 +00000000 +00000000 +; ! 0x3E +00100000 +00100000 +00100000 +00000000 +00100000 +; $ 0x3F +01111000 +10100000 +01110000 +00101000 +11110000 +; ; 0x40 +00000000 +00100000 +00000000 +00100000 +01000000 +; ` 0x41 +01000000 +00100000 +00000000 +00000000 +00000000 +; ^ 0x42 +00100000 +01010000 +00000000 +00000000 +00000000 +; { 0x43 +00110000 +01000000 +11000000 +01000000 +00110000 +; } 0x44 +01100000 +00010000 +00011000 +00010000 +01100000 +; up 0x45 +00100000 +00100000 +01110000 +01110000 +11111000 +; down 0x46 +11111000 +01110000 +01110000 +00100000 +00100000 +; left 0x47 +00001000 +00111000 +11111000 +00111000 +00001000 +; right 0x48 +10000000 +11100000 +11111000 +11100000 +10000000 +; arrow left 0x49 +00100000 +01100000 +11111000 +01100000 +00100000 +; .5 0x4A +00111000 +00100000 +00110000 +00001000 +10110000 +; maximize (Win) 0x4B +11111100 +10000100 +11111100 +00000000 +00000000 +; minimize (Win) 0x4C +00000000 +11111100 +00000000 +00000000 +00000000 +; maximize (SDL) 0x4D +11111000 +10001000 +10001000 +10001000 +11111000 +; shw fullstop 0x4E +00000000 +00000000 +00100000 +01010000 +00100000 +; shw left bracket 0x4F +01110000 +01000000 +01000000 +01000000 +00000000 +; shw right bracket 0x50 +00000000 +00010000 +00010000 +00010000 +01110000 +; shw comma 0x51 +00000000 +00000000 +00000000 +01000000 +00100000 +; shw mid-dot 0x52 +00000000 +00100000 +01110000 +00100000 +00000000 +; shw wo 0x53 +11111000 +00001000 +11110000 +00100000 +11000000 +; shw mini a 0x54 +00000000 +11111000 +01010000 +01100000 +01000000 +; shw mini i 0x55 +00000000 +00010000 +00100000 +11100000 +00100000 +; shw mini u 0x56 +00000000 +00100000 +11111000 +10001000 +00110000 +; shw mini e 0x57 +00000000 +00000000 +11111000 +00100000 +11111000 +; shw mini o 0x58 +00000000 +00010000 +11111000 +00110000 +11010000 +; shw mini ya 0x59 +00000000 +01000000 +11111000 +01010000 +01000000 +; shw mini yu 0x5A +00000000 +00000000 +11110000 +00010000 +11111000 +; shw mini yo 0x5B +00000000 +11111000 +00001000 +01111000 +11111000 +; shw mini tsu 0x5C +00000000 +10101000 +10101000 +00010000 +01100000 +; shw prolong 0x5D +00000000 +10000000 +01111000 +00000000 +00000000 +; shw a 0x5E +11111000 +00101000 +00110000 +00100000 +11000000 +; shw i 0x5F +00001000 +00110000 +11100000 +00100000 +00100000 +; shw u 0x60 +00100000 +11111000 +10001000 +00010000 +01100000 +; shw e 0x61 +11111000 +00100000 +00100000 +00100000 +11111000 +; shw o 0x62 +00010000 +11111000 +00110000 +01010000 +10010000 +; shw ka 0x63 +01000000 +11111000 +01001000 +01001000 +10011000 +; shw ki 0x64 +00100000 +11111000 +00100000 +11111000 +00100000 +; shw ku 0x65 +01000000 +01111000 +10001000 +00010000 +01100000 +; shw ke 0x66 ^^ +01000000 +01111000 +10010000 +00010000 +01100000 +; shw ko 0x67 +11111000 +00001000 +00001000 +00001000 +11111000 +; shw sa 0x68 +01010000 +11111000 +01010000 +00010000 +01100000 +; shw shi 0x69 +01000000 +10101000 +01001000 +00010000 +11100000 +; shw su 0x6A +11111000 +00001000 +00010000 +00110000 +11001000 +; shw se 0x6B +01000000 +11111000 +01010000 +01000000 +00111000 +; shw so 0x6C +10001000 +01001000 +00001000 +00010000 +01100000 +; shw ta 0x6D +01000000 +01111000 +11001000 +00110000 +01100000 +; shw chi 0x6E +11111000 +00100000 +11111000 +00100000 +01000000 +; shw tsu 0x6F +10101000 +10101000 +00001000 +00010000 +01100000 +; shw te 0x70 +11111000 +00000000 +11111000 +00100000 +11000000 +; shw to 0x71 +01000000 +01000000 +01100000 +01010000 +01000000 +; shw na 0x72 +00100000 +11111000 +00100000 +00100000 +01000000 +; shw ni 0x73 +11110000 +00000000 +00000000 +00000000 +11111000 +; shw nu 0x74 +11111000 +00001000 +00101000 +00010000 +01101000 +; shw ne 0x75 +00100000 +11111000 +00001000 +01110000 +10101000 +; shw no 0x76 +00001000 +00001000 +00001000 +00010000 +01100000 +; shw ha 0x77 +01010000 +01010000 +01010000 +10001000 +10001000 +; shw hi 0x78 +10000000 +10011000 +11100000 +10000000 +01111000 +; shw hu 0x79 +11111000 +00001000 +00001000 +00010000 +01100000 +; shw he 0x7A +01000000 +10100000 +10010000 +00001000 +00000000 +; shw ho 0x7B +00100000 +11111000 +01110000 +10101000 +00100000 +; shw ma 0x7C +11111000 +00001000 +10010000 +01100000 +00100000 +; shw mi 0x7D +11111000 +00000000 +11111000 +00000000 +11111000 +; shw mu 0x7E +00100000 +01000000 +01000000 +10010000 +11111000 +; shw me 0x7F +00001000 +01001000 +00110000 +00110000 +11001000 +; shw mo 0x80 +11111000 +00100000 +11111000 +00100000 +00111000 +; shw ya 0x81 +01000000 +11111100 +01001000 +00100000 +00100000 +; shw yu 0x82 +11110000 +00010000 +00010000 +00010000 +11111000 +; shw yo 0x83 +11111000 +00001000 +11111000 +00001000 +11111000 +; shw ra 0x84 +11111000 +00000000 +11111000 +00010000 +01100000 +; shw ri 0x85 +10001000 +10001000 +10001000 +00010000 +01100000 +; shw ru 0x86 +01100000 +01100000 +01101000 +01101000 +10110000 +; shw re 0x87 +10000000 +10000000 +10001000 +10001000 +11110000 +; shw ro 0x88 +11111000 +10001000 +10001000 +10001000 +11111000 +; shw wa 0x89 +11111000 +10001000 +00001000 +00010000 +01100000 +; shw n 0x8A +10000000 +01001000 +00001000 +00010000 +11100000 +; shw voiced 0x8B +10100000 +10100000 +00000000 +00000000 +00000000 +; shw halfvoiced 0x8C +01000000 +10100000 +01000000 +00000000 +00000000 +EOF