Merge pull request 'Cache rendered chars, experimental null char handling' (#4) from next into main
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Rust / build (push) Successful in 6m28s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Rust / build (push) Successful in 6m28s
				
			Reviewed-on: #4
This commit is contained in:
		
						commit
						75a0ae7a59
					
				
					 10 changed files with 116 additions and 77 deletions
				
			
		
							
								
								
									
										46
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										46
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							|  | @ -4,9 +4,9 @@ version = 3 | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "ab_glyph" | name = "ab_glyph" | ||||||
| version = "0.2.29" | version = "0.2.30" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" | checksum = "1e0f4f6fbdc5ee39f2ede9f5f3ec79477271a6d6a2baff22310d51736bda6cea" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "ab_glyph_rasterizer", |  "ab_glyph_rasterizer", | ||||||
|  "owned_ttf_parser", |  "owned_ttf_parser", | ||||||
|  | @ -14,9 +14,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "ab_glyph_rasterizer" | name = "ab_glyph_rasterizer" | ||||||
| version = "0.1.8" | version = "0.1.9" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" | checksum = "b2187590a23ab1e3df8681afdf0987c48504d80291f002fcdb651f0ef5e25169" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "adler2" | name = "adler2" | ||||||
|  | @ -265,9 +265,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "cc" | name = "cc" | ||||||
| version = "1.2.27" | version = "1.2.29" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" | checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "jobserver", |  "jobserver", | ||||||
|  "libc", |  "libc", | ||||||
|  | @ -294,9 +294,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "clap" | name = "clap" | ||||||
| version = "4.5.40" | version = "4.5.41" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" | checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "clap_builder", |  "clap_builder", | ||||||
|  "clap_derive", |  "clap_derive", | ||||||
|  | @ -304,9 +304,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "clap_builder" | name = "clap_builder" | ||||||
| version = "4.5.40" | version = "4.5.41" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" | checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "anstream", |  "anstream", | ||||||
|  "anstyle", |  "anstyle", | ||||||
|  | @ -316,9 +316,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "clap_derive" | name = "clap_derive" | ||||||
| version = "4.5.40" | version = "4.5.41" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" | checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "heck", |  "heck", | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  | @ -760,17 +760,6 @@ dependencies = [ | ||||||
|  "hashbrown", |  "hashbrown", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] |  | ||||||
| name = "inherent" |  | ||||||
| version = "1.0.12" |  | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" |  | ||||||
| checksum = "6c38228f24186d9cc68c729accb4d413be9eaed6ad07ff79e0270d9e56f3de13" |  | ||||||
| dependencies = [ |  | ||||||
|  "proc-macro2", |  | ||||||
|  "quote", |  | ||||||
|  "syn", |  | ||||||
| ] |  | ||||||
| 
 |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "is_terminal_polyfill" | name = "is_terminal_polyfill" | ||||||
| version = "1.70.1" | version = "1.70.1" | ||||||
|  | @ -1521,14 +1510,13 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "servicepoint" | name = "servicepoint" | ||||||
| version = "0.15.2" | version = "0.16.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "7d1e88713031e003dc3ee708dbb282e36714eee466a12d311d0e2e24c61c7118" | checksum = "9b04582e916474f1bc1605cad3773262c425d9062b487e49a0df59662f2cca8d" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "bitvec", |  "bitvec", | ||||||
|  "bzip2", |  "bzip2", | ||||||
|  "flate2", |  "flate2", | ||||||
|  "inherent", |  | ||||||
|  "log", |  "log", | ||||||
|  "once_cell", |  "once_cell", | ||||||
|  "rust-lzma", |  "rust-lzma", | ||||||
|  | @ -1538,7 +1526,7 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "servicepoint-simulator" | name = "servicepoint-simulator" | ||||||
| version = "0.2.3" | version = "0.2.4" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "clap", |  "clap", | ||||||
|  "env_logger", |  "env_logger", | ||||||
|  | @ -2399,9 +2387,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "winnow" | name = "winnow" | ||||||
| version = "0.7.11" | version = "0.7.12" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" | checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "memchr", |  "memchr", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| [package] | [package] | ||||||
| name = "servicepoint-simulator" | name = "servicepoint-simulator" | ||||||
| version = "0.2.3" | version = "0.2.4" | ||||||
| edition = "2021" | edition = "2021" | ||||||
| publish = true | publish = true | ||||||
| license = "GPL-3.0-or-later" | license = "GPL-3.0-or-later" | ||||||
|  | @ -19,9 +19,6 @@ env_logger = "0.11" | ||||||
| clap = { version = "4.5", features = ["derive"] } | clap = { version = "4.5", features = ["derive"] } | ||||||
| thiserror = "2.0" | thiserror = "2.0" | ||||||
| 
 | 
 | ||||||
