diff --git a/Cargo.lock b/Cargo.lock index 4fc2352..25ba4a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "autocfg" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" +dependencies = [ + "autocfg 1.1.0", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -23,12 +32,27 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + [[package]] name = "env_logger" version = "0.8.4" @@ -39,6 +63,12 @@ dependencies = [ "regex", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "futures" version = "0.3.25" @@ -140,7 +170,7 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "wasi", ] @@ -163,7 +193,7 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -178,6 +208,47 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b06910a54adb901a01dfd9c475e7959c41acd55a078101ec70fb180f01b7435f" +[[package]] +name = "num" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +dependencies = [ + "num-integer", + "num-iter", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg 1.1.0", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg 1.1.0", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg 1.1.0", +] + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -207,7 +278,7 @@ checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" dependencies = [ "env_logger", "log", - "rand", + "rand 0.8.5", ] [[package]] @@ -219,15 +290,59 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.8", + "libc", + "rand_chacha", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.6.4" @@ -237,6 +352,77 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "regex" version = "1.7.0" @@ -272,7 +458,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7229b505ae0706e64f37ffc54a9c163e11022a6636d58fe1f3f52018257ff9f7" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "proc-macro2", "quote", "rustc_version", @@ -291,25 +477,26 @@ dependencies = [ [[package]] name = "sdl2" -version = "0.35.2" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7959277b623f1fb9e04aea73686c3ca52f01b2145f8ea16f4ff30d8b7623b1a" +checksum = "d051a07231e303f5f719da78cb6f7394f6d5b54f733aef5b0b447804a83edd7b" dependencies = [ "bitflags", "lazy_static", "libc", + "num", + "rand 0.6.5", "sdl2-sys", ] [[package]] name = "sdl2-sys" -version = "0.35.2" +version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3586be2cf6c0a8099a79a12b4084357aa9b3e0b0d7980e3b67aaf7a9d55f9f0" +checksum = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", - "version-compare", ] [[package]] @@ -324,7 +511,7 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" dependencies = [ - "autocfg", + "autocfg 1.1.0", ] [[package]] @@ -354,14 +541,30 @@ dependencies = [ "sdl2", ] -[[package]] -name = "version-compare" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 5a41c6d..15392b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,15 @@ path = "src/bin/uxncli/main.rs" name = "uxnsym" path = "src/bin/uxnsym/main.rs" +[[bin]] +name = "uxnsdl2" +path = "src/bin/uxnsdl2/main.rs" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies] -sdl2 = "0.35.2" +[dependencies.sdl2] +version = "0.32.1" # FIXME: Get upgraded +default-features = false [dev-dependencies] quickcheck = "1.0.3" diff --git a/assets/bardo.png b/assets/bardo.png new file mode 100644 index 0000000..b6bba99 Binary files /dev/null and b/assets/bardo.png differ diff --git a/src/bin/uxnsdl2/main.rs b/src/bin/uxnsdl2/main.rs new file mode 100644 index 0000000..7e2a7df --- /dev/null +++ b/src/bin/uxnsdl2/main.rs @@ -0,0 +1,73 @@ +use sdl2::event::Event; +use sdl2::keyboard::Keycode; +use sdl2::pixels::Color; +use sdl2::rect::{Point, Rect}; +use sdl2::render::WindowCanvas; +// "self" imports the "image" module itself as well as everything else we listed +use std::thread::sleep; +use std::time::Duration; + +fn render(canvas: &mut WindowCanvas, color: Color) -> Result<(), String> { + canvas.set_draw_color(color); + canvas.clear(); + + canvas.set_draw_color(color); + // fills the canvas with the color we set in `set_draw_color`. + canvas.clear(); + + // change the color of our drawing with a gold-color ... + canvas.set_draw_color(Color::RGB(255, 210, 0)); + + // A draw a rectangle which almost fills our window with it! + canvas.fill_rect(Rect::new(10, 10, 780, 580))?; + + canvas.draw_point(Point::new(5, 5))?; + + canvas.present(); + + Ok(()) +} + +fn main() -> Result<(), String> { + let sdl_context = sdl2::init()?; + let video_subsystem = sdl_context.video()?; + let window = video_subsystem + .window("rusty varvara [sdl2]", 800, 600) + .position_centered() + .build() + .expect("could not initialize video subsystem"); + + let mut canvas = window + .into_canvas() + .build() + .expect("could not make a canvas"); + + let mut event_pump = sdl_context.event_pump()?; + let mut i = 0; + 'running: loop { + // Handle events + for event in event_pump.poll_iter() { + match event { + Event::Quit { .. } + | Event::KeyDown { + keycode: Some(Keycode::Escape), + .. + } => { + break 'running; + } + _ => {} + } + } + + // Update + i = (i + 1) % 255; + + // Render + render(&mut canvas, Color::RGB(i, 64, 255 - i))?; + + // Time management! + sleep(Duration::new(0, 1_000_000_000u32 / 60)); + } + + Ok(()) +} diff --git a/src/device/video_sdl2.rs b/src/device/video_sdl2.rs new file mode 100644 index 0000000..0dc27f6 --- /dev/null +++ b/src/device/video_sdl2.rs @@ -0,0 +1,187 @@ +use crate::uxn::device::Device; + +static blending: [[u8; 16]; 5] = [ + [0, 0, 0, 0, 1, 0, 1, 1, 2, 2, 0, 2, 3, 3, 3, 0], + [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3], + [1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1], + [2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2], + [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0], +]; + +static palette_mono: [u32; 2] = [0x0f000000u32, 0x0fffffffu32]; + +struct Layer { + pixels: Vec, + changed: bool, +} + +pub struct Sdl2VideoDevice { + vector: u16, + palette: [u32; 4], + pixels: &[u32], + width: u16, + height: u16, + fg: Layer, + bg: Layer, + mono: u8, + + x_cur: u16, // x8, x9 + y_cur: u16, // xa, xb + auto: bool, // x6 + sprite_addr: u16, // xc, xd +} + +impl Sdl2VideoDevice { + fn new() -> Sdl2VideoDevice { + unimplemented!(); + } + + fn clear(&mut self) { + for i in 0..self.width * self.height { + // FIXME: Is there some clear/set operation on vector? You can write your own seemingly, but it's this loop. + self.fg.pixels[i] = 0x00; + self.bg.pixels[i] = 0x00; + } + } + + /** + * Update an entry in either the foreground or background buffers, marking the buffer as dirty. + */ + fn write_pixel(&mut self, layer: bool, x: u16, y: u16, color: u8) { + let layer = if layer { &mut self.fg } else { &mut self.bg }; + if x < self.width && y < self.height { + let idx = x + (y * self.height) as usize; + if color != layer.pixes[idx] { + layer.pixels[idx] = color; + layer.changed |= true; + } + } + } + + /** + * Roll through the pixels associated with a sprite, calling write_pixel for each one. + */ + fn write_sprite( + &mut self, + layer: bool, + x: u16, + y: u16, + sprite_ptr: (), + flipx: bool, + flipy: bool, + twobpp: bool, + ) { + let mut v = h = opaque = blending[4][color]; + for v in 0..8 { + let c: u8 = sprite[v] | (if twobpp { sprite[v + 8] } else { 0 }) << 8; + + for h in 7..0 { + c = c >>= 1; + let ch = (c & 1) | ((c >> 7) & 2); + if (opaque || (ch != 0)) { + self.write_pixel( + layer, + x + (if flipx { 7 - h } else { h }), + y + (if flipy { 7 - v } else { v }), + blending[ch][color], + ); + } + } + } + } + + /** + * Compute a partial form of the palette. + * Note that redraw() does its own final palette computation. + * Not clear what parts of that live where why. + */ + fn set_palette(&mut self, colors: [u8; 6]) { + // TODO: What in the everliving fuck is this doing. + // Works in C's *u8 land, not clear it works in Rust. + let mut shift = 4; + for i in 0..4 { + let r = (colors[0 + i / 2] >> shift) & 0x0f; + let g = (colors[2 + i / 2] >> shift) & 0x0f; + let b = (colors[4 + i / 2] >> shift) & 0x0f; + + self.palette[i] = 0x0f000000 | r << 16 | g << 8 | b; + self.palette[i] |= self.palette[i] << 4; + + shift ^= 4; + } + + // Both layers are now dirty + self.fg.changed |= true; + self.bg.changed |= true; + } + + fn redraw(&mut self) { + let size = self.width * self.height; + let mut pallet = [0u32; 16]; + for i in 0..16 { + let idx = if (i >> 2) != 0 { i >> 2 } else { i & 3 }; + palette[i] = self.palette[idx]; + } + if (self.mono) { + for i in i..size { + let idx = (if self.fg.pixels[i] != 0 { + self.fg.pixels[i] + } else { + self.bg.pixels[i] + }) & 0x1; + pixels[i] = palette_mono[idx]; + } + } else { + for i in 0..size { + pixels[i] = palette[self.fg.pixels[i] << 2 | self.bg.pixels[i]]; + } + } + self.fg.changed = false; + self.bg.changed = false; + } +} + +impl Device for Sdl2VideoDevice { + fn dei1(&mut self, vm: &mut Uxn, port: u8) -> Result { + let slot = port & 0xF; + // FIXME: this is sorta copypasta, but LOTS of source byte order assumptions here. + match slot { + 0x0 => Ok(self.vector >> 8), + 0x1 => Ok(self.vector & 0xFF), + 0x2 => Ok(self.width >> 8), + 0x3 => Ok(self.width & 0xFF), + 0x4 => Ok(self.height >> 8), + 0x5 => Ok(self.height & 0xFF), + _ => Ok(0), + } + } + + /** + * Callback used by UXN to do output through a "device". + */ + fn deo1(&mut self, vm: &mut Uxn, port: u8, val: u8) -> Result<(), DeviceError> { + let slot = port & 0xF; + match slot { + // Writing to the device vector + 0x0 => self.vector = self.vector & 0x00FF | ((val as u16) << 8), + 0x1 => self.vector = self.vector & 0xFF00 | (val as u16), + // Writing to the device width port. + // Note that the reference implementation triggers resizing on the lower byte + 0x2 | 0x3 => (), + // Writing to the device height port + // Note that the reference implementation triggers resizing on the lower byte + 0x4 | 0x5 => (), + + // FIXME: Writing to all the settings words (auto, x, y, addr) + + // Write a pixel word + 0xe => (), + + // Write a sprite word + 0xf => (), + + _ => (), + } + Ok() + } +}