diff options
Diffstat (limited to 'bins')
| -rw-r--r-- | bins/paint/Cargo.toml | 8 | ||||
| -rw-r--r-- | bins/paint/src/main.rs | 137 |
2 files changed, 145 insertions, 0 deletions
diff --git a/bins/paint/Cargo.toml b/bins/paint/Cargo.toml new file mode 100644 index 0000000..c89597e --- /dev/null +++ b/bins/paint/Cargo.toml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | [package] | ||
| 2 | name = "paint" | ||
| 3 | version.workspace = true | ||
| 4 | edition.workspace = true | ||
| 5 | [lints] | ||
| 6 | workspace = true | ||
| 7 | [dependencies] | ||
| 8 | rsapi = { path = "../../rsapi" } | ||
diff --git a/bins/paint/src/main.rs b/bins/paint/src/main.rs new file mode 100644 index 0000000..d395a4c --- /dev/null +++ b/bins/paint/src/main.rs | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | //! paint — drawing canvas via the GUI exports table. | ||
| 2 | //! | ||
| 3 | //! Keys: 1-8 select color, c clears to black. Mouse draws when pressed. | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | #[panic_handler] | ||
| 9 | fn panic(_info: &core::panic::PanicInfo) -> ! { | ||
| 10 | loop { core::hint::spin_loop(); } | ||
| 11 | } | ||
| 12 | |||
| 13 | const W: u32 = 640; | ||
| 14 | const H: u32 = 400; | ||
| 15 | |||
| 16 | const fn pack(r: u8, g: u8, b: u8) -> u32 { | ||
| 17 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32) | ||
| 18 | } | ||
| 19 | |||
| 20 | const PALETTE: [u32; 9] = [ | ||
| 21 | pack(255, 255, 255), // 1 white | ||
| 22 | pack(255, 0, 0), // 2 red | ||
| 23 | pack(0, 255, 0), // 3 green | ||
| 24 | pack(0, 0, 255), // 4 blue | ||
| 25 | pack(255, 255, 0), // 5 yellow | ||
| 26 | pack(255, 0, 255), // 6 magenta | ||
| 27 | pack(0, 255, 255), // 7 cyan | ||
| 28 | pack(255, 128, 0), // 8 orange | ||
| 29 | pack(0, 0, 0), // clear (black) | ||
| 30 | ]; | ||
| 31 | |||
| 32 | #[unsafe(no_mangle)] | ||
| 33 | pub extern "C" fn efi_main(exports: &'static rsapi::Exports, _argc: usize, _argv: *const rsapi::Arg) -> i32 { | ||
| 34 | // Create window | ||
| 35 | let title = b"paint"; | ||
| 36 | let win = (exports.wm_create)(rsapi::Line { ptr: title.as_ptr(), len: title.len() }, W, H); | ||
| 37 | if win < 0 { return 1; } | ||
| 38 | |||
| 39 | // Get pixel buffer | ||
| 40 | let mut info = rsapi::WindowInfo { ptr: core::ptr::null_mut(), w: 0, h: 0 }; | ||
| 41 | if !(exports.wm_buffer)(win, &mut info) { | ||
| 42 | (exports.wm_destroy)(win); | ||
| 43 | return 1; | ||
| 44 | } | ||
| 45 | |||
| 46 | let buf = info.ptr; | ||
| 47 | let bw = info.w as usize; | ||
| 48 | let bh = info.h as usize; | ||
| 49 | |||
| 50 | let mut color: usize = 0; | ||
| 51 | let mut last_x: i32 = -1; | ||
| 52 | let mut last_y: i32 = -1; | ||
| 53 | |||
| 54 | let mut ev = rsapi::WmEvent { | ||
| 55 | kind: 0, | ||
| 56 | key_kind: rsapi::WmKeyKind::Char, | ||
| 57 | key_char: 0, | ||
| 58 | mouse: rsapi::WmMouseEvent { x: 0, y: 0, buttons: 0 }, | ||
| 59 | focused: false, | ||
| 60 | _pad: [0; 4], | ||
| 61 | }; | ||
| 62 | |||
| 63 | // Event loop | ||
| 64 | loop { | ||
| 65 | if !(exports.wm_recv)(&mut ev) { | ||
| 66 | continue; | ||
| 67 | } | ||
| 68 | match ev.kind { | ||
| 69 | 0 => { | ||
| 70 | // Key event | ||
| 71 | match ev.key_kind { | ||
| 72 | rsapi::WmKeyKind::Char => { | ||
| 73 | match ev.key_char { | ||
| 74 | b'1'..=b'8' => color = (ev.key_char - b'1') as usize, | ||
| 75 | b'c' => { | ||
| 76 | unsafe { | ||
| 77 | |||
| 78 | let n = bw * bh; | ||
| 79 | let p = buf as *mut u32; | ||
| 80 | for i in 0..n { | ||
| 81 | *p.add(i) = 0; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | (exports.wm_flush)(win); | ||
| 85 | } | ||
| 86 | _ => {} | ||
| 87 | } | ||
| 88 | } | ||
| 89 | rsapi::WmKeyKind::F4 => break, | ||
| 90 | _ => {} | ||
| 91 | } | ||
| 92 | } | ||
| 93 | 1 => { | ||
| 94 | // Mouse event | ||
| 95 | let m = &ev.mouse; | ||
| 96 | if m.buttons & 1 != 0 { | ||
| 97 | // Left button: draw pixel at (m.x, m.y) | ||
| 98 | if m.x >= 0 && m.y >= 0 && (m.x as usize) < bw && (m.y as usize) < bh { | ||
| 99 | unsafe { | ||
| 100 | |||
| 101 | *buf.add(m.y as usize * bw + m.x as usize) = PALETTE[color % PALETTE.len()]; | ||
| 102 | } | ||
| 103 | // Connect with last point (line drawing) | ||
| 104 | if last_x >= 0 { | ||
| 105 | let lx = last_x; let ly = last_y; | ||
| 106 | let dx = (m.x - lx).abs(); let sx = if lx < m.x { 1 } else { -1 }; | ||
| 107 | let dy = -(m.y - ly).abs(); let sy = if ly < m.y { 1 } else { -1 }; | ||
| 108 | let mut err = dx + dy; | ||
| 109 | let mut cx = lx; let mut cy = ly; | ||
| 110 | loop { | ||
| 111 | if cx >= 0 && cy >= 0 && (cx as usize) < bw && (cy as usize) < bh { | ||
| 112 | unsafe { | ||
| 113 | *buf.add(cy as usize * bw + cx as usize) = PALETTE[color % PALETTE.len()]; } | ||
| 114 | } | ||
| 115 | if cx == m.x && cy == m.y { break; } | ||
| 116 | let e2 = 2 * err; | ||
| 117 | if e2 >= dy { err += dy; cx += sx; } | ||
| 118 | if e2 <= dx { err += dx; cy += sy; } | ||
| 119 | } | ||
| 120 | } | ||
| 121 | (exports.wm_flush)(win); | ||
| 122 | last_x = m.x; | ||
| 123 | last_y = m.y; | ||
| 124 | } | ||
| 125 | } else { | ||
| 126 | last_x = -1; last_y = -1; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | 2 => {} // focus | ||
| 130 | 3 => break, // close | ||
| 131 | _ => {} | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | (exports.wm_destroy)(win); | ||
| 136 | 0 | ||
| 137 | } | ||