| # package parsing |  | ||||||
| servicepoint = { features = ["all_compressions"], version = "0.15.2" } |  | ||||||
| 
 |  | ||||||
| # font rendering | # font rendering | ||||||
| font-kit = "0.14.2" | font-kit = "0.14.2" | ||||||
| # I should not need this as a direct dependency, but then I cannot spell the types needed to use font-kit... | # I should not need this as a direct dependency, but then I cannot spell the types needed to use font-kit... | ||||||
|  | @ -32,6 +29,10 @@ winit = "0.30" | ||||||
| # for drawing pixels onto the surface of the window | # for drawing pixels onto the surface of the window | ||||||
| softbuffer = "0.4.6" | softbuffer = "0.4.6" | ||||||
| 
 | 
 | ||||||
|  | [dependencies.servicepoint] | ||||||
|  | version = "0.16.0" | ||||||
|  | features = ["all_compressions"] | ||||||
|  | 
 | ||||||
| [profile.release] | [profile.release] | ||||||
| lto = true          # Enable link-time optimization | lto = true          # Enable link-time optimization | ||||||
| codegen-units = 1   # Reduce number of codegen units to increase optimizations | codegen-units = 1   # Reduce number of codegen units to increase optimizations | ||||||
|  |  | ||||||
							
								
								
									
										26
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								README.md
									
										
									
									
									
								
							|  | @ -42,14 +42,24 @@ Make sure to run a release build, because a debug build _way_ slower. | ||||||
| Usage: servicepoint-simulator [OPTIONS] | Usage: servicepoint-simulator [OPTIONS] | ||||||
| 
 | 
 | ||||||
