diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ec084dfb..e5676623 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,7 +48,7 @@ jobs: - uses: actions/checkout@v6 - uses: mozilla-actions/sccache-action@v0.0.10 - run: sudo apt update - - run: sudo apt install libsdl2-dev libsdl2-ttf-dev + - run: sudo apt install libsdl2-dev - run: ./.github/workflows/release.sh linux-x86_64-sdl - uses: actions/upload-artifact@v7 with: diff --git a/.github/workflows/release.sh b/.github/workflows/release.sh index 6d88865e..02d867c1 100755 --- a/.github/workflows/release.sh +++ b/.github/workflows/release.sh @@ -83,7 +83,7 @@ main() { ;; macos*) - brew install sdl2 sdl2_ttf + brew install sdl2 local brew="$(brew --prefix)" ( @@ -98,14 +98,12 @@ main() { # Bundle the necessary shared libraries as provided by Homebrew. cp "${brew}"/Cellar/sdl2/*/lib/libSDL2-*.dylib "${distname}" cp "${brew}"/Cellar/sdl2/*/LICENSE.txt "${distname}/LICENSE.sdl2" - cp "${brew}"/Cellar/sdl2_ttf/*/lib/libSDL2_ttf-*.dylib "${distname}" - cp "${brew}"/Cellar/sdl2_ttf/*/LICENSE.txt "${distname}/LICENSE.sdl2_ttf" cp "${brew}"/Cellar/freetype/*/lib/libfreetype.*.dylib "${distname}" cp "${brew}"/Cellar/freetype/*/LICENSE.TXT "${distname}/LICENSE.freetype" cp "${brew}"/Cellar/libpng/*/lib/libpng16.*.dylib "${distname}" cp "${brew}"/Cellar/libpng/*/LICENSE "${distname}/LICENSE.libpng" - brew uninstall --ignore-dependencies sdl2 sdl2_ttf freetype libpng + brew uninstall --ignore-dependencies sdl2 freetype libpng sanity_check "${distname}/endbasic" ;; diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d02b285b..35baaa70 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@v6 - uses: mozilla-actions/sccache-action@v0.0.10 - run: sudo apt update - - run: sudo apt install libsdl2-dev libsdl2-ttf-dev + - run: sudo apt install libsdl2-dev - run: ./.github/workflows/package.sh cargo-install: @@ -43,7 +43,7 @@ jobs: - uses: actions/checkout@v6 - uses: mozilla-actions/sccache-action@v0.0.10 - run: sudo apt update - - run: sudo apt install libsdl2-dev libsdl2-ttf-dev + - run: sudo apt install libsdl2-dev - run: ./.github/workflows/install.sh - run: ./.github/workflows/install.sh --no-default-features - run: ./.github/workflows/install.sh --features=sdl diff --git a/.github/workflows/setup-sdl.ps1 b/.github/workflows/setup-sdl.ps1 index e792ec8e..069daa05 100644 --- a/.github/workflows/setup-sdl.ps1 +++ b/.github/workflows/setup-sdl.ps1 @@ -16,20 +16,16 @@ Invoke-WebRequest ` -Uri https://www.libsdl.org/release/SDL2-devel-2.32.10-VC.zip ` -OutFile SDL2-devel-2.32.10-VC.zip -Invoke-WebRequest ` - -Uri https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-devel-2.24.0-VC.zip ` - -OutFile SDL2_ttf-devel-2.24.0-VC.zip unzip SDL2-devel-2.32.10-VC.zip -unzip SDL2_ttf-devel-2.24.0-VC.zip [void](New-Item -Force -Type Directory libs) -Copy-Item .\SDL2-2.32.10\lib\x64\*.lib,.\SDL2_ttf-2.24.0\lib\x64\*.lib libs +Copy-Item .\SDL2-2.32.10\lib\x64\*.lib libs [void](New-Item -Force -Type Directory dlls) -Copy-Item .\SDL2-2.32.10\lib\x64\*.dll,.\SDL2_ttf-2.24.0\lib\x64\*.dll dlls -Copy-Item .\SDL2-2.32.10\lib\x64\*.txt,.\SDL2_ttf-2.24.0\lib\x64\*.txt dlls +Copy-Item .\SDL2-2.32.10\lib\x64\*.dll dlls +Copy-Item .\SDL2-2.32.10\lib\x64\*.txt dlls -Remove-Item -Recurse -Force .\SDL2-2.32.10,.\SDL2_ttf-2.24.0,SDL2*.zip +Remove-Item -Recurse -Force .\SDL2-2.32.10 foreach ($dir in ".", diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index de0b76f7..5733e958 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: - uses: actions/checkout@v6 - uses: mozilla-actions/sccache-action@v0.0.10 - run: sudo apt update - - run: sudo apt install libsdl2-dev libsdl2-ttf-dev + - run: sudo apt install libsdl2-dev - run: rustup component add clippy rustfmt - run: ./.github/workflows/lint.sh @@ -45,7 +45,7 @@ jobs: - uses: actions/checkout@v6 - uses: mozilla-actions/sccache-action@v0.0.10 - run: sudo apt update - - run: sudo apt install libsdl2-dev libsdl2-ttf-dev + - run: sudo apt install libsdl2-dev - run: cargo test --package='*' --features=sdl -- --include-ignored --skip sdl_console @@ -62,7 +62,7 @@ jobs: steps: - uses: actions/checkout@v6 - uses: mozilla-actions/sccache-action@v0.0.10 - - run: brew install sdl2 sdl2_ttf + - run: brew install sdl2 - run: cargo test --package=endbasic-client -- --include-ignored - run: cargo test --package=endbasic-core -- --include-ignored - run: cargo test --package=endbasic-std -- --include-ignored diff --git a/NEWS.md b/NEWS.md index 6c8a794f..55010942 100644 --- a/NEWS.md +++ b/NEWS.md @@ -48,6 +48,9 @@ for the time being.** * Because the new core has been AGPLv3+ licensed, the rest of the project has switched to this license as well. +* Modified the SDL console to use the same rasterization primitives as + the LCD for full font rendering control. + ## Changes in version 0.12.1 **Released on 2026-05-03.** diff --git a/cli/src/main.rs b/cli/src/main.rs index afa69611..09b3e5ce 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -29,6 +29,8 @@ use std::fs::File; use std::io; use std::path::Path; use std::rc::Rc; +#[cfg(feature = "sdl")] +use std::thread; /// Errors caused by the user when invoking this binary (invalid options or arguments). #[derive(Debug, thiserror::Error)] @@ -104,8 +106,18 @@ fn new_machine_builder( gpio_pins_spec: Option<&str>, ) -> Result { let signals_chan = async_channel::unbounded(); + let console = setup_console(console_spec, signals_chan.0.clone())?; + new_machine_builder_with_console(console, gpio_pins_spec, signals_chan) +} + +/// Creates a new EndBASIC machine builder with the preconfigured `console` and `signals_chan`. +fn new_machine_builder_with_console( + console: Rc>, + gpio_pins_spec: Option<&str>, + signals_chan: (Sender, async_channel::Receiver), +) -> Result { let mut builder = MachineBuilder::default(); - builder = builder.with_console(setup_console(console_spec, signals_chan.0.clone())?); + builder = builder.with_console(console); builder = builder.with_signals_chan(signals_chan); builder = builder.with_gpio_pins(setup_gpio_pins(gpio_pins_spec)?); Ok(builder) @@ -160,7 +172,7 @@ fn setup_console( signals_tx: Sender, spec: &mut ConsoleSpec, ) -> io::Result>> { - endbasic_sdl::setup(spec, signals_tx) + endbasic_sdl::setup(spec, &endbasic_std::gfx::lcd::fonts::Fonts::all(), signals_tx) } /// Errors out during the creation of the graphical console when SDL support is not compiled in. @@ -183,7 +195,7 @@ fn setup_console( endbasic_rpi::spi_bus_open, endbasic_terminal::TerminalConsole::from_stdio(signals_tx)?, spec, - &endbasic_std::gfx::lcd::fonts::all_fonts(), + &endbasic_std::gfx::lcd::fonts::Fonts::all(), )?; Ok(Rc::from(RefCell::from(console))) } @@ -237,7 +249,16 @@ async fn run_repl_loop( local_drive_spec: &str, service_url: &str, ) -> Result { - let mut builder = new_machine_builder(console_spec, gpio_pins_spec)?; + let builder = new_machine_builder(console_spec, gpio_pins_spec)?; + run_repl_loop_with_builder(builder, local_drive_spec, service_url).await +} + +/// Enters the interactive interpreter with a preconfigured `builder`. +async fn run_repl_loop_with_builder( + mut builder: MachineBuilder, + local_drive_spec: &str, + service_url: &str, +) -> Result { let console = builder.get_console(); let program = Rc::from(RefCell::from(endbasic_repl::editor::Editor::default())); let storage = Rc::from(RefCell::from(Storage::default())); @@ -269,6 +290,11 @@ async fn run_script>( gpio_pins_spec: Option<&str>, ) -> Result { let builder = new_machine_builder(console_spec, gpio_pins_spec)?; + run_script_with_builder(path, builder).await +} + +/// Executes the `path` program in a fresh machine with a preconfigured `builder`. +async fn run_script_with_builder>(path: P, builder: MachineBuilder) -> Result { let mut machine = builder.build(); let mut input = File::open(path)?; @@ -296,7 +322,17 @@ async fn run_interactive( local_drive_spec: &str, service_url: &str, ) -> Result { - let mut builder = new_machine_builder(console_spec, gpio_pins_spec)?; + let builder = new_machine_builder(console_spec, gpio_pins_spec)?; + run_interactive_with_builder(path, builder, local_drive_spec, service_url).await +} + +/// Executes the `path` program in a fresh interactive machine with a preconfigured `builder`. +async fn run_interactive_with_builder( + path: &str, + mut builder: MachineBuilder, + local_drive_spec: &str, + service_url: &str, +) -> Result { let console = builder.get_console(); let program = Rc::from(RefCell::from(endbasic_repl::editor::Editor::default())); let storage = Rc::from(RefCell::from(Storage::default())); @@ -358,43 +394,155 @@ fn app_build(builder: Builder) -> Builder { .extra_help(app_extra_help) } -async fn app_main(matches: Matches) -> Result { - let console_spec = matches.opt_str("console"); +enum AppMode { + Repl, + RunInteractive(String), + RunScript(String), +} - let gpio_pins_spec = matches.opt_str("gpio-pins"); +fn parse_app_mode(matches: &Matches) -> Result { + match matches.arg_trail() { + [] => Ok(AppMode::Repl), + [file] => { + if matches.opt_present("interactive") { + Ok(AppMode::RunInteractive((*file).to_owned())) + } else { + Ok(AppMode::RunScript((*file).to_owned())) + } + } + [_, ..] => Err(UsageError::new("Too many arguments").into()), + } +} - let service_url = matches - .opt_str("service-url") - .unwrap_or_else(|| endbasic_client::PROD_API_ADDRESS.to_owned()); +fn uses_sdl_console(console_spec: Option<&str>) -> bool { + ConsoleSpec::init(console_spec.unwrap_or("text")).driver == "sdl" +} - match matches.arg_trail() { - [] => { - let local_drive = get_local_drive_spec(matches.opt_str("local-drive"))?; - Ok(run_repl_loop( +async fn app_main_async( + console_spec: Option, + gpio_pins_spec: Option, + local_drive_spec: Option, + service_url: String, + mode: AppMode, +) -> Result { + match mode { + AppMode::Repl => { + let local_drive = get_local_drive_spec(local_drive_spec)?; + run_repl_loop( console_spec.as_deref(), gpio_pins_spec.as_deref(), &local_drive, &service_url, ) - .await?) + .await } - [file] => { - if matches.opt_present("interactive") { - let local_drive = get_local_drive_spec(matches.opt_str("local-drive"))?; - Ok(run_interactive( - file, - console_spec.as_deref(), - gpio_pins_spec.as_deref(), - &local_drive, - &service_url, - ) - .await?) - } else { - Ok(run_script(file, console_spec.as_deref(), gpio_pins_spec.as_deref()).await?) - } + AppMode::RunInteractive(file) => { + let local_drive = get_local_drive_spec(local_drive_spec)?; + run_interactive( + &file, + console_spec.as_deref(), + gpio_pins_spec.as_deref(), + &local_drive, + &service_url, + ) + .await } - [_, ..] => Err(UsageError::new("Too many arguments").into()), + AppMode::RunScript(file) => { + run_script(&file, console_spec.as_deref(), gpio_pins_spec.as_deref()).await + } + } +} + +#[cfg(feature = "sdl")] +fn run_sdl_app( + console_spec: Option, + gpio_pins_spec: Option, + local_drive_spec: Option, + service_url: String, + mode: AppMode, +) -> Result { + let signals_chan = async_channel::unbounded(); + let mut console_spec_parser = ConsoleSpec::init(console_spec.as_deref().unwrap_or("text")); + let (console_factory, host) = endbasic_sdl::prepare( + &mut console_spec_parser, + &endbasic_std::gfx::lcd::fonts::Fonts::all(), + signals_chan.0.clone(), + )?; + console_spec_parser.finish().map_err(|e| { + io::Error::new(io::ErrorKind::InvalidInput, format!("Invalid --console flag: {}", e)) + })?; + + let interpreter = thread::spawn(move || -> Result { + let runtime = tokio::runtime::Builder::new_current_thread().enable_all().build()?; + let console = console_factory.connect()?; + let builder = + new_machine_builder_with_console(console, gpio_pins_spec.as_deref(), signals_chan)?; + runtime.block_on(async move { + match mode { + AppMode::Repl => { + run_repl_loop_with_builder( + builder, + local_drive_spec.as_deref().expect("Missing local drive"), + &service_url, + ) + .await + } + AppMode::RunInteractive(path) => { + run_interactive_with_builder( + &path, + builder, + local_drive_spec.as_deref().expect("Missing local drive"), + &service_url, + ) + .await + } + AppMode::RunScript(path) => run_script_with_builder(path, builder).await, + } + }) + }); + + host.run(); + interpreter.join().expect("Interpreter thread should not have panicked") +} + +#[cfg(not(feature = "sdl"))] +fn run_sdl_app( + _console_spec: Option, + _gpio_pins_spec: Option, + _local_drive_spec: Option, + _service_url: String, + _mode: AppMode, +) -> Result { + Err(UsageError::new("--console=sdl requires the sdl feature to be compiled in").into()) +} + +fn app_main(matches: Matches) -> Result { + let console_spec = matches.opt_str("console"); + let gpio_pins_spec = matches.opt_str("gpio-pins"); + let service_url = matches + .opt_str("service-url") + .unwrap_or_else(|| endbasic_client::PROD_API_ADDRESS.to_owned()); + let local_drive_spec = matches.opt_str("local-drive"); + let mode = parse_app_mode(&matches)?; + + if uses_sdl_console(console_spec.as_deref()) { + let local_drive_spec = match &mode { + AppMode::Repl | AppMode::RunInteractive(_) => { + Some(get_local_drive_spec(local_drive_spec)?) + } + AppMode::RunScript(_) => None, + }; + run_sdl_app(console_spec, gpio_pins_spec, local_drive_spec, service_url, mode) + } else { + let runtime = tokio::runtime::Runtime::new()?; + runtime.block_on(app_main_async( + console_spec, + gpio_pins_spec, + local_drive_spec, + service_url, + mode, + )) } } -tokio_app!("EndBASIC", app_build, app_main); +app!("EndBASIC", app_build, app_main); diff --git a/sdl/Cargo.toml b/sdl/Cargo.toml index 1e6ff3e7..9a81317b 100644 --- a/sdl/Cargo.toml +++ b/sdl/Cargo.toml @@ -31,7 +31,6 @@ path = "../std" [dependencies.sdl2] version = "0.38" default-features = false -features = ["ttf"] [dev-dependencies] flate2 = "1.0" diff --git a/sdl/src/IBMPlexMono-Regular-6.0.0.ttf b/sdl/src/IBMPlexMono-Regular-6.0.0.ttf deleted file mode 100644 index 8d43f3d0..00000000 Binary files a/sdl/src/IBMPlexMono-Regular-6.0.0.ttf and /dev/null differ diff --git a/sdl/src/console.rs b/sdl/src/console.rs index 6d3b0ac0..d0bc09e6 100644 --- a/sdl/src/console.rs +++ b/sdl/src/console.rs @@ -20,14 +20,43 @@ use crate::host::{self, Request, Response}; use async_channel::Sender; use async_trait::async_trait; use endbasic_std::Signal; -use endbasic_std::console::{ - CharsXY, ClearType, Console, Key, PixelsXY, Resolution, SizeInPixels, remove_control_chars, -}; +use endbasic_std::console::graphics::InputOps; +use endbasic_std::console::{Key, RGB, Resolution}; +use endbasic_std::gfx::lcd::{AsByteSlice, Lcd, LcdSize, LcdXY}; use std::io; -use std::path::PathBuf; use std::sync::mpsc::{self, Receiver, SyncSender, TryRecvError}; use std::thread::{self, JoinHandle}; +/// Transport used by a client-side SDL console to connect to a running host loop. +pub(crate) struct SdlConsoleClient { + request_tx: SyncSender, + response_rx: Receiver, + on_key_rx: Receiver, +} + +impl SdlConsoleClient { + /// Binds this client transport to a running host loop. + pub(crate) fn connect(self) -> io::Result<(SdlConsole, Receiver)> { + let Self { request_tx, response_rx, on_key_rx } = self; + match response_rx.recv().expect("Channel must be alive") { + Response::Empty(Err(e)) => Err(e), + Response::Info(info) => { + Ok((Self::make_console(None, request_tx, response_rx, info), on_key_rx)) + } + r => panic!("Unexpected response {:?}", r), + } + } + + fn make_console( + handle: Option>, + request_tx: SyncSender, + response_rx: Receiver, + info: (LcdSize, usize), + ) -> SdlConsole { + SdlConsole { handle, request_tx, response_rx, info } + } +} + /// Implementation of the EndBASIC console on top of an SDL2 window. /// /// This is only the "client" part of the console, which implements the `Console` trait and @@ -36,61 +65,52 @@ pub(crate) struct SdlConsole { handle: Option>, request_tx: SyncSender, response_rx: Receiver, - on_key_rx: Receiver, - fg_color: Option, - bg_color: Option, - alt_backup: Option<(Option, Option)>, + info: (LcdSize, usize), } impl SdlConsole { /// Initializes a new SDL console. /// - /// The console is sized to `resolution` pixels and its default colors are set to - /// `default_fg_color` and `default_bg_color`. Also loads the desired font from `font_path` at - /// `font_size` and uses it to calculate the size of the console in characters. + /// The console is sized to `resolution` pixels. Uses `glyph_size` to calculate the size of the + /// console in characters. /// /// There can only be one active `SdlConsole` at any given time given that this initializes and /// owns the SDL context. - pub(crate) fn new( + pub(crate) fn prepare( resolution: Resolution, - default_fg_color: Option, - default_bg_color: Option, - font_path: PathBuf, - font_size: u16, + glyph_size: LcdSize, signals_tx: Sender, - ) -> io::Result { + ) -> (SdlConsoleClient, host::SdlHost) { let (request_tx, request_rx) = mpsc::sync_channel(1); let (response_tx, response_rx) = mpsc::sync_channel(1); let (on_key_tx, on_key_rx) = mpsc::channel(); + let client = SdlConsoleClient { request_tx, response_rx, on_key_rx }; + let host = host::SdlHost::new( + resolution, + glyph_size, + request_rx, + response_tx, + on_key_tx, + signals_tx, + ); + (client, host) + } + + pub(crate) fn new( + resolution: Resolution, + glyph_size: LcdSize, + signals_tx: Sender, + ) -> io::Result<(Self, Receiver)> { + let (client, host) = Self::prepare(resolution, glyph_size, signals_tx); let handle = thread::spawn(move || { - host::run( - resolution, - default_fg_color, - default_bg_color, - font_path, - font_size, - request_rx, - response_tx, - on_key_tx, - signals_tx, - ); + host.run(); }); // Wait for the console to be up and running. We must do this for error propagation but // also to ensure that the caller can free up the local temporary font resources, if any. - match response_rx.recv().expect("Channel must be alive") { - Response::Empty(Ok(())) => Ok(Self { - handle: Some(handle), - request_tx, - response_rx, - on_key_rx, - fg_color: None, - bg_color: None, - alt_backup: None, - }), - Response::Empty(Err(e)) => Err(e), - r => panic!("Unexpected response {:?}", r), - } + let (mut console, on_key_rx) = client.connect()?; + console.handle = Some(handle); + Ok((console, on_key_rx)) } /// Issues a synchronous call against the console host for a request that returns nothing but @@ -107,153 +127,58 @@ impl SdlConsole { impl Drop for SdlConsole { fn drop(&mut self) { - self.request_tx.send(Request::Exit).expect("Channel must be alive"); - self.handle - .take() - .expect("Handle must always be present") - .join() - .expect("Thread should not have panicked"); + let _ = self.request_tx.send(Request::Exit); + if let Some(handle) = self.handle.take() { + handle.join().expect("Thread should not have panicked"); + } } } -#[async_trait(?Send)] -impl Console for SdlConsole { - fn clear(&mut self, how: ClearType) -> io::Result<()> { - self.call(Request::Clear(how)) - } - - fn color(&self) -> (Option, Option) { - (self.fg_color, self.bg_color) - } - - fn set_color(&mut self, fg: Option, bg: Option) -> io::Result<()> { - self.call(Request::SetColor(fg, bg))?; - self.fg_color = fg; - self.bg_color = bg; - Ok(()) - } - - fn enter_alt(&mut self) -> io::Result<()> { - if self.alt_backup.is_some() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Cannot nest alternate screens", - )); - } - - self.alt_backup = Some((self.fg_color, self.bg_color)); - - self.call(Request::EnterAlt) - } +/// Number of bytes per pixel as supported by this implementation. +pub(super) const PIXEL_BYTES: usize = 4; - fn hide_cursor(&mut self) -> io::Result<()> { - self.call(Request::HideCursor) - } +/// Data for one pixel encoded as RGB888 with an alpha channel. +#[derive(Clone, Copy)] +pub(super) struct SdlPixel(pub [u8; PIXEL_BYTES]); - fn is_interactive(&self) -> bool { - true +impl AsByteSlice for SdlPixel { + fn as_slice(&self) -> &[u8] { + &self.0 } +} - fn leave_alt(&mut self) -> io::Result<()> { - let alt_backup = match self.alt_backup.take() { - Some(t) => t, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Cannot leave alternate screen; not entered", - )); - } - }; - - self.call(Request::LeaveAlt)?; +impl Lcd for SdlConsole { + type Pixel = SdlPixel; - (self.fg_color, self.bg_color) = alt_backup; - Ok(()) + fn encode(&self, rgb: RGB) -> Self::Pixel { + SdlPixel([rgb.0, rgb.1, rgb.2, 255]) } - fn locate(&mut self, pos: CharsXY) -> io::Result<()> { - self.call(Request::Locate(pos)) + fn info(&self) -> (LcdSize, usize) { + self.info } - fn move_within_line(&mut self, off: i16) -> io::Result<()> { - self.call(Request::MoveWithinLine(off)) + fn set_data(&mut self, x1y1: LcdXY, x2y2: LcdXY, data: &[u8]) -> io::Result<()> { + self.call(Request::SetData(x1y1, x2y2, data.to_vec())) } +} - fn print(&mut self, text: &str) -> io::Result<()> { - let text = remove_control_chars(text); - self.call(Request::Print(text)) - } +pub(crate) struct SdlInput(pub(crate) Receiver); +#[async_trait(?Send)] +impl InputOps for SdlInput { async fn poll_key(&mut self) -> io::Result> { - match self.on_key_rx.try_recv() { + match self.0.try_recv() { Ok(k) => Ok(Some(k)), Err(TryRecvError::Empty) => Ok(None), - Err(TryRecvError::Disconnected) => panic!("Channel must be alive"), + Err(TryRecvError::Disconnected) => Ok(Some(Key::Eof)), } } async fn read_key(&mut self) -> io::Result { - Ok(self.on_key_rx.recv().expect("Channel must be alive")) - } - - fn show_cursor(&mut self) -> io::Result<()> { - self.call(Request::ShowCursor) - } - - fn size_chars(&self) -> io::Result { - self.request_tx.send(Request::SizeChars).expect("Channel must be alive"); - match self.response_rx.recv().expect("Channel must be alive") { - Response::SizeChars(size) => Ok(size), - _ => panic!("Unexpected response type"), - } - } - - fn size_pixels(&self) -> io::Result { - self.request_tx.send(Request::SizePixels).expect("Channel must be alive"); - match self.response_rx.recv().expect("Channel must be alive") { - Response::SizePixels(size) => Ok(size), - _ => panic!("Unexpected response type"), - } - } - - fn write(&mut self, text: &str) -> io::Result<()> { - let text = remove_control_chars(text); - self.call(Request::Write(text)) - } - - fn draw_circle(&mut self, center: PixelsXY, radius: u16) -> io::Result<()> { - self.call(Request::DrawCircle(center, radius)) - } - - fn draw_circle_filled(&mut self, center: PixelsXY, radius: u16) -> io::Result<()> { - self.call(Request::DrawCircleFilled(center, radius)) - } - - fn draw_line(&mut self, x1y1: PixelsXY, x2y2: PixelsXY) -> io::Result<()> { - self.call(Request::DrawLine(x1y1, x2y2)) - } - - fn draw_pixel(&mut self, xy: PixelsXY) -> io::Result<()> { - self.call(Request::DrawPixel(xy)) - } - - fn draw_rect(&mut self, x1y1: PixelsXY, x2y2: PixelsXY) -> io::Result<()> { - self.call(Request::DrawRect(x1y1, x2y2)) - } - - fn draw_rect_filled(&mut self, x1y1: PixelsXY, x2y2: PixelsXY) -> io::Result<()> { - self.call(Request::DrawRectFilled(x1y1, x2y2)) - } - - fn sync_now(&mut self) -> io::Result<()> { - self.call(Request::SyncNow) - } - - fn set_sync(&mut self, enabled: bool) -> io::Result { - self.request_tx.send(Request::SetSync(enabled)).expect("Channel must be alive"); - match self.response_rx.recv().expect("Channel must be alive") { - Response::SetSync(result) => result, - _ => panic!("Unexpected response type"), + match self.0.recv() { + Ok(k) => Ok(k), + Err(_) => Ok(Key::Eof), } } } diff --git a/sdl/src/font.rs b/sdl/src/font.rs deleted file mode 100644 index 0e009bb9..00000000 --- a/sdl/src/font.rs +++ /dev/null @@ -1,122 +0,0 @@ -// EndBASIC -// Copyright 2022 Julio Merino -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy -// of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -//! SDL font manipulation helpers. - -use crate::string_error_to_io_error; -use endbasic_std::console::{CharsXY, SizeInPixels}; -use once_cell::sync::Lazy; -use sdl2::ttf::{Font, FontError, Sdl2TtfContext}; -use std::convert::TryFrom; -use std::io; -use std::path::Path; - -/// Global instance of the SDL TTF font loader. Trying to deal with the lifetime of the derived -/// fonts seems to be incredibly hard because of how we hide the `SdlConsole` implementation behind -/// the `Console` trait. It might be possible to do this in a better way, but for now, keeping the -/// context global works well and is simple enough. -static TTF_CONTEXT: Lazy> = Lazy::new(sdl2::ttf::init); - -/// Converts a `FontError` to an `io::Error`. -pub(crate) fn font_error_to_io_error(e: FontError) -> io::Error { - let kind = match e { - FontError::InvalidLatin1Text(_) => io::ErrorKind::InvalidInput, - FontError::SdlError(_) => io::ErrorKind::Other, - }; - io::Error::new(kind, e) -} - -/// Wrapper around a monospaced SDL font. -pub(crate) struct MonospacedFont<'a> { - pub(crate) font: Font<'a, 'static>, - pub(crate) glyph_size: SizeInPixels, -} - -impl<'a> MonospacedFont<'a> { - /// Loads the font from the file `path` with `point_size`. If the loaded font is not - /// monospaced, returns an error. - pub(crate) fn load(path: &Path, point_size: u16) -> io::Result> { - let ttf_context = TTF_CONTEXT.as_ref().map_err(|s| io::Error::other(s.to_string()))?; - - let font = ttf_context.load_font(path, point_size).map_err(string_error_to_io_error)?; - - if !font.face_is_fixed_width() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - format!("Font {} is not monospaced", path.display()), - )); - } - - let glyph_size = { - let metrics = match font.find_glyph_metrics('A') { - Some(metrics) => metrics, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Font lacks a glyph for 'A'; is it valid?", - )); - } - }; - - let width = match u16::try_from(metrics.advance) { - Ok(0) => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Invalid font width 0", - )); - } - Ok(width) => width, - Err(e) => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - format!("Invalid font width {}: {}", metrics.advance, e), - )); - } - }; - - let height = match u16::try_from(font.height()) { - Ok(0) => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Invalid font height 0", - )); - } - Ok(height) => height, - Err(e) => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - format!("Invalid font height {}: {}", font.height(), e), - )); - } - }; - - SizeInPixels::new(width, height) - }; - - Ok(MonospacedFont { font, glyph_size }) - } - - /// Computes the number of characters that fit within the given pixels `area`. - pub(crate) fn chars_in_area(&self, area: SizeInPixels) -> CharsXY { - CharsXY::new( - area.width - .checked_div(self.glyph_size.width) - .expect("Glyph size tested for non-zero during init"), - area.height - .checked_div(self.glyph_size.height) - .expect("Glyph size tested for non-zero during init"), - ) - } -} diff --git a/sdl/src/host.rs b/sdl/src/host.rs index 48441577..d7a6abe2 100644 --- a/sdl/src/host.rs +++ b/sdl/src/host.rs @@ -19,19 +19,15 @@ //! All communication with this thread happens via channels to ensure all SDL operations are invoked //! from a single thread. -use crate::font::{MonospacedFont, font_error_to_io_error}; use crate::string_error_to_io_error; -use async_trait::async_trait; use endbasic_std::Signal; -use endbasic_std::console::drawing::{draw_circle, draw_circle_filled}; -use endbasic_std::console::graphics::{ClampedInto, ClampedMul, InputOps, RasterInfo, RasterOps}; -use endbasic_std::console::{ - CharsXY, ClearType, Console, GraphicsConsole, Key, PixelsXY, RGB, Resolution, SizeInPixels, -}; +use endbasic_std::console::graphics::{ClampedInto, ClampedMul}; +use endbasic_std::console::{CharsXY, Key, Resolution, SizeInPixels}; +use endbasic_std::gfx::lcd::{LcdSize, LcdXY, to_xy_size}; use sdl2::event::Event; use sdl2::keyboard::{Keycode, Mod}; -use sdl2::pixels::{Color, PixelFormatEnum}; -use sdl2::rect::{Point, Rect}; +use sdl2::pixels::PixelFormatEnum; +use sdl2::rect::Rect; use sdl2::render::{SurfaceCanvas, TextureCreator, TextureValueError, UpdateTextureError}; use sdl2::surface::{Surface, SurfaceContext}; use sdl2::video::{Window, WindowBuildError}; @@ -42,6 +38,7 @@ use std::fmt::{self, Write}; use std::io; #[cfg(test)] use std::path::Path; +#[cfg(test)] use std::path::PathBuf; use std::rc::Rc; use std::sync::mpsc::{Receiver, Sender, SyncSender, TryRecvError}; @@ -99,26 +96,32 @@ fn window_build_error_to_io_error(e: WindowBuildError) -> io::Error { io::Error::new(kind, e) } -/// Constructs an SDL `Point` from a `PixelsXY`. -fn point_xy(xy: PixelsXY) -> Point { - Point::new(i32::from(xy.x), i32::from(xy.y)) +/// Constructs an SDL `Rect` from an `LcdXY` `origin` and an `LcdSize` `size`. +fn rect_origin_size(origin: LcdXY, size: LcdSize) -> Rect { + if cfg!(debug_assertions) { + Rect::new( + i32::try_from(origin.x).expect("Origin X must fit in i32"), + i32::try_from(origin.y).expect("Origin Y must fit in i32"), + u32::try_from(size.width).expect("Width must fit in u32"), + u32::try_from(size.height).expect("Height must fit in u32"), + ) + } else { + Rect::new(origin.x as i32, origin.y as i32, size.width as u32, size.height as u32) + } } -/// Constructs an SDL `Rect` from a `PixelsXY` `origin` and a `PixelsSize` `size`. -fn rect_origin_size(origin: PixelsXY, size: SizeInPixels) -> Rect { - Rect::new( - i32::from(origin.x), - i32::from(origin.y), - u32::from(size.width), - u32::from(size.height), +/// Computes the number of characters that fit within the given pixels `area`. +fn chars_in_area(glyph_size: LcdSize, area: SizeInPixels) -> CharsXY { + CharsXY::new( + area.width + .checked_div(u16::try_from(glyph_size.width).expect("Glyph width must fit in u16")) + .expect("Glyph size tested for non-zero during init"), + area.height + .checked_div(u16::try_from(glyph_size.height).expect("Glyph height must fit in u16")) + .expect("Glyph size tested for non-zero during init"), ) } -/// Converts our own `RGB` type to an SDL `Color`. -fn rgb_to_color(rgb: RGB) -> Color { - Color::RGB(rgb.0, rgb.1, rgb.2) -} - /// Given an SDL `event`, converts it to a `Key` event if it is a key press; otherwise, returns /// `None` for unknown events. fn parse_event(event: Event) -> Option { @@ -186,9 +189,6 @@ struct Context { #[cfg_attr(not(test), allow(unused))] sdl: Sdl, - /// Monospaced font to use in the console. - font: MonospacedFont<'static>, - /// Event pump to read keyboard events from. event_pump: EventPump, @@ -207,26 +207,17 @@ struct Context { /// Size of the console in pixels. size_pixels: SizeInPixels, - - /// Size of the console in characters. This is derived from `size_pixels` and the `font` glyph - /// metrics. - size_chars: CharsXY, - - /// Current draw color. Used only to track if we need to update the context. - draw_color: RGB, } impl Context { /// Initializes a new SDL console. /// - /// The console is sized to `resolution` pixels. Also loads the desired font from - /// `font_path` at `font_size` and uses it to calculate the size of the console in characters. + /// The console is sized to `resolution` pixels. Uses `glyph_size` to calculate the size of the + /// console in characters. /// /// There can only be one active `SdlConsole` at any given time given that this initializes and /// owns the SDL context. - fn new(resolution: Resolution, font_path: PathBuf, font_size: u16) -> io::Result { - let font = MonospacedFont::load(&font_path, font_size)?; - + fn new(resolution: Resolution, glyph_size: LcdSize) -> io::Result { let sdl = sdl2::init().map_err(string_error_to_io_error)?; let event_pump = sdl.event_pump().map_err(string_error_to_io_error)?; let video = sdl.video().map_err(string_error_to_io_error)?; @@ -259,7 +250,7 @@ impl Context { let (width, height) = window.drawable_size(); SizeInPixels::new(width.clamped_into(), height.clamped_into()) }; - let size_chars = font.chars_in_area(size_pixels); + let size_chars = chars_in_area(glyph_size, size_pixels); write!( &mut title, @@ -270,51 +261,17 @@ impl Context { window.set_title(&title).expect("There should have been no NULLs in the formatted title"); let pixel_format = window.window_pixel_format(); + let surface = Surface::new(u32::from(size_pixels.width), u32::from(size_pixels.height), pixel_format) .map_err(string_error_to_io_error)?; - let mut canvas = surface.into_canvas().map_err(string_error_to_io_error)?; + let canvas = surface.into_canvas().map_err(string_error_to_io_error)?; let texture_creator = canvas.texture_creator(); - let draw_color = RGB::default(); - canvas.set_draw_color(rgb_to_color(draw_color)); - - Ok(Self { - sdl, - font, - event_pump, - window, - canvas, - pixel_format, - texture_creator, - size_pixels, - size_chars, - draw_color, - }) - } -} - -impl RasterOps for Context { - type ID = (Vec, SizeInPixels); - - fn get_info(&self) -> RasterInfo { - RasterInfo { - size_chars: self.size_chars, - size_pixels: self.size_pixels, - glyph_size: self.font.glyph_size, - } - } - - fn set_draw_color(&mut self, color: RGB) { - if self.draw_color != color { - self.canvas.set_draw_color(rgb_to_color(color)); - self.draw_color = color; - } - } - - fn clear(&mut self) -> io::Result<()> { - self.canvas.clear(); - Ok(()) + let mut ctx = + Self { sdl, event_pump, window, canvas, pixel_format, texture_creator, size_pixels }; + ctx.present_canvas()?; + Ok(ctx) } fn present_canvas(&mut self) -> io::Result<()> { @@ -327,30 +284,15 @@ impl RasterOps for Context { window_surface.finish().map_err(string_error_to_io_error) } - fn read_pixels(&mut self, xy: PixelsXY, size: SizeInPixels) -> io::Result { - let rect = rect_origin_size(xy, size); - let data = match self.canvas.read_pixels(rect, self.pixel_format) { - Ok(data) => data, - Err(e) if e == "Can't read outside the current viewport" => { - // The SDL read pixels operation intersects the requested rect with the viewport. - // However, SDL2-compat does not like it when the two don't intersect at all. - // Fake the response so that our SDL2 code remains compatible with SDL2-compat. - vec![ - 0; - usize::from(size.width) - * usize::from(size.height) - * self.pixel_format.byte_size_per_pixel() - ] - } - Err(e) => { - return Err(string_error_to_io_error(e)); - } - }; - Ok((data, size)) + fn get_info(&self) -> (LcdSize, usize) { + let size = self.size_pixels; + let pixel_size = self.pixel_format.byte_size_per_pixel(); + (LcdSize { width: usize::from(size.width), height: usize::from(size.height) }, pixel_size) } - fn put_pixels(&mut self, xy: PixelsXY, (data, size): &Self::ID) -> io::Result<()> { - let rect = rect_origin_size(xy, *size); + fn set_data(&mut self, x1y1: LcdXY, x2y2: LcdXY, data: &[u8]) -> io::Result<()> { + let (xy, size) = to_xy_size(x1y1, x2y2); + let rect = rect_origin_size(xy, size); let mut texture = self .texture_creator .create_texture_static(None, rect.width(), rect.height()) @@ -362,85 +304,9 @@ impl RasterOps for Context { } .clamped_mul(self.pixel_format.byte_size_per_pixel()); texture.update(None, data, width).map_err(update_texture_error_to_io_error)?; - self.canvas.copy(&texture, None, rect).map_err(string_error_to_io_error) - } - - fn move_pixels( - &mut self, - x1y1: PixelsXY, - x2y2: PixelsXY, - size: SizeInPixels, - ) -> io::Result<()> { - let shifted = { - let src = self.canvas.surface(); - let mut temp = Surface::new(src.width(), src.height(), self.pixel_format) - .map_err(string_error_to_io_error)?; - let src_rect = rect_origin_size(x1y1, size); - let dst_rect = rect_origin_size(x2y2, size); - temp.fill_rect(src_rect, rgb_to_color(self.draw_color)) - .map_err(string_error_to_io_error)?; - src.blit(src_rect, &mut temp, dst_rect).map_err(string_error_to_io_error)?; - temp - }; - shifted.blit(None, self.canvas.surface_mut(), None).map_err(string_error_to_io_error)?; - Ok(()) - } - - fn write_text(&mut self, xy: PixelsXY, text: &str) -> io::Result<()> { - debug_assert!(!text.is_empty(), "SDL does not like empty strings"); - - let len = match u16::try_from(text.chars().count()) { - Ok(v) => v, - Err(_) => return Err(io::Error::new(io::ErrorKind::InvalidInput, "String too long")), - }; - - let rect = Rect::new( - i32::from(xy.x), - i32::from(xy.y), - len.clamped_mul(self.font.glyph_size.width), - u32::from(self.font.glyph_size.height), - ); - - let surface = - self.font.font.render(text).blended(self.draw_color).map_err(font_error_to_io_error)?; - let texture = self - .texture_creator - .create_texture_from_surface(&surface) - .map_err(texture_value_error_to_io_error)?; - self.canvas.copy(&texture, None, rect).map_err(string_error_to_io_error) - } - - fn draw_circle(&mut self, center: PixelsXY, radius: u16) -> io::Result<()> { - draw_circle(self, center, radius) - } - - fn draw_circle_filled(&mut self, center: PixelsXY, radius: u16) -> io::Result<()> { - draw_circle_filled(self, center, radius) - } - - fn draw_line(&mut self, x1y1: PixelsXY, x2y2: PixelsXY) -> io::Result<()> { - if x1y1 == x2y2 { - // Paper over differences between platforms. On Linux, this would paint a single dot, - // but on Windows, it paints nothing. For consistency with drawing a circle of radius - // 0, and for consistency with the web interface, avoid painting anything here. - return Ok(()); - } - - self.canvas.draw_line(point_xy(x1y1), point_xy(x2y2)).map_err(string_error_to_io_error) - } - - fn draw_pixel(&mut self, xy: PixelsXY) -> io::Result<()> { - self.canvas.draw_point(point_xy(xy)).map_err(string_error_to_io_error) - } - - fn draw_rect(&mut self, xy: PixelsXY, size: SizeInPixels) -> io::Result<()> { - let rect = rect_origin_size(xy, size); - self.canvas.draw_rect(rect).map_err(string_error_to_io_error) - } - - fn draw_rect_filled(&mut self, xy: PixelsXY, size: SizeInPixels) -> io::Result<()> { - let rect = rect_origin_size(xy, size); - self.canvas.fill_rect(rect).map_err(string_error_to_io_error) + self.canvas.copy(&texture, None, rect).map_err(string_error_to_io_error)?; + drop(texture); + self.present_canvas() } } @@ -452,17 +318,20 @@ impl SharedContext { (*self.0).borrow_mut().event_pump.poll_event() } + fn get_info(&self) -> (LcdSize, usize) { + (*self.0).borrow().get_info() + } + + fn set_data(&mut self, x1y1: LcdXY, x2y2: LcdXY, data: &[u8]) -> io::Result<()> { + (*self.0).borrow_mut().set_data(x1y1, x2y2, data) + } + #[cfg(test)] fn push_event(&mut self, ev: Event) -> io::Result<()> { let event_ss = (*self.0).borrow().sdl.event().map_err(string_error_to_io_error)?; event_ss.push_event(ev).map_err(string_error_to_io_error) } - #[cfg(test)] - fn raw_write(&mut self, text: &str, xy: PixelsXY) -> io::Result<()> { - (*self.0).borrow_mut().write_text(xy, text) - } - #[cfg(test)] fn save_bmp(&self, path: &Path) -> io::Result<()> { let ctx = (*self.0).borrow_mut(); @@ -471,101 +340,15 @@ impl SharedContext { } } -impl RasterOps for SharedContext { - type ID = (Vec, SizeInPixels); - - fn get_info(&self) -> RasterInfo { - self.0.borrow().get_info() - } - - fn set_draw_color(&mut self, color: RGB) { - (*self.0).borrow_mut().set_draw_color(color) - } - - fn clear(&mut self) -> io::Result<()> { - (*self.0).borrow_mut().clear() - } - - fn present_canvas(&mut self) -> io::Result<()> { - (*self.0).borrow_mut().present_canvas() - } - - fn read_pixels(&mut self, xy: PixelsXY, size: SizeInPixels) -> io::Result { - (*self.0).borrow_mut().read_pixels(xy, size) - } - - fn put_pixels(&mut self, xy: PixelsXY, data: &Self::ID) -> io::Result<()> { - (*self.0).borrow_mut().put_pixels(xy, data) - } - - fn move_pixels( - &mut self, - x1y1: PixelsXY, - x2y2: PixelsXY, - size: SizeInPixels, - ) -> io::Result<()> { - (*self.0).borrow_mut().move_pixels(x1y1, x2y2, size) - } - - fn write_text(&mut self, xy: PixelsXY, text: &str) -> io::Result<()> { - (*self.0).borrow_mut().write_text(xy, text) - } - - fn draw_circle(&mut self, center: PixelsXY, radius: u16) -> io::Result<()> { - (*self.0).borrow_mut().draw_circle(center, radius) - } - - fn draw_circle_filled(&mut self, center: PixelsXY, radius: u16) -> io::Result<()> { - (*self.0).borrow_mut().draw_circle_filled(center, radius) - } - - fn draw_line(&mut self, x1y1: PixelsXY, x2y2: PixelsXY) -> io::Result<()> { - (*self.0).borrow_mut().draw_line(x1y1, x2y2) - } - - fn draw_pixel(&mut self, xy: PixelsXY) -> io::Result<()> { - (*self.0).borrow_mut().draw_pixel(xy) - } - - fn draw_rect(&mut self, xy: PixelsXY, size: SizeInPixels) -> io::Result<()> { - (*self.0).borrow_mut().draw_rect(xy, size) - } - - fn draw_rect_filled(&mut self, xy: PixelsXY, size: SizeInPixels) -> io::Result<()> { - (*self.0).borrow_mut().draw_rect_filled(xy, size) - } -} - /// Representation of requests that the console host can handle. pub(crate) enum Request { Exit, - Clear(ClearType), - SetColor(Option, Option), - EnterAlt, - HideCursor, - LeaveAlt, - Locate(CharsXY), - MoveWithinLine(i16), - Print(String), - ShowCursor, - SizeChars, - SizePixels, - Write(String), - DrawCircle(PixelsXY, u16), - DrawCircleFilled(PixelsXY, u16), - DrawLine(PixelsXY, PixelsXY), - DrawPixel(PixelsXY), - DrawRect(PixelsXY, PixelsXY), - DrawRectFilled(PixelsXY, PixelsXY), - SyncNow, - SetSync(bool), + SetData(LcdXY, LcdXY, Vec), #[cfg(test)] PushEvent(Event), #[cfg(test)] - RawWrite(String, PixelsXY), - #[cfg(test)] SaveBmp(PathBuf), } @@ -573,137 +356,106 @@ pub(crate) enum Request { #[derive(Debug)] pub(crate) enum Response { Empty(io::Result<()>), - SizeChars(CharsXY), - SizePixels(SizeInPixels), - SetSync(io::Result), -} - -/// Implementation of `InputOps` that should never be used. -// TODO(jmmv): This is necessary because the host-level console implementation requires these -// methods to be present but the input operations are handled in the client-side console. This -// might mean we need a better design. -struct NoopInputOps {} - -#[async_trait(?Send)] -impl InputOps for NoopInputOps { - async fn poll_key(&mut self) -> io::Result> { - unreachable!(); - } - - async fn read_key(&mut self) -> io::Result { - unreachable!(); - } + Info((LcdSize, usize)), } -/// Runs the main graphics loop. -#[allow(clippy::too_many_arguments)] -pub(crate) fn run( +/// Data necessary to host the SDL loop on the current thread. +pub(crate) struct SdlHost { resolution: Resolution, - default_fg_color: Option, - default_bg_color: Option, - font_path: PathBuf, - font_size: u16, + glyph_size: LcdSize, request_rx: Receiver, response_tx: SyncSender, on_key_tx: Sender, signals_tx: async_channel::Sender, -) { - let ctx = match Context::new(resolution, font_path, font_size) { - Ok(ctx) => ctx, - Err(e) => { - response_tx.send(Response::Empty(Err(e))).expect("Channel must be alive"); - return; - } - }; +} - let info = ctx.get_info(); - let mut ctx = SharedContext(Rc::from(RefCell::from(ctx))); - - let input = NoopInputOps {}; - let mut console = GraphicsConsole::new(input, ctx.clone(), default_fg_color, default_bg_color) - .expect("Console initialization must succeed"); - - response_tx.send(Response::Empty(Ok(()))).expect("Channel must be alive"); - - let mut budget = LOOP_POLL_BUDGET; - loop { - let mut did_something = false; - - match request_rx.try_recv() { - Ok(request) => { - let response = match request { - Request::Exit => break, - - Request::Clear(how) => Response::Empty(console.clear(how)), - Request::SetColor(fg, bg) => Response::Empty(console.set_color(fg, bg)), - Request::EnterAlt => Response::Empty(console.enter_alt()), - Request::HideCursor => Response::Empty(console.hide_cursor()), - Request::LeaveAlt => Response::Empty(console.leave_alt()), - Request::Locate(pos) => Response::Empty(console.locate(pos)), - Request::MoveWithinLine(off) => Response::Empty(console.move_within_line(off)), - Request::Print(text) => Response::Empty(console.print(&text)), - Request::ShowCursor => Response::Empty(console.show_cursor()), - Request::SizeChars => Response::SizeChars(info.size_chars), - Request::SizePixels => Response::SizePixels(info.size_pixels), - Request::Write(text) => Response::Empty(console.write(&text)), - Request::DrawCircle(center, radius) => { - Response::Empty(console.draw_circle(center, radius)) - } - Request::DrawCircleFilled(center, radius) => { - Response::Empty(console.draw_circle_filled(center, radius)) - } - Request::DrawLine(x1y1, x2y2) => Response::Empty(console.draw_line(x1y1, x2y2)), - Request::DrawPixel(xy) => Response::Empty(console.draw_pixel(xy)), - Request::DrawRect(x1y1, x2y2) => Response::Empty(console.draw_rect(x1y1, x2y2)), - Request::DrawRectFilled(x1y1, x2y2) => { - Response::Empty(console.draw_rect_filled(x1y1, x2y2)) - } - Request::SyncNow => Response::Empty(console.sync_now()), - Request::SetSync(enabled) => Response::SetSync(console.set_sync(enabled)), +impl SdlHost { + /// Creates a new SDL host that must be run on the desired thread. + pub(crate) fn new( + resolution: Resolution, + glyph_size: LcdSize, + request_rx: Receiver, + response_tx: SyncSender, + on_key_tx: Sender, + signals_tx: async_channel::Sender, + ) -> Self { + Self { resolution, glyph_size, request_rx, response_tx, on_key_tx, signals_tx } + } + + /// Runs the SDL graphics loop on the current thread. + pub(crate) fn run(self) { + let Self { resolution, glyph_size, request_rx, response_tx, on_key_tx, signals_tx } = self; + + let ctx = match Context::new(resolution, glyph_size) { + Ok(ctx) => ctx, + Err(e) => { + response_tx.send(Response::Empty(Err(e))).expect("Channel must be alive"); + return; + } + }; - #[cfg(test)] - Request::PushEvent(ev) => Response::Empty(ctx.push_event(ev)), + let mut ctx = SharedContext(Rc::from(RefCell::from(ctx))); - #[cfg(test)] - Request::RawWrite(text, start) => Response::Empty(ctx.raw_write(&text, start)), + response_tx.send(Response::Info(ctx.get_info())).expect("Channel must be alive"); - #[cfg(test)] - Request::SaveBmp(path) => Response::Empty(ctx.save_bmp(&path)), - }; + let mut budget = LOOP_POLL_BUDGET; + loop { + let mut did_something = false; - // TODO(jmmv): This is inefficient. Most of the operations above could probably - // benefit from _not_ returning a response at all, being asynchronous from the - // client perspective -- but the code is like this right now because it is adapted - // from a previous version that was synchronous. - response_tx.send(response).expect("Channel must be alive"); + match request_rx.try_recv() { + Ok(request) => { + let response = match request { + Request::Exit => break, - did_something = true; + Request::SetData(x1y1, x2y2, data) => { + Response::Empty(ctx.set_data(x1y1, x2y2, &data)) + } + + #[cfg(test)] + Request::PushEvent(ev) => Response::Empty(ctx.push_event(ev)), + + #[cfg(test)] + Request::SaveBmp(path) => Response::Empty(ctx.save_bmp(&path)), + }; + + // TODO(jmmv): This is inefficient. Most of the operations above could probably + // benefit from _not_ returning a response at all, being asynchronous from the + // client perspective -- but the code is like this right now because it is adapted + // from a previous version that was synchronous. + if response_tx.send(response).is_err() { + break; + } + + did_something = true; + } + Err(TryRecvError::Empty) => (), + Err(TryRecvError::Disconnected) => break, } - Err(TryRecvError::Empty) => (), - Err(TryRecvError::Disconnected) => panic!("Channel must be alive"), - } - if let Some(event) = ctx.poll_event() { - if let Some(key) = parse_event(event) { - if key == Key::Interrupt { - // signals_tx is an async channel because that's what the execution engine - // needs. This means that we cannot use a regular "send" here because we - // would need to await for it, which is a no-no because we are not in an - // async context. Using "try_send" should be sufficient though given that - // the channel we use is not bounded. - signals_tx.try_send(Signal::Break).expect("Channel must be alive and not full") + if let Some(event) = ctx.poll_event() { + if let Some(key) = parse_event(event) { + if key == Key::Interrupt { + // signals_tx is an async channel because that's what the execution engine + // needs. This means that we cannot use a regular "send" here because we + // would need to await for it, which is a no-no because we are not in an + // async context. Using "try_send" should be sufficient though given that + // the channel we use is not bounded. + signals_tx + .try_send(Signal::Break) + .expect("Channel must be alive and not full") + } + + if on_key_tx.send(key).is_err() { + break; + } } - on_key_tx.send(key).expect("Channel must be alive"); + did_something = true; } - did_something = true; - } - - if did_something { - budget = LOOP_POLL_BUDGET; - } else { - if budget > 0 { + if did_something { + budget = LOOP_POLL_BUDGET; + } else if budget > 0 { budget -= 1; } else { thread::sleep(Duration::from_millis(LOOP_DELAY_MS)); diff --git a/sdl/src/lib.rs b/sdl/src/lib.rs index 7c2ef928..d6eace31 100644 --- a/sdl/src/lib.rs +++ b/sdl/src/lib.rs @@ -17,57 +17,86 @@ //! SDL2-based graphics terminal emulator. use async_channel::Sender; +use console::{SdlConsole, SdlConsoleClient, SdlInput}; use endbasic_std::Signal; -use endbasic_std::console::{Console, ConsoleSpec, Resolution}; +use endbasic_std::console::{Console, ConsoleSpec, GraphicsConsole, Resolution}; +use endbasic_std::gfx::lcd::BufferedLcd; +use endbasic_std::gfx::lcd::fonts::{FONT_VT220, Font, Fonts}; use std::cell::RefCell; -use std::fs::File; -use std::io::{self, Write}; +use std::io; use std::num::NonZeroU32; -use std::path::PathBuf; use std::rc::Rc; -use tempfile::TempDir; mod console; -mod font; mod host; /// Default resolution to use when none is provided. const DEFAULT_RESOLUTION_PIXELS: (u32, u32) = (800, 600); -/// Default font to use when none is provided. -const DEFAULT_FONT_BYTES: &[u8] = include_bytes!("IBMPlexMono-Regular-6.0.0.ttf"); +/// Thread-safe console factory that can be moved to the interpreter thread. +pub struct ConsoleFactory { + client: SdlConsoleClient, + font: &'static Font, + default_fg_color: Option, + default_bg_color: Option, +} + +impl ConsoleFactory { + /// Connects this factory to a running SDL host loop and returns the finished console. + pub fn connect(self) -> io::Result>> { + let Self { client, font, default_fg_color, default_bg_color } = self; + let (console, on_key_rx) = client.connect()?; + let input = SdlInput(on_key_rx); + let rasops = BufferedLcd::new(console, font); + let console = GraphicsConsole::new(input, rasops, default_fg_color, default_bg_color)?; + Ok(Rc::from(RefCell::from(console))) + } +} + +/// SDL host loop that must run on the desired UI thread. +pub struct Host { + host: host::SdlHost, +} -/// Default font size. -const DEFAULT_FONT_SIZE: u16 = 16; +impl Host { + /// Runs the SDL host loop on the current thread until shutdown. + pub fn run(self) { + self.host.run() + } +} /// Converts a flat string error message to an `io::Error`. fn string_error_to_io_error(e: String) -> io::Error { io::Error::other(e) } -/// Context to maintain a font on disk temporarily. -pub(crate) struct TempFont { - dir: TempDir, -} +/// Parses the SDL console specification and prepares a split client/host pair. +pub fn prepare( + spec: &mut ConsoleSpec, + fonts: &Fonts, + signals_tx: Sender, +) -> io::Result<(ConsoleFactory, Host)> { + let resolution: Resolution = spec.take_keyed_flag("resolution")?.unwrap_or_else(|| { + let width = NonZeroU32::new(DEFAULT_RESOLUTION_PIXELS.0).unwrap(); + let height = NonZeroU32::new(DEFAULT_RESOLUTION_PIXELS.1).unwrap(); + Resolution::Windowed((width, height)) + }); -impl TempFont { - /// Gets an instance of the default font. - pub(crate) fn default_font() -> io::Result { - let dir = tempfile::tempdir()?; - let mut file = File::create(dir.path().join("font.ttf"))?; - file.write_all(DEFAULT_FONT_BYTES)?; - Ok(Self { dir }) - } + let default_fg_color = spec.take_keyed_flag::("fg_color")?; + let default_bg_color = spec.take_keyed_flag::("bg_color")?; - /// Gets the path to the temporary font. - pub(crate) fn path(&self) -> PathBuf { - self.dir.path().join("font.ttf") - } + let font_name = spec.take_keyed_flag_str("font").unwrap_or(FONT_VT220.name); + let font = fonts.get(font_name)?; + + let (client, host) = SdlConsole::prepare(resolution, font.glyph_size, signals_tx); + let factory = ConsoleFactory { client, font, default_fg_color, default_bg_color }; + Ok((factory, Host { host })) } /// Creates the graphical console based on the given `spec`. pub fn setup( spec: &mut ConsoleSpec, + fonts: &Fonts, signals_tx: Sender, ) -> io::Result>> { let resolution: Resolution = spec.take_keyed_flag("resolution")?.unwrap_or_else(|| { @@ -79,32 +108,13 @@ pub fn setup( let default_fg_color = spec.take_keyed_flag::("fg_color")?; let default_bg_color = spec.take_keyed_flag::("bg_color")?; - let font_path = spec.take_keyed_flag::("font_path")?; - - let font_size = spec.take_keyed_flag("font_size")?.unwrap_or(DEFAULT_FONT_SIZE); - - let console = match font_path { - None => { - let default_font = TempFont::default_font()?; - console::SdlConsole::new( - resolution, - default_fg_color, - default_bg_color, - default_font.path(), - font_size, - signals_tx, - )? - // The console has been created at this point, so it should be safe to drop - // default_font and clean up the on-disk file backing it up. - } - Some(font_path) => console::SdlConsole::new( - resolution, - default_fg_color, - default_bg_color, - font_path.to_owned(), - font_size, - signals_tx, - )?, - }; + let font_name = spec.take_keyed_flag_str("font").unwrap_or(FONT_VT220.name); + let font = fonts.get(font_name)?; + + let (console, on_key_rx) = SdlConsole::new(resolution, font.glyph_size, signals_tx)?; + let input = SdlInput(on_key_rx); + let rasops = BufferedLcd::new(console, font); + let console = GraphicsConsole::new(input, rasops, default_fg_color, default_bg_color)?; + Ok(Rc::from(RefCell::from(console))) } diff --git a/st7735s/src/lib.rs b/st7735s/src/lib.rs index 06b19645..58fe5fda 100644 --- a/st7735s/src/lib.rs +++ b/st7735s/src/lib.rs @@ -27,10 +27,9 @@ use async_channel::{Receiver, TryRecvError}; use async_trait::async_trait; use endbasic_std::console::graphics::InputOps; use endbasic_std::console::{ - CharsXY, ClearType, Console, ConsoleSpec, GraphicsConsole, Key, ParseError, PixelsXY, RGB, - SizeInPixels, + CharsXY, ClearType, Console, ConsoleSpec, GraphicsConsole, Key, PixelsXY, RGB, SizeInPixels, }; -use endbasic_std::gfx::lcd::fonts::Fonts; +use endbasic_std::gfx::lcd::fonts::{FONT_5X8, Fonts}; use endbasic_std::gfx::lcd::{BufferedLcd, Lcd, LcdSize, LcdXY, RGB565Pixel, to_xy_size}; use endbasic_std::gpio::{Pin, PinMode, Pins}; use endbasic_std::spi::{SpiBus, SpiMode}; @@ -485,20 +484,8 @@ where let default_fg_color = spec.take_keyed_flag::("fg_color")?; let default_bg_color = spec.take_keyed_flag::("bg_color")?; - let font_name = spec.take_keyed_flag_str("font").unwrap_or("5x8"); - let font = match fonts.get(font_name) { - Some(font) => font, - None => { - let mut valid = fonts.keys().copied().collect::>(); - valid.sort(); - return Err(ParseError(format!( - "Unknown font: {}; valid names are: {}", - font_name, - valid.join(", ") - )) - .into()); - } - }; + let font_name = spec.take_keyed_flag_str("font").unwrap_or(FONT_5X8.name); + let font = fonts.get(font_name)?; let pins = Arc::from(Mutex::from(pins)); let lcd = ST7735SLcd::new(pins.clone(), new_spi)?; diff --git a/std/src/gfx/lcd/fonts/font_16x16.rs b/std/src/gfx/lcd/fonts/font_16x16.rs index 142c22fd..0a5c474f 100644 --- a/std/src/gfx/lcd/fonts/font_16x16.rs +++ b/std/src/gfx/lcd/fonts/font_16x16.rs @@ -321,7 +321,7 @@ const DATA: &[u8] = &[ ]; /// Square 16x16 font. -pub(crate) const FONT_16X16: Font = Font { +pub const FONT_16X16: Font = Font { name: "16x16", glyph_size: LcdSize { width: WIDTH, height: HEIGHT }, stride: 2, diff --git a/std/src/gfx/lcd/fonts/font_5x8.rs b/std/src/gfx/lcd/fonts/font_5x8.rs index 88056cd4..e3ef107a 100644 --- a/std/src/gfx/lcd/fonts/font_5x8.rs +++ b/std/src/gfx/lcd/fonts/font_5x8.rs @@ -921,7 +921,7 @@ const DATA: &[u8] = &[ ]; /// Small font for tiny displays. -pub(crate) const FONT_5X8: Font = Font { +pub const FONT_5X8: Font = Font { name: "5x8", glyph_size: LcdSize { width: WIDTH, height: HEIGHT }, stride: 1, diff --git a/std/src/gfx/lcd/fonts/font_vt220.rs b/std/src/gfx/lcd/fonts/font_vt220.rs new file mode 100644 index 00000000..4d8dc1f1 --- /dev/null +++ b/std/src/gfx/lcd/fonts/font_vt220.rs @@ -0,0 +1,3888 @@ +// EndBASIC +// Copyright 2026 Julio Merino +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +/* + * Copyright (c) 1992, 1993, 1994 Hellmuth Michaelis and Joerg Wunsch + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by + * Hellmuth Michaelis and Joerg Wunsch + * 4. The name authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Translated into compiler and human readable for the Atari-TT port of + * NetBSD by Leo Weppelman. + * + * Reorganized and edited some chars to fit the iso-8859-1 fontset by + * Thomas Gerner + * + * Translated into wsfont format from sys/arch/atari/dev/font_8x16.c rev 1.2 + * by Izumi Tsutsui. + */ + +//! The VT220 font from NetBSD. + +use crate::gfx::lcd::LcdSize; +use crate::gfx::lcd::fonts::Font; + +/// Width of the font glyphs in pixels. +const WIDTH: usize = 8; + +/// Height of the font glyphs in pixels. +const HEIGHT: usize = 16; + +/// Raw font data table for ASCII characters. Use `glyph` to access. +const DATA: &[u8] = &[ + /* 0x20 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x21 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x3c, /* ..****.. */ + 0x3c, /* ..****.. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x22 */ + 0x00, /* ........ */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x24, /* ..*..*.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x23 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x6c, /* .**.**.. */ + 0x6c, /* .**.**.. */ + 0xfe, /* *******. */ + 0x6c, /* .**.**.. */ + 0x6c, /* .**.**.. */ + 0x6c, /* .**.**.. */ + 0xfe, /* *******. */ + 0x6c, /* .**.**.. */ + 0x6c, /* .**.**.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x24 */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc2, /* **....*. */ + 0xc0, /* **...... */ + 0x7c, /* .*****.. */ + 0x06, /* .....**. */ + 0x86, /* *....**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x25 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc2, /* **....*. */ + 0xc6, /* **...**. */ + 0x0c, /* ....**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0xc6, /* **...**. */ + 0x86, /* *....**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x26 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x6c, /* .**.**.. */ + 0x38, /* ..***... */ + 0x76, /* .***.**. */ + 0xdc, /* **.***.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x27 */ + 0x00, /* ........ */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x28 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x0c, /* ....**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x18, /* ...**... */ + 0x0c, /* ....**.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x29 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x30, /* ..**.... */ + 0x18, /* ...**... */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x2A */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x66, /* .**..**. */ + 0x3c, /* ..****.. */ + 0xff, /* ******** */ + 0x3c, /* ..****.. */ + 0x66, /* .**..**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x2B */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x7e, /* .******. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x2C */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x2D */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7e, /* .******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x2E */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x2F */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x02, /* ......*. */ + 0x06, /* .....**. */ + 0x0c, /* ....**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0xc0, /* **...... */ + 0x80, /* *....... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x30 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xce, /* **..***. */ + 0xde, /* **.****. */ + 0xf6, /* ****.**. */ + 0xe6, /* ***..**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x31 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x38, /* ..***... */ + 0x78, /* .****... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x7e, /* .******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x32 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0x06, /* .....**. */ + 0x0c, /* ....**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0xc0, /* **...... */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x33 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x3c, /* ..****.. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x34 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x0c, /* ....**.. */ + 0x1c, /* ...***.. */ + 0x3c, /* ..****.. */ + 0x6c, /* .**.**.. */ + 0xcc, /* **..**.. */ + 0xfe, /* *******. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x1e, /* ...****. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x35 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xfe, /* *******. */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xfc, /* ******.. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x36 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x60, /* .**..... */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xfc, /* ******.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x37 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xfe, /* *******. */ + 0xc6, /* **...**. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x0c, /* ....**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x38 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x39 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7e, /* .******. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x0c, /* ....**.. */ + 0x78, /* .****... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x3A */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x3B */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x3C */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x06, /* .....**. */ + 0x0c, /* ....**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x30, /* ..**.... */ + 0x18, /* ...**... */ + 0x0c, /* ....**.. */ + 0x06, /* .....**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x3D */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7e, /* .******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7e, /* .******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x3E */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x60, /* .**..... */ + 0x30, /* ..**.... */ + 0x18, /* ...**... */ + 0x0c, /* ....**.. */ + 0x06, /* .....**. */ + 0x0c, /* ....**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x3F */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x0c, /* ....**.. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x40 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xde, /* **.****. */ + 0xde, /* **.****. */ + 0xde, /* **.****. */ + 0xdc, /* **.***.. */ + 0xc0, /* **...... */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x41 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x10, /* ...*.... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x42 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xfc, /* ******.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x7c, /* .*****.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0xfc, /* ******.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x43 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x3c, /* ..****.. */ + 0x66, /* .**..**. */ + 0xc2, /* **....*. */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc2, /* **....*. */ + 0x66, /* .**..**. */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x44 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xf8, /* *****... */ + 0x6c, /* .**.**.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x6c, /* .**.**.. */ + 0xf8, /* *****... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x45 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xfe, /* *******. */ + 0x66, /* .**..**. */ + 0x62, /* .**...*. */ + 0x68, /* .**.*... */ + 0x78, /* .****... */ + 0x68, /* .**.*... */ + 0x60, /* .**..... */ + 0x62, /* .**...*. */ + 0x66, /* .**..**. */ + 0xfe, /* *******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x46 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xfe, /* *******. */ + 0x66, /* .**..**. */ + 0x62, /* .**...*. */ + 0x68, /* .**.*... */ + 0x78, /* .****... */ + 0x68, /* .**.*... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0xf0, /* ****.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x47 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x3c, /* ..****.. */ + 0x66, /* .**..**. */ + 0xc2, /* **....*. */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xde, /* **.****. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x66, /* .**..**. */ + 0x3a, /* ..***.*. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x48 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x49 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x3c, /* ..****.. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x4A */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x1e, /* ...****. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x78, /* .****... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x4B */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xe6, /* ***..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x6c, /* .**.**.. */ + 0x78, /* .****... */ + 0x78, /* .****... */ + 0x6c, /* .**.**.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0xe6, /* ***..**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x4C */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xf0, /* ****.... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x62, /* .**...*. */ + 0x66, /* .**..**. */ + 0xfe, /* *******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x4D */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xee, /* ***.***. */ + 0xfe, /* *******. */ + 0xfe, /* *******. */ + 0xd6, /* **.*.**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x4E */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xe6, /* ***..**. */ + 0xf6, /* ****.**. */ + 0xfe, /* *******. */ + 0xde, /* **.****. */ + 0xce, /* **..***. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x4F */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x50 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xfc, /* ******.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x7c, /* .*****.. */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0xf0, /* ****.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x51 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xd6, /* **.*.**. */ + 0xde, /* **.****. */ + 0x7c, /* .*****.. */ + 0x0c, /* ....**.. */ + 0x0e, /* ....***. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x52 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xfc, /* ******.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x7c, /* .*****.. */ + 0x6c, /* .**.**.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0xe6, /* ***..**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x53 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x60, /* .**..... */ + 0x38, /* ..***... */ + 0x0c, /* ....**.. */ + 0x06, /* .....**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x54 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7e, /* .******. */ + 0x7e, /* .******. */ + 0x5a, /* .*.**.*. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x55 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x56 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x6c, /* .**.**.. */ + 0x38, /* ..***... */ + 0x10, /* ...*.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x57 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xd6, /* **.*.**. */ + 0xd6, /* **.*.**. */ + 0xd6, /* **.*.**. */ + 0xfe, /* *******. */ + 0xee, /* ***.***. */ + 0x6c, /* .**.**.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x58 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x6c, /* .**.**.. */ + 0x7c, /* .*****.. */ + 0x38, /* ..***... */ + 0x38, /* ..***... */ + 0x7c, /* .*****.. */ + 0x6c, /* .**.**.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x59 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x3c, /* ..****.. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x5A */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xfe, /* *******. */ + 0xc6, /* **...**. */ + 0x86, /* *....**. */ + 0x0c, /* ....**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0xc2, /* **....*. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x5B */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x3c, /* ..****.. */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x5C */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x80, /* *....... */ + 0xc0, /* **...... */ + 0xe0, /* ***..... */ + 0x70, /* .***.... */ + 0x38, /* ..***... */ + 0x1c, /* ...***.. */ + 0x0e, /* ....***. */ + 0x06, /* .....**. */ + 0x02, /* ......*. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x5D */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x3c, /* ..****.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x5E */ + 0x10, /* ...*.... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x5F */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xff, /* ******** */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x60 */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x61 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x78, /* .****... */ + 0x0c, /* ....**.. */ + 0x7c, /* .*****.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x62 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xe0, /* ***..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x78, /* .****... */ + 0x6c, /* .**.**.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x63 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x64 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x1c, /* ...***.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x3c, /* ..****.. */ + 0x6c, /* .**.**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x65 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x66 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x64, /* .**..*.. */ + 0x60, /* .**..... */ + 0xf0, /* ****.... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0xf0, /* ****.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x67 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x76, /* .***.**. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x7c, /* .*****.. */ + 0x0c, /* ....**.. */ + 0xcc, /* **..**.. */ + 0x78, /* .****... */ + 0x00, /* ........ */ + /* 0x68 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xe0, /* ***..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x6c, /* .**.**.. */ + 0x76, /* .***.**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0xe6, /* ***..**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x69 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x6A */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x00, /* ........ */ + 0x0e, /* ....***. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + /* 0x6B */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xe0, /* ***..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x66, /* .**..**. */ + 0x6c, /* .**.**.. */ + 0x78, /* .****... */ + 0x78, /* .****... */ + 0x6c, /* .**.**.. */ + 0x66, /* .**..**. */ + 0xe6, /* ***..**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x6C */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x6D */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xec, /* ***.**.. */ + 0xfe, /* *******. */ + 0xd6, /* **.*.**. */ + 0xd6, /* **.*.**. */ + 0xd6, /* **.*.**. */ + 0xd6, /* **.*.**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x6E */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xdc, /* **.***.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x6F */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x70 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xdc, /* **.***.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x7c, /* .*****.. */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0xf0, /* ****.... */ + 0x00, /* ........ */ + /* 0x71 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x76, /* .***.**. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x7c, /* .*****.. */ + 0x0c, /* ....**.. */ + 0x0c, /* ....**.. */ + 0x1e, /* ...****. */ + 0x00, /* ........ */ + /* 0x72 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xdc, /* **.***.. */ + 0x76, /* .***.**. */ + 0x66, /* .**..**. */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0xf0, /* ****.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x73 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0x60, /* .**..... */ + 0x38, /* ..***... */ + 0x0c, /* ....**.. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x74 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x10, /* ...*.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0xfc, /* ******.. */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x36, /* ..**.**. */ + 0x1c, /* ...***.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x75 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x76 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x6c, /* .**.**.. */ + 0x38, /* ..***... */ + 0x10, /* ...*.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x77 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xd6, /* **.*.**. */ + 0xd6, /* **.*.**. */ + 0xd6, /* **.*.**. */ + 0xfe, /* *******. */ + 0x6c, /* .**.**.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x78 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0x6c, /* .**.**.. */ + 0x38, /* ..***... */ + 0x38, /* ..***... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x79 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7e, /* .******. */ + 0x06, /* .....**. */ + 0x0c, /* ....**.. */ + 0xf8, /* *****... */ + 0x00, /* ........ */ + /* 0x7A */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xfe, /* *******. */ + 0xcc, /* **..**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x7B */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x0e, /* ....***. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x70, /* .***.... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x0e, /* ....***. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x7C */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x7D */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x70, /* .***.... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x0e, /* ....***. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x70, /* .***.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x7E */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x76, /* .***.**. */ + 0xdc, /* **.***.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x7F */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x10, /* ...*.... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x80 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x81 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x82 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x83 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x84 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x85 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x86 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x87 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x88 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x89 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x8A */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x8B */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x8C */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x8D */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x8E */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x8F */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x90 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x91 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x92 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x93 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x94 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x95 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x96 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x97 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x98 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x99 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x9A */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x9B */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x9C */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x9D */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x9E */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x9F */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xA0 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xA1 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x3c, /* ..****.. */ + 0x3c, /* ..****.. */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xA2 */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x66, /* .**..**. */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x66, /* .**..**. */ + 0x3c, /* ..****.. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xA3 */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x64, /* .**..*.. */ + 0x60, /* .**..... */ + 0xf0, /* ****.... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0xe6, /* ***..**. */ + 0xfc, /* ******.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xA4 */ + 0xc3, /* **....** */ + 0x3c, /* ..****.. */ + 0x66, /* .**..**. */ + 0x42, /* .*....*. */ + 0x66, /* .**..**. */ + 0x3c, /* ..****.. */ + 0xc3, /* **....** */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xA5 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x3c, /* ..****.. */ + 0x18, /* ...**... */ + 0x7e, /* .******. */ + 0x18, /* ...**... */ + 0x7e, /* .******. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xA6 */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + /* 0xA7 */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0x60, /* .**..... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x6c, /* .**.**.. */ + 0x38, /* ..***... */ + 0x0c, /* ....**.. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xA8 */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xA9 */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0x82, /* *.....*. */ + 0x9a, /* *..**.*. */ + 0xa6, /* *.*..**. */ + 0xa2, /* *.*...*. */ + 0xa6, /* *.*..**. */ + 0x9a, /* *..**.*. */ + 0x82, /* *.....*. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xAA */ + 0x00, /* ........ */ + 0x3c, /* ..****.. */ + 0x6c, /* .**.**.. */ + 0x6c, /* .**.**.. */ + 0x3e, /* ..*****. */ + 0x00, /* ........ */ + 0x7e, /* .******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xAB */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x36, /* ..**.**. */ + 0x6c, /* .**.**.. */ + 0xd8, /* **.**... */ + 0x6c, /* .**.**.. */ + 0x36, /* ..**.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xAC */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xfe, /* *******. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xAD */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xfe, /* *******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xAE */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0x82, /* *.....*. */ + 0xba, /* *.***.*. */ + 0xa6, /* *.*..**. */ + 0xba, /* *.***.*. */ + 0xaa, /* *.*.*.*. */ + 0xa6, /* *.*..**. */ + 0x82, /* *.....*. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xAF */ + 0x00, /* ........ */ + 0xfe, /* *******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xB0 */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x6c, /* .**.**.. */ + 0x38, /* ..***... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xB1 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x7e, /* .******. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xff, /* ******** */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xB2 */ + 0x00, /* ........ */ + 0x70, /* .***.... */ + 0xd8, /* **.**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0xc8, /* **..*... */ + 0xf8, /* *****... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xB3 */ + 0x00, /* ........ */ + 0x70, /* .***.... */ + 0xd8, /* **.**... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0xd8, /* **.**... */ + 0x70, /* .***.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xB4 */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xB5 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x7c, /* .*****.. */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0xc0, /* **...... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xB6 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7f, /* .******* */ + 0xdb, /* **.**.** */ + 0xdb, /* **.**.** */ + 0xdb, /* **.**.** */ + 0x7b, /* .****.** */ + 0x1b, /* ...**.** */ + 0x1b, /* ...**.** */ + 0x1b, /* ...**.** */ + 0x1b, /* ...**.** */ + 0x1b, /* ...**.** */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xB7 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xB8 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xB9 */ + 0x00, /* ........ */ + 0x30, /* ..**.... */ + 0x70, /* .***.... */ + 0xf0, /* ****.... */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x78, /* .****... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xBA */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x6c, /* .**.**.. */ + 0x38, /* ..***... */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xBB */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xd8, /* **.**... */ + 0x6c, /* .**.**.. */ + 0x36, /* ..**.**. */ + 0x6c, /* .**.**.. */ + 0xd8, /* **.**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xBC */ + 0x00, /* ........ */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc2, /* **....*. */ + 0xc6, /* **...**. */ + 0xcc, /* **..**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x66, /* .**..**. */ + 0xce, /* **..***. */ + 0x9e, /* *..****. */ + 0x3e, /* ..*****. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xBD */ + 0x00, /* ........ */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc2, /* **....*. */ + 0xc6, /* **...**. */ + 0xcc, /* **..**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0xdc, /* **.***.. */ + 0x86, /* *....**. */ + 0x0c, /* ....**.. */ + 0x18, /* ...**... */ + 0x3e, /* ..*****. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xBE */ + 0x00, /* ........ */ + 0xc0, /* **...... */ + 0x60, /* .**..... */ + 0xc2, /* **....*. */ + 0x66, /* .**..**. */ + 0xcc, /* **..**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x66, /* .**..**. */ + 0xce, /* **..***. */ + 0x9e, /* *..****. */ + 0x3e, /* ..*****. */ + 0x06, /* .....**. */ + 0x06, /* .....**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xBF */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x00, /* ........ */ + 0x30, /* ..**.... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0xc0, /* **...... */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xC0 */ + 0x18, /* ...**... */ + 0x0c, /* ....**.. */ + 0x06, /* .....**. */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xC1 */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xC2 */ + 0x10, /* ...*.... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xC3 */ + 0x76, /* .***.**. */ + 0xdc, /* **.***.. */ + 0x00, /* ........ */ + 0x10, /* ...*.... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xC4 */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x10, /* ...*.... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xC5 */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x38, /* ..***... */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xC6 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x3e, /* ..*****. */ + 0x6c, /* .**.**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xfe, /* *******. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xce, /* **..***. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xC7 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x3c, /* ..****.. */ + 0x66, /* .**..**. */ + 0xc2, /* **....*. */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc2, /* **....*. */ + 0x66, /* .**..**. */ + 0x3c, /* ..****.. */ + 0x0c, /* ....**.. */ + 0x06, /* .....**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xC8 */ + 0x18, /* ...**... */ + 0x0c, /* ....**.. */ + 0x06, /* .....**. */ + 0x00, /* ........ */ + 0xfe, /* *******. */ + 0x66, /* .**..**. */ + 0x60, /* .**..... */ + 0x7c, /* .*****.. */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x66, /* .**..**. */ + 0xfe, /* *******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xC9 */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0xfe, /* *******. */ + 0x66, /* .**..**. */ + 0x60, /* .**..... */ + 0x7c, /* .*****.. */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x66, /* .**..**. */ + 0xfe, /* *******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xCA */ + 0x10, /* ...*.... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x00, /* ........ */ + 0xfe, /* *******. */ + 0x66, /* .**..**. */ + 0x60, /* .**..... */ + 0x7c, /* .*****.. */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x66, /* .**..**. */ + 0xfe, /* *******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xCB */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0xfe, /* *******. */ + 0x66, /* .**..**. */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x7c, /* .*****.. */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x66, /* .**..**. */ + 0xfe, /* *******. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xCC */ + 0x18, /* ...**... */ + 0x0c, /* ....**.. */ + 0x06, /* .....**. */ + 0x00, /* ........ */ + 0x3c, /* ..****.. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xCD */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0x3c, /* ..****.. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xCE */ + 0x10, /* ...*.... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x00, /* ........ */ + 0x3c, /* ..****.. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xCF */ + 0x00, /* ........ */ + 0x66, /* .**..**. */ + 0x00, /* ........ */ + 0x3c, /* ..****.. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xD0 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xf8, /* *****... */ + 0x6c, /* .**.**.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0xf6, /* ****.**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x6c, /* .**.**.. */ + 0xf8, /* *****... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xD1 */ + 0x76, /* .***.**. */ + 0xdc, /* **.***.. */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xe6, /* ***..**. */ + 0xf6, /* ****.**. */ + 0xfe, /* *******. */ + 0xde, /* **.****. */ + 0xce, /* **..***. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xD2 */ + 0x18, /* ...**... */ + 0x0c, /* ....**.. */ + 0x06, /* .....**. */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xD3 */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xD4 */ + 0x10, /* ...*.... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xD5 */ + 0x76, /* .***.**. */ + 0xdc, /* **.***.. */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xD6 */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xD7 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0x6c, /* .**.**.. */ + 0x38, /* ..***... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xD8 */ + 0x00, /* ........ */ + 0x06, /* .....**. */ + 0x7e, /* .******. */ + 0xce, /* **..***. */ + 0xce, /* **..***. */ + 0xce, /* **..***. */ + 0xd6, /* **.*.**. */ + 0xd6, /* **.*.**. */ + 0xe6, /* ***..**. */ + 0xe6, /* ***..**. */ + 0xe6, /* ***..**. */ + 0xfc, /* ******.. */ + 0xc0, /* **...... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xD9 */ + 0x18, /* ...**... */ + 0x0c, /* ....**.. */ + 0x06, /* .....**. */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xDA */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xDB */ + 0x10, /* ...*.... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xDC */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xDD */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x3c, /* ..****.. */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xDE */ + 0x00, /* ........ */ + 0xf0, /* ****.... */ + 0x60, /* .**..... */ + 0x7c, /* .*****.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x7c, /* .*****.. */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0xf0, /* ****.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xDF */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x78, /* .****... */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xd8, /* **.**... */ + 0xcc, /* **..**.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xcc, /* **..**.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xE0 */ + 0x00, /* ........ */ + 0x60, /* .**..... */ + 0x30, /* ..**.... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x78, /* .****... */ + 0x0c, /* ....**.. */ + 0x7c, /* .*****.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xE1 */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0x78, /* .****... */ + 0x0c, /* ....**.. */ + 0x7c, /* .*****.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xE2 */ + 0x00, /* ........ */ + 0x10, /* ...*.... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x00, /* ........ */ + 0x78, /* .****... */ + 0x0c, /* ....**.. */ + 0x7c, /* .*****.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xE3 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x76, /* .***.**. */ + 0xdc, /* **.***.. */ + 0x00, /* ........ */ + 0x78, /* .****... */ + 0x0c, /* ....**.. */ + 0x7c, /* .*****.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xE4 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xcc, /* **..**.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x78, /* .****... */ + 0x0c, /* ....**.. */ + 0x7c, /* .*****.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xE5 */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x38, /* ..***... */ + 0x00, /* ........ */ + 0x78, /* .****... */ + 0x0c, /* ....**.. */ + 0x7c, /* .*****.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xE6 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x6c, /* .**.**.. */ + 0xfe, /* *******. */ + 0xb2, /* *.**..*. */ + 0x32, /* ..**..*. */ + 0x7e, /* .******. */ + 0xd8, /* **.**... */ + 0xd8, /* **.**... */ + 0x6e, /* .**.***. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xE7 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x3c, /* ..****.. */ + 0x66, /* .**..**. */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0x66, /* .**..**. */ + 0x3c, /* ..****.. */ + 0x0c, /* ....**.. */ + 0x06, /* .....**. */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xE8 */ + 0x00, /* ........ */ + 0x60, /* .**..... */ + 0x30, /* ..**.... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xE9 */ + 0x00, /* ........ */ + 0x0c, /* ....**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xEA */ + 0x00, /* ........ */ + 0x10, /* ...*.... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xEB */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xfe, /* *******. */ + 0xc0, /* **...... */ + 0xc0, /* **...... */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xEC */ + 0x00, /* ........ */ + 0x60, /* .**..... */ + 0x30, /* ..**.... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xED */ + 0x00, /* ........ */ + 0x0c, /* ....**.. */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xEE */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x66, /* .**..**. */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xEF */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x66, /* .**..**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x38, /* ..***... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x3c, /* ..****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xF0 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x3e, /* ..*****. */ + 0x30, /* ..**.... */ + 0x18, /* ...**... */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xF1 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x76, /* .***.**. */ + 0xdc, /* **.***.. */ + 0x00, /* ........ */ + 0xdc, /* **.***.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xF2 */ + 0x00, /* ........ */ + 0x60, /* .**..... */ + 0x30, /* ..**.... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xF3 */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xF4 */ + 0x00, /* ........ */ + 0x10, /* ...*.... */ + 0x38, /* ..***... */ + 0x6c, /* .**.**.. */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xF5 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x76, /* .***.**. */ + 0xdc, /* **.***.. */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xF6 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .*****.. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7c, /* .*****.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xF7 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x7e, /* .******. */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xF8 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x06, /* .....**. */ + 0x7e, /* .******. */ + 0xce, /* **..***. */ + 0xce, /* **..***. */ + 0xd6, /* **.*.**. */ + 0xe6, /* ***..**. */ + 0xe6, /* ***..**. */ + 0xfc, /* ******.. */ + 0xc0, /* **...... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xF9 */ + 0x00, /* ........ */ + 0x60, /* .**..... */ + 0x30, /* ..**.... */ + 0x18, /* ...**... */ + 0x00, /* ........ */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xFA */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xFB */ + 0x00, /* ........ */ + 0x30, /* ..**.... */ + 0x78, /* .****... */ + 0xcc, /* **..**.. */ + 0x00, /* ........ */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xFC */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xcc, /* **..**.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0xcc, /* **..**.. */ + 0x76, /* .***.**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0xFD */ + 0x00, /* ........ */ + 0x18, /* ...**... */ + 0x30, /* ..**.... */ + 0x60, /* .**..... */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7e, /* .******. */ + 0x06, /* .....**. */ + 0x0c, /* ....**.. */ + 0x78, /* .****... */ + 0x00, /* ........ */ + /* 0xFE */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xf0, /* ****.... */ + 0x60, /* .**..... */ + 0x7c, /* .*****.. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x66, /* .**..**. */ + 0x7c, /* .*****.. */ + 0x60, /* .**..... */ + 0x60, /* .**..... */ + 0xf0, /* ****.... */ + 0x00, /* ........ */ + /* 0xFF */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0xc6, /* **...**. */ + 0x7e, /* .******. */ + 0x06, /* .....**. */ + 0x0c, /* ....**.. */ + 0x78, /* .****... */ + 0x00, /* ........ */ +]; + +/// The VT220 font from NetBSD. +pub const FONT_VT220: Font = Font { + name: "vt220", + glyph_size: LcdSize { width: WIDTH, height: HEIGHT }, + stride: 1, + data: DATA, +}; diff --git a/std/src/gfx/lcd/fonts/mod.rs b/std/src/gfx/lcd/fonts/mod.rs index 537532fb..d20adf7a 100644 --- a/std/src/gfx/lcd/fonts/mod.rs +++ b/std/src/gfx/lcd/fonts/mod.rs @@ -17,12 +17,16 @@ use crate::gfx::lcd::LcdSize; use std::collections::HashMap; +use std::io; mod font_5x8; -pub(crate) use font_5x8::FONT_5X8; +pub use font_5x8::FONT_5X8; mod font_16x16; -pub(crate) use font_16x16::FONT_16X16; +pub use font_16x16::FONT_16X16; + +mod font_vt220; +pub use font_vt220::FONT_VT220; /// Representation of a font. pub struct Font { @@ -58,14 +62,32 @@ impl Font { } /// Registry of all available fonts. -pub type Fonts = HashMap<&'static str, &'static Font>; - -/// Obtains a mapping of all available fonts. -pub fn all_fonts() -> Fonts { - let mut fonts = Fonts::default(); - fonts.insert(FONT_5X8.name, &FONT_5X8); - fonts.insert(FONT_16X16.name, &FONT_16X16); - fonts +pub struct Fonts(HashMap<&'static str, &'static Font>); + +impl Fonts { + /// Obtains a mapping of all available fonts. + pub fn all() -> Self { + let mut fonts = HashMap::default(); + fonts.insert(FONT_5X8.name, &FONT_5X8); + fonts.insert(FONT_16X16.name, &FONT_16X16); + fonts.insert(FONT_VT220.name, &FONT_VT220); + Self(fonts) + } + + /// Gets a font by `name`, ensuring that it's present. + pub fn get(&self, name: &str) -> io::Result<&'static Font> { + match self.0.get(name) { + Some(font) => Ok(*font), + None => { + let mut valid = self.0.keys().copied().collect::>(); + valid.sort(); + Err(io::Error::new( + io::ErrorKind::InvalidInput, + format!("Unknown font: {}; valid names are: {}", name, valid.join(", ")), + )) + } + } + } } #[cfg(test)] diff --git a/std/src/gfx/lcd/mod.rs b/std/src/gfx/lcd/mod.rs index 90a093d2..c9259583 100644 --- a/std/src/gfx/lcd/mod.rs +++ b/std/src/gfx/lcd/mod.rs @@ -68,8 +68,8 @@ pub struct LcdXY { } /// Represents a size that fits in the LCD space. -#[derive(Clone, Copy)] -#[cfg_attr(test, derive(Debug, PartialEq))] +#[derive(Clone, Copy, Debug)] +#[cfg_attr(test, derive(PartialEq))] pub struct LcdSize { /// The width. pub width: usize,