|
1 | 1 | //! Screen-related commands for Neotron OS |
2 | 2 |
|
| 3 | +use neotron_common_bios::video::RGBColour; |
| 4 | +use pc_keyboard::DecodedKey; |
| 5 | + |
3 | 6 | use crate::{ |
4 | 7 | bios::{ |
5 | 8 | video::{Format, Mode}, |
@@ -29,6 +32,24 @@ pub static MODE_ITEM: menu::Item<Ctx> = menu::Item { |
29 | 32 | help: Some("List/change video mode"), |
30 | 33 | }; |
31 | 34 |
|
| 35 | +pub static GFX_ITEM: menu::Item<Ctx> = menu::Item { |
| 36 | + item_type: menu::ItemType::Callback { |
| 37 | + function: gfx_cmd, |
| 38 | + parameters: &[ |
| 39 | + menu::Parameter::Mandatory { |
| 40 | + parameter_name: "new_mode", |
| 41 | + help: Some("The new gfx mode to try"), |
| 42 | + }, |
| 43 | + menu::Parameter::Optional { |
| 44 | + parameter_name: "filename", |
| 45 | + help: Some("a file to display"), |
| 46 | + }, |
| 47 | + ], |
| 48 | + }, |
| 49 | + command: "gfx", |
| 50 | + help: Some("Test a graphics mode"), |
| 51 | +}; |
| 52 | + |
32 | 53 | /// Called when the "cls" command is executed. |
33 | 54 | fn cls_cmd(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &mut Ctx) { |
34 | 55 | // Reset SGR, go home, clear screen, |
@@ -88,6 +109,82 @@ fn mode_cmd(_menu: &menu::Menu<Ctx>, item: &menu::Item<Ctx>, args: &[&str], _ctx |
88 | 109 | } |
89 | 110 | } |
90 | 111 |
|
| 112 | +/// Called when the "gfx" command is executed |
| 113 | +fn gfx_cmd(_menu: &menu::Menu<Ctx>, item: &menu::Item<Ctx>, args: &[&str], ctx: &mut Ctx) { |
| 114 | + let Some(new_mode) = menu::argument_finder(item, args, "new_mode").unwrap() else { |
| 115 | + osprintln!("Missing arg"); |
| 116 | + return; |
| 117 | + }; |
| 118 | + let file_name = menu::argument_finder(item, args, "filename").unwrap(); |
| 119 | + let Ok(mode_num) = new_mode.parse::<u8>() else { |
| 120 | + osprintln!("Invalid integer {:?}", new_mode); |
| 121 | + return; |
| 122 | + }; |
| 123 | + let Some(mode) = Mode::try_from_u8(mode_num) else { |
| 124 | + osprintln!("Invalid mode {:?}", new_mode); |
| 125 | + return; |
| 126 | + }; |
| 127 | + let api = crate::API.get(); |
| 128 | + let old_mode = (api.video_get_mode)(); |
| 129 | + let old_ptr = (api.video_get_framebuffer)(); |
| 130 | + |
| 131 | + let buffer = ctx.tpa.as_slice_u8(); |
| 132 | + let buffer_ptr = buffer.as_mut_ptr() as *mut u32; |
| 133 | + if let Some(file_name) = file_name { |
| 134 | + let Ok(file) = crate::FILESYSTEM.open_file(file_name, embedded_sdmmc::Mode::ReadOnly) |
| 135 | + else { |
| 136 | + osprintln!("No such file."); |
| 137 | + return; |
| 138 | + }; |
| 139 | + let _ = file.read(buffer); |
| 140 | + } else { |
| 141 | + // draw a dummy non-zero data. In Chunky1 this is a checkerboard. |
| 142 | + let line_size_words = mode.line_size_bytes() / 4; |
| 143 | + for row in 0..mode.vertical_lines() as usize { |
| 144 | + let word = if (row % 2) == 0 { |
| 145 | + 0x5555_5555 |
| 146 | + } else { |
| 147 | + 0xAAAA_AAAA |
| 148 | + }; |
| 149 | + for col in 0..line_size_words { |
| 150 | + let idx = (row * line_size_words) + col; |
| 151 | + unsafe { |
| 152 | + // Let's try stripes? |
| 153 | + buffer_ptr.add(idx).write_volatile(word); |
| 154 | + } |
| 155 | + } |
| 156 | + } |
| 157 | + } |
| 158 | + |
| 159 | + if let neotron_common_bios::FfiResult::Err(e) = |
| 160 | + unsafe { (api.video_set_mode)(mode, buffer_ptr) } |
| 161 | + { |
| 162 | + osprintln!("Couldn't set mode {}: {:?}", mode_num, e); |
| 163 | + } |
| 164 | + |
| 165 | + // Now wait for user input |
| 166 | + let mut r = 0u8; |
| 167 | + let mut g = 80u8; |
| 168 | + let mut b = 160u8; |
| 169 | + 'wait: loop { |
| 170 | + (api.video_wait_for_line)(0); |
| 171 | + ((api.video_set_palette)(0, RGBColour::from_rgb(r, g, b))); |
| 172 | + r = r.wrapping_add(1); |
| 173 | + g = g.wrapping_add(1); |
| 174 | + b = b.wrapping_add(1); |
| 175 | + |
| 176 | + let keyin = crate::STD_INPUT.lock().get_raw(); |
| 177 | + if let Some(DecodedKey::Unicode('Q') | DecodedKey::Unicode('q')) = keyin { |
| 178 | + break 'wait; |
| 179 | + } |
| 180 | + } |
| 181 | + |
| 182 | + // Put it back as it was |
| 183 | + unsafe { |
| 184 | + (api.video_set_mode)(old_mode, old_ptr); |
| 185 | + } |
| 186 | +} |
| 187 | + |
91 | 188 | /// Print out all supported video modes |
92 | 189 | fn print_modes() { |
93 | 190 | let api = crate::API.get(); |
|
0 commit comments