11//! Screen-related commands for Neotron OS
22
3+ use neotron_common_bios:: video:: { Attr , TextBackgroundColour , TextForegroundColour } ;
4+
35use crate :: { print, println, Ctx , API , VGA_CONSOLE } ;
46
57pub static CLEAR_ITEM : menu:: Item < Ctx > = menu:: Item {
@@ -20,6 +22,24 @@ pub static FILL_ITEM: menu::Item<Ctx> = menu::Item {
2022 help : Some ( "Fill the screen with characters" ) ,
2123} ;
2224
25+ pub static BENCH_ITEM : menu:: Item < Ctx > = menu:: Item {
26+ item_type : menu:: ItemType :: Callback {
27+ function : bench,
28+ parameters : & [ ] ,
29+ } ,
30+ command : "screen_bench" ,
31+ help : Some ( "Time how long to put 1,000,000 characters on the screen, with scrolling." ) ,
32+ } ;
33+
34+ pub static MANDEL_ITEM : menu:: Item < Ctx > = menu:: Item {
35+ item_type : menu:: ItemType :: Callback {
36+ function : mandel,
37+ parameters : & [ ] ,
38+ } ,
39+ command : "screen_mandel" ,
40+ help : Some ( "Calculate the Mandelbrot set" ) ,
41+ } ;
42+
2343/// Called when the "clear" command is executed.
2444fn clear ( _menu : & menu:: Menu < Ctx > , _item : & menu:: Item < Ctx > , _args : & [ & str ] , _ctx : & mut Ctx ) {
2545 if let Some ( ref mut console) = unsafe { & mut VGA_CONSOLE } {
@@ -31,19 +51,97 @@ fn clear(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx:
3151fn fill ( _menu : & menu:: Menu < Ctx > , _item : & menu:: Item < Ctx > , _args : & [ & str ] , _ctx : & mut Ctx ) {
3252 if let Some ( ref mut console) = unsafe { & mut VGA_CONSOLE } {
3353 console. clear ( ) ;
54+ let api = API . get ( ) ;
55+ let mode = ( api. video_get_mode ) ( ) ;
56+ let ( Some ( width) , Some ( height) ) = ( mode. text_width ( ) , mode. text_height ( ) ) else {
57+ println ! ( "Unable to get console size" ) ;
58+ return ;
59+ } ;
60+ // A range of printable ASCII compatible characters
61+ let mut char_cycle = ( b' ' ..=b'~' ) . cycle ( ) ;
62+ let mut remaining = height * width;
63+
64+ // Scroll two screen fulls
65+ ' outer: for bg in ( 0 ..=7 ) . cycle ( ) {
66+ let bg_colour = TextBackgroundColour :: new ( bg) . unwrap ( ) ;
67+ for fg in 1 ..=15 {
68+ if fg == bg {
69+ continue ;
70+ }
71+ let fg_colour = TextForegroundColour :: new ( fg) . unwrap ( ) ;
72+ remaining -= 1 ;
73+ if remaining == 0 {
74+ break ' outer;
75+ }
76+ let attr = Attr :: new ( fg_colour, bg_colour, false ) ;
77+ let glyph = char_cycle. next ( ) . unwrap ( ) ;
78+ console. set_attr ( attr) ;
79+ console. write_bstr ( & [ glyph] ) ;
80+ }
81+ }
82+ let attr = Attr :: new (
83+ TextForegroundColour :: WHITE ,
84+ TextBackgroundColour :: BLACK ,
85+ false ,
86+ ) ;
87+ console. set_attr ( attr) ;
3488 }
89+ }
90+
91+ /// Called when the "bench" command is executed.
92+ fn bench ( _menu : & menu:: Menu < Ctx > , _item : & menu:: Item < Ctx > , _args : & [ & str ] , _ctx : & mut Ctx ) {
93+ const NUM_CHARS : u64 = 1_000_000 ;
94+ if let Some ( ref mut console) = unsafe { & mut VGA_CONSOLE } {
95+ let api = API . get ( ) ;
96+ let start = ( api. time_ticks_get ) ( ) ;
97+ console. clear ( ) ;
98+ let glyphs = & [ b'x' ] ;
99+ for _idx in 0 ..NUM_CHARS {
100+ console. write_bstr ( glyphs) ;
101+ }
102+ let end = ( api. time_ticks_get ) ( ) ;
103+ let delta = end. 0 - start. 0 ;
104+ let chars_per_second = ( NUM_CHARS * ( api. time_ticks_per_second ) ( ) . 0 ) / delta;
105+ println ! (
106+ "{} chars in {} ticks, or {} chars per second" ,
107+ NUM_CHARS , delta, chars_per_second
108+ ) ;
109+ }
110+ }
111+
112+ /// Called when the "mandel" command is executed.
113+ fn mandel ( _menu : & menu:: Menu < Ctx > , _item : & menu:: Item < Ctx > , _args : & [ & str ] , _ctx : & mut Ctx ) {
114+ fn mandelbrot ( cx : f64 , cy : f64 , max_loops : u32 ) -> u32 {
115+ let mut x = cx;
116+ let mut y = cy;
117+ for i in 1 ..max_loops {
118+ let x_squared = x * x;
119+ let y_squared = y * y;
120+ if x_squared + y_squared > 4.0 {
121+ return i;
122+ }
123+ let x1 = x_squared - y_squared + cx;
124+ let y1 = ( 2.0 * x * y) + cy;
125+ x = x1;
126+ y = y1;
127+ }
128+ 0
129+ }
130+
35131 let api = API . get ( ) ;
36132 let mode = ( api. video_get_mode ) ( ) ;
37133 let ( Some ( width) , Some ( height) ) = ( mode. text_width ( ) , mode. text_height ( ) ) else {
38- println ! ( "Unable to get console size" ) ;
134+ println ! ( "Unable to get screen size" ) ;
39135 return ;
40136 } ;
41- // A range of printable ASCII compatible characters
42- let mut char_cycle = ( ' ' ..='~' ) . cycle ( ) ;
43- // Scroll two screen fulls
44- for _row in 0 ..height * 2 {
45- for _col in 0 ..width {
46- print ! ( "{}" , char_cycle. next( ) . unwrap( ) ) ;
137+
138+ let glyphs = b" .,'~!^:;[/<&?oxOX# " ;
139+ for y_pos in 0 ..height - 2 {
140+ let y = ( f64:: from ( y_pos) * 4.0 / f64:: from ( height) ) - 2.0 ;
141+ for x_pos in 0 ..width {
142+ let x = ( f64:: from ( x_pos) * 4.0 / f64:: from ( width) ) - 2.0 ;
143+ let result = mandelbrot ( x, y, 20 ) ;
144+ print ! ( "{}" , glyphs[ result as usize ] as char ) ;
47145 }
48146 }
49147}
0 commit comments