| Options: | Options: | ||||||
|       --bind <BIND>  address and port to bind to [default: 0.0.0.0:2342] |       --bind <BIND> | ||||||
|   -f, --font <FONT>  The name of the font family to use. This defaults to the system monospace font. |           address and port to bind to [default: 0.0.0.0:2342] | ||||||
|   -s, --spacers      add spacers between tile rows to simulate gaps in real display |   -f, --font <FONT> | ||||||
|   -r, --red          Use the red color channel |           The name of the font family to use. This defaults to the system monospace font. | ||||||
|   -g, --green        Use the green color channel |   -s, --spacers | ||||||
|   -b, --blue         Use the blue color channel |           add spacers between tile rows to simulate gaps in real display | ||||||
|   -v, --verbose      Set default log level lower. You can also change this via the RUST_LOG environment variable. |   -r, --red | ||||||
|   -h, --help         Print help |           Use the red color channel | ||||||
|  |   -g, --green | ||||||
|  |           Use the green color channel | ||||||
|  |   -b, --blue | ||||||
|  |           Use the blue color channel | ||||||
|  |   -v, --verbose | ||||||
|  |           Set default log level lower. You can also change this via the RUST_LOG environment variable. | ||||||
|  |       --experimental-null-char-handling | ||||||
|  |           When receiving a null byte as a char in the CharGridCommand, do not overwrite any pixels instead of clearing all pixels. | ||||||
|  |   -h, --help | ||||||
|  |           Print help | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| See [env_logger](https://docs.rs/env_logger/latest/env_logger/) to configure logging. | See [env_logger](https://docs.rs/env_logger/latest/env_logger/) to configure logging. | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								flake.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										12
									
								
								flake.lock
									
										
									
										generated
									
									
									
								
							|  | @ -7,11 +7,11 @@ | ||||||
|         ] |         ] | ||||||
|       }, |       }, | ||||||
|       "locked": { |       "locked": { | ||||||
|         "lastModified": 1745925850, |         "lastModified": 1752249768, | ||||||
|         "narHash": "sha256-cyAAMal0aPrlb1NgzMxZqeN1mAJ2pJseDhm2m6Um8T0=", |         "narHash": "sha256-wKqMvhTqMgTKM/CdTH/ihq9eLZM95qpU0FG7cvTBFJg=", | ||||||
|         "owner": "nix-community", |         "owner": "nix-community", | ||||||
|         "repo": "naersk", |         "repo": "naersk", | ||||||
|         "rev": "38bc60bbc157ae266d4a0c96671c6c742ee17a5f", |         "rev": "35aa63738857c40f98ecb04db52887d664836e74", | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       }, |       }, | ||||||
|       "original": { |       "original": { | ||||||
|  | @ -37,11 +37,11 @@ | ||||||
|     }, |     }, | ||||||
|     "nixpkgs": { |     "nixpkgs": { | ||||||
|       "locked": { |       "locked": { | ||||||
|         "lastModified": 1750969886, |         "lastModified": 1752162966, | ||||||
|         "narHash": "sha256-zW/OFnotiz/ndPFdebpo3X0CrbVNf22n4DjN2vxlb58=", |         "narHash": "sha256-3MxxkU8ZXMHXcbFz7UE4M6qnIPTYGcE/7EMqlZNnVDE=", | ||||||
|         "owner": "nixos", |         "owner": "nixos", | ||||||
|         "repo": "nixpkgs", |         "repo": "nixpkgs", | ||||||
|         "rev": "a676066377a2fe7457369dd37c31fd2263b662f4", |         "rev": "10e687235226880ed5e9f33f1ffa71fe60f2638a", | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       }, |       }, | ||||||
|       "original": { |       "original": { | ||||||
|  |  | ||||||
|  | @ -75,6 +75,7 @@ | ||||||
|             NIX_LD_LIBRARY_PATH = LD_LIBRARY_PATH; |             NIX_LD_LIBRARY_PATH = LD_LIBRARY_PATH; | ||||||
|             NIX_LD = pkgs.stdenv.cc.bintools.dynamicLinker; |             NIX_LD = pkgs.stdenv.cc.bintools.dynamicLinker; | ||||||
|             RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}"; |             RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}"; | ||||||
|  |             RUST_BACKTRACE = "1"; | ||||||
|           }; |           }; | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
|  |  | ||||||
|  | @ -22,6 +22,11 @@ pub struct Cli { | ||||||
|         help = "Set default log level lower. You can also change this via the RUST_LOG environment variable." |         help = "Set default log level lower. You can also change this via the RUST_LOG environment variable." | ||||||
|     )] |     )] | ||||||
|     pub verbose: bool, |     pub verbose: bool, | ||||||
|  |     #[arg(
 | ||||||
|  |         long, | ||||||
|  |         help = "When receiving a null byte as a char in the CharGridCommand, do not overwrite any pixels instead of clearing all pixels." | ||||||
|  |     )] | ||||||
|  |     pub experimental_null_char_handling: bool, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Parser, Debug)] | #[derive(Parser, Debug)] | ||||||
|  |  | ||||||
|  | @ -5,10 +5,11 @@ use crate::{ | ||||||
| }; | }; | ||||||
| use log::{debug, error, info, trace, warn}; | use log::{debug, error, info, trace, warn}; | ||||||
| use servicepoint::{ | use servicepoint::{ | ||||||
|     BinaryOperation, BitVecCommand, Bitmap, BitmapCommand, GlobalBrightnessCommand, |     BinaryOperation, BitVecCommand, Bitmap, BitmapCommand, BrightnessGrid, | ||||||
|     BrightnessGrid, BrightnessGridCommand, CharGridCommand, ClearCommand, |     BrightnessGridCommand, CharGridCommand, ClearCommand, CompressionCode, | ||||||
|     CompressionCode, Cp437GridCommand, FadeOutCommand, Grid, HardResetCommand, |     Cp437GridCommand, FadeOutCommand, GlobalBrightnessCommand, Grid, GridMut, | ||||||
|     Origin, TypedCommand, PIXEL_COUNT, PIXEL_WIDTH, TILE_SIZE, |     HardResetCommand, Origin, TypedCommand, PIXEL_COUNT, PIXEL_WIDTH, | ||||||
|  |     TILE_SIZE, | ||||||
| }; | }; | ||||||
| use std::{ | use std::{ | ||||||
|     ops::{BitAnd, BitOr, BitXor}, |     ops::{BitAnd, BitOr, BitXor}, | ||||||
|  | @ -21,6 +22,7 @@ pub struct CommandExecutionContext<'t> { | ||||||
|     luma: &'t RwLock<BrightnessGrid>, |     luma: &'t RwLock<BrightnessGrid>, | ||||||
|     cp437_font: Cp437Font, |     cp437_font: Cp437Font, | ||||||
|     font_renderer: FontRenderer8x8, |     font_renderer: FontRenderer8x8, | ||||||
|  |     experimental_null_char_handling: bool, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[must_use] | #[must_use] | ||||||
|  | @ -46,11 +48,11 @@ impl CommandExecute for BitmapCommand { | ||||||
|     fn execute(&self, context: &CommandExecutionContext) -> ExecutionResult { |     fn execute(&self, context: &CommandExecutionContext) -> ExecutionResult { | ||||||
|         let Self { |         let Self { | ||||||
|             origin: |             origin: | ||||||
|             Origin { |                 Origin { | ||||||
|                 x: offset_x, |                     x: offset_x, | ||||||
|                 y: offset_y, |                     y: offset_y, | ||||||
|                 .. |                     .. | ||||||
|             }, |                 }, | ||||||
|             bitmap: pixels, |             bitmap: pixels, | ||||||
|             .. |             .. | ||||||
|         } = self; |         } = self; | ||||||
|  | @ -143,7 +145,7 @@ impl CommandExecute for Cp437GridCommand { | ||||||
|                     bitmap: context.cp437_font[char_code].clone(), |                     bitmap: context.cp437_font[char_code].clone(), | ||||||
|                     compression: CompressionCode::default(), |                     compression: CompressionCode::default(), | ||||||
|                 } |                 } | ||||||
|                     .execute(context); |                 .execute(context); | ||||||
|                 match execute_result { |                 match execute_result { | ||||||
|                     Success => {} |                     Success => {} | ||||||
|                     Failure => { |                     Failure => { | ||||||
|  | @ -192,16 +194,30 @@ impl CommandExecute for CharGridCommand { | ||||||
|         for char_y in 0usize..grid.height() { |         for char_y in 0usize..grid.height() { | ||||||
|             for char_x in 0usize..grid.width() { |             for char_x in 0usize..grid.width() { | ||||||
|                 let char = grid.get(char_x, char_y); |                 let char = grid.get(char_x, char_y); | ||||||
|  |                 let mut bitmap_window = { | ||||||
|  |                     let pixel_x = (char_x + x) * TILE_SIZE; | ||||||
|  |                     let pixel_y = (char_y + y) * TILE_SIZE; | ||||||
|  |                     display | ||||||
|  |                         .window_mut( | ||||||
|  |                             pixel_x..pixel_x + TILE_SIZE, | ||||||
|  |                             pixel_y..pixel_y + TILE_SIZE, | ||||||
|  |                         ) | ||||||
|  |                         .unwrap() | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 if char == '\0' { | ||||||
|  |                     if context.experimental_null_char_handling { | ||||||
|  |                         trace!("skipping {char:?}"); | ||||||
|  |                     } else { | ||||||
|  |                         bitmap_window.fill(false); | ||||||
|  |                     } | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 trace!("drawing {char}"); |                 trace!("drawing {char}"); | ||||||
| 
 |                 if let Err(e) = | ||||||
|                 let tile_x = char_x + x; |                     context.font_renderer.render(char, &mut bitmap_window) | ||||||
|                 let tile_y = char_y + y; |                 { | ||||||
| 
 |  | ||||||
|                 if let Err(e) = context.font_renderer.render( |  | ||||||
|                     char, |  | ||||||
|                     &mut display, |  | ||||||
|                     Origin::new(tile_x * TILE_SIZE, tile_y * TILE_SIZE), |  | ||||||
|                 ) { |  | ||||||
|                     error!( |                     error!( | ||||||
|                         "stopping drawing text because char draw failed: {e}" |                         "stopping drawing text because char draw failed: {e}" | ||||||
|                     ); |                     ); | ||||||
|  | @ -251,12 +267,14 @@ impl<'t> CommandExecutionContext<'t> { | ||||||
|         display: &'t RwLock<Bitmap>, |         display: &'t RwLock<Bitmap>, | ||||||
|         luma: &'t RwLock<BrightnessGrid>, |         luma: &'t RwLock<BrightnessGrid>, | ||||||
|         font_renderer: FontRenderer8x8, |         font_renderer: FontRenderer8x8, | ||||||
|  |         experimental_null_char_handling: bool, | ||||||
|     ) -> Self { |     ) -> Self { | ||||||
|         CommandExecutionContext { |         CommandExecutionContext { | ||||||
|             display, |             display, | ||||||
|             luma, |             luma, | ||||||
|             font_renderer, |             font_renderer, | ||||||
|             cp437_font: Cp437Font::default(), |             cp437_font: Cp437Font::default(), | ||||||
|  |             experimental_null_char_handling, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -12,8 +12,11 @@ use pathfinder_geometry::{ | ||||||
|     transform2d::Transform2F, |     transform2d::Transform2F, | ||||||
|     vector::{vec2f, vec2i}, |     vector::{vec2f, vec2i}, | ||||||
| }; | }; | ||||||
| use servicepoint::{Bitmap, Grid, Origin, Pixels, TILE_SIZE}; | use servicepoint::{Bitmap, GridMut, WindowMut, TILE_SIZE}; | ||||||
| use std::sync::{Mutex, MutexGuard}; | use std::{ | ||||||
|  |     collections::HashMap, | ||||||
|  |     sync::{Mutex, MutexGuard}, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| struct SendFont(Font); | struct SendFont(Font); | ||||||
|  | @ -32,6 +35,7 @@ pub struct FontRenderer8x8 { | ||||||
|     font: SendFont, |     font: SendFont, | ||||||
|     canvas: Mutex<Canvas>, |     canvas: Mutex<Canvas>, | ||||||
|     fallback_char: Option<u32>, |     fallback_char: Option<u32>, | ||||||
|  |     cache: Mutex<HashMap<char, Bitmap>>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, thiserror::Error)] | #[derive(Debug, thiserror::Error)] | ||||||
|  | @ -56,6 +60,7 @@ impl FontRenderer8x8 { | ||||||
|             font: SendFont(font), |             font: SendFont(font), | ||||||
|             fallback_char, |             fallback_char, | ||||||
|             canvas: Mutex::new(canvas), |             canvas: Mutex::new(canvas), | ||||||
|  |             cache: Mutex::new(HashMap::new()), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -74,9 +79,13 @@ impl FontRenderer8x8 { | ||||||
|     pub fn render( |     pub fn render( | ||||||
|         &self, |         &self, | ||||||
|         char: char, |         char: char, | ||||||
|         bitmap: &mut Bitmap, |         target: &mut WindowMut<bool, Bitmap>, | ||||||
|         offset: Origin<Pixels>, |  | ||||||
|     ) -> Result<(), RenderError> { |     ) -> Result<(), RenderError> { | ||||||
|  |         let cache = &mut *self.cache.lock().unwrap(); | ||||||
|  |         if let Some(drawn_char) = cache.get(&char) { | ||||||
|  |             target.deref_assign(drawn_char); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         let glyph_id = self.get_glyph(char)?; |         let glyph_id = self.get_glyph(char)?; | ||||||
| 
 | 
 | ||||||
|         let mut canvas = self.canvas.lock().unwrap(); |         let mut canvas = self.canvas.lock().unwrap(); | ||||||
|  | @ -91,20 +100,21 @@ impl FontRenderer8x8 { | ||||||
|             RasterizationOptions::Bilevel, |             RasterizationOptions::Bilevel, | ||||||
|         )?; |         )?; | ||||||
| 
 | 
 | ||||||
|         Self::copy_to_bitmap(canvas, bitmap, offset) |         let mut bitmap = Bitmap::new(TILE_SIZE, TILE_SIZE).unwrap(); | ||||||
|  |         Self::copy_to_bitmap(canvas, &mut bitmap)?; | ||||||
|  |         target.deref_assign(&bitmap); | ||||||
|  |         cache.insert(char, bitmap); | ||||||
|  |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn copy_to_bitmap( |     fn copy_to_bitmap( | ||||||
|         canvas: MutexGuard<Canvas>, |         canvas: MutexGuard<Canvas>, | ||||||
|         bitmap: &mut Bitmap, |         bitmap: &mut Bitmap, | ||||||
|         offset: Origin<Pixels>, |  | ||||||
|     ) -> Result<(), RenderError> { |     ) -> Result<(), RenderError> { | ||||||
|         for y in 0..TILE_SIZE { |         for y in 0..TILE_SIZE { | ||||||
|             for x in 0..TILE_SIZE { |             for x in 0..TILE_SIZE { | ||||||
|                 let canvas_val = canvas.pixels[x + y * TILE_SIZE] != 0; |                 let canvas_val = canvas.pixels[x + y * TILE_SIZE] != 0; | ||||||
|                 let bitmap_x = offset.x + x; |                 if !bitmap.set_optional(x, y, canvas_val) { | ||||||
|                 let bitmap_y = offset.y + y; |  | ||||||
|                 if !bitmap.set_optional(bitmap_x, bitmap_y, canvas_val) { |  | ||||||
|                     return Err(OutOfBounds(x, y)); |                     return Err(OutOfBounds(x, y)); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  | @ -24,6 +24,7 @@ const PIXEL_HEIGHT_WITH_SPACERS: usize = | ||||||
|     PIXEL_HEIGHT + NUM_SPACERS * SPACER_HEIGHT; |     PIXEL_HEIGHT + NUM_SPACERS * SPACER_HEIGHT; | ||||||
| 
 | 
 | ||||||
| const OFF_COLOR: u32 = u32::from_ne_bytes([0u8, 0, 0, 0]); | const OFF_COLOR: u32 = u32::from_ne_bytes([0u8, 0, 0, 0]); | ||||||
|  | const SPACER_COLOR: u32 = u32::from_ne_bytes([100u8, 100, 100, 0]); | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub enum AppEvents { | pub enum AppEvents { | ||||||
|  | @ -61,7 +62,7 @@ impl<'t> Gui<'t> { | ||||||
|             if self.options.spacers && tile_y != 0 { |             if self.options.spacers && tile_y != 0 { | ||||||
|                 // cannot just frame.skip(PIXEL_WIDTH as usize * SPACER_HEIGHT as usize) because of typing
 |                 // cannot just frame.skip(PIXEL_WIDTH as usize * SPACER_HEIGHT as usize) because of typing
 | ||||||
|                 for _ in 0..PIXEL_WIDTH * SPACER_HEIGHT { |                 for _ in 0..PIXEL_WIDTH * SPACER_HEIGHT { | ||||||
|                     frame.next().unwrap(); |                     *frame.next().unwrap() = SPACER_COLOR; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -39,7 +39,12 @@ fn main() { | ||||||
|         .font |         .font | ||||||
|         .map(FontRenderer8x8::from_name) |         .map(FontRenderer8x8::from_name) | ||||||
|         .unwrap_or_else(FontRenderer8x8::default); |         .unwrap_or_else(FontRenderer8x8::default); | ||||||
|     let context = CommandExecutionContext::new(&display, &luma, font_renderer); |     let context = CommandExecutionContext::new( | ||||||
|  |         &display, | ||||||
|  |         &luma, | ||||||
|  |         font_renderer, | ||||||
|  |         cli.experimental_null_char_handling, | ||||||
|  |     ); | ||||||
|     let mut udp_server = UdpServer::new( |     let mut udp_server = UdpServer::new( | ||||||
|         cli.bind, |         cli.bind, | ||||||
|         stop_udp_rx, |         stop_udp_rx, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue