commit 1216ed0d0932533979dbb12f9d9e1379b8ac641e Author: Skye Date: Tue Jan 10 13:12:46 2023 +0900 uwu diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..a24b210 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,6 @@ +[unstable] +build-std = ["core", "compiler_builtins", "alloc"] +build-std-features = ["compiler-builtins-mem"] + +[build] +target = "aarch64-nintendo-switch-freestanding" \ No newline at end of file diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d8f9ec7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target/ +.direnv/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..e828288 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,231 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330223a1aecc308757b9926e9391c9b47f8ef2dbd8aea9df88312aea18c5e8d6" +dependencies = [ + "libm", +] + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "font8x8" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63201c624b8c8883921b1a1accc8916c4fa9dbfb15d122b26e4dde945b86bbf" + +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + +[[package]] +name = "linked_list_allocator" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "549ce1740e46b291953c4340adcd74c59bcf4308f4cac050fd33ba91b7168f4a" + +[[package]] +name = "logpacket" +version = "0.1.0" +source = "git+https://github.com/aarch64-switch-rs/logpacket#d807c993fb4578e3809d91e3484c7d97f59eb3db" + +[[package]] +name = "nx" +version = "0.1.0" +source = "git+https://github.com/aarch64-switch-rs/nx#31f4590cac1776a4731380c29bcbb972591b5bba" +dependencies = [ + "arrayvec", + "linked_list_allocator", + "logpacket", + "paste", + "static_assertions", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e6affeb1632d6ff6a23d2cd40ffed138e82f1532571a26f527c8a284bb2fbb" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "paste" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" + +[[package]] +name = "proc-macro2" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rusttype" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff8374aa04134254b7995b63ad3dc41c7f7236f69528b28553da7d72efaa967" +dependencies = [ + "ab_glyph_rasterizer", + "libm", + "owned_ttf_parser", +] + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "serde" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "ttf-parser" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" + +[[package]] +name = "ui2d" +version = "0.1.0" +dependencies = [ + "font8x8", + "libm", + "nx", + "rusttype", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-segmentation" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" + +[[package]] +name = "uwurandom-nx" +version = "0.1.0" +dependencies = [ + "nx", + "rand_core", + "ui2d", + "uwurandom-rs", +] + +[[package]] +name = "uwurandom-proc-macros" +version = "0.1.0" +source = "git+https://git.skye.vg/me/uwurandom-rs#9b7344cadb7d1a73f5dec92ee2a77bad2a1e1d76" +dependencies = [ + "convert_case", + "quote", + "serde", + "serde_json", + "syn", +] + +[[package]] +name = "uwurandom-rs" +version = "0.1.0" +source = "git+https://git.skye.vg/me/uwurandom-rs#9b7344cadb7d1a73f5dec92ee2a77bad2a1e1d76" +dependencies = [ + "rand_core", + "uwurandom-proc-macros", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1ef6b1a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "uwurandom-nx" +authors = ["aarch64-switch-rs authors"] +version = "0.1.0" +edition = "2021" + +[dependencies] +nx = { git = "https://github.com/aarch64-switch-rs/nx", features=["input", "rand"] } +rand_core = "0.6.4" +ui2d = { path = "./ui2d" } +uwurandom-rs = { git = "https://git.skye.vg/me/uwurandom-rs" } + +# For help / more information, see https://github.com/aarch64-switch-rs/cargo-nx/wiki + +[package.metadata.nx.nro.nacp] +default_name = "uwurandom-nx" +default_author = "skyevg" +version = "0.1.0" +application_id = "0x010018160C3AFA2D" diff --git a/Inter-Regular.ttf b/Inter-Regular.ttf new file mode 100644 index 0000000..8d4eebf Binary files /dev/null and b/Inter-Regular.ttf differ diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..7b9e7dc --- /dev/null +++ b/flake.lock @@ -0,0 +1,94 @@ +{ + "nodes": { + "flake-utils": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "locked": { + "lastModified": 1659877975, + "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1672525397, + "narHash": "sha256-WASDnyxHKWVrEe0dIzkpH+jzKlCKAk0husv0f/9pyxg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "8ba56d7c0d7490680f2d51ba46a141eca7c46afa", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1665296151, + "narHash": "sha256-uOB0oxqxN9K7XGF1hcnY+PQnlQJ+3bP2vCn/+Ru/bbc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "14ccaaedd95a488dd7ae142757884d8e125b3363", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1672712534, + "narHash": "sha256-8S0DdMPcbITnlOu0uA81mTo3hgX84wK8S9wS34HEFY4=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "69fb7bf0a8c40e6c4c197fa1816773774c8ac59f", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..4ea6e8a --- /dev/null +++ b/flake.nix @@ -0,0 +1,25 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + rust-overlay.url = "github:oxalica/rust-overlay"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, rust-overlay, flake-utils, ... }: + flake-utils.lib.eachDefaultSystem (system: + let + overlays = [ (import rust-overlay) ]; + pkgs = import nixpkgs { inherit system overlays; }; + in + with pkgs; { + devShells.default = mkShell { + buildInputs = [ + (rust-bin.selectLatestNightlyWith (toolchain: + toolchain.default.override { + extensions = [ "rust-src" ]; + targets = [ "thumbv6m-none-eabi" ]; + })) + ]; + }; + }); +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ac41d45 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,192 @@ +#![no_std] +#![no_main] + +extern crate alloc; +use alloc::string::String; +use alloc::vec::Vec; + +extern crate nx; +use nx::diag::abort; +use nx::diag::log::lm::LmLogger; +use nx::gpu; +use nx::input; +use nx::rand::RandomGenerator; +use nx::result::*; +use nx::service::hid; +use nx::svc; +use nx::util; +use rand_core::RngCore; +use uwurandom_rs::StateMachine; + +use core::panic; + +extern crate ui2d; + +#[no_mangle] +pub fn initialize_heap(hbl_heap: util::PointerAndSize) -> util::PointerAndSize { + if hbl_heap.is_valid() { + hbl_heap + } else { + let heap_size: usize = 0x10000000; + let heap_address = svc::set_heap_size(heap_size).unwrap(); + util::PointerAndSize::new(heap_address, heap_size) + } +} + +pub struct Square { + x: i32, + y: i32, + size: i32, + x_incr: i32, + y_incr: i32, + x_mult: i32, + y_mult: i32, + color: ui2d::RGBA8, +} + +impl Square { + pub fn new(x: i32, y: i32, size: i32, color: ui2d::RGBA8) -> Self { + Self { + x: x, + y: y, + size: size, + x_incr: 1, + y_incr: 1, + x_mult: 1, + y_mult: 1, + color: color, + } + } + + pub fn handle_render(&mut self, surface: &mut ui2d::SurfaceEx) { + surface.draw(self.x, self.y, self.size, self.size, self.color, false); + + self.x += self.x_incr * self.x_mult; + self.y += self.y_incr * self.y_mult; + + if self.x <= 0 { + if self.x_incr < 0 { + self.x_incr -= 1; + self.x_incr = -self.x_incr; + } + self.x += self.x_incr * self.x_mult; + self.x_mult += 1; + } else if (self.x + self.size) as u32 >= surface.get_width() { + if self.x_incr > 0 { + self.x_incr += 1; + self.x_incr = -self.x_incr; + } + self.x += self.x_incr * self.x_mult; + self.x_mult += 1; + } + + if self.y <= 0 { + if self.y_incr < 0 { + self.y_incr -= 1; + self.y_incr = -self.y_incr; + } + self.y += self.y_incr * self.y_mult; + self.y_mult += 1; + } else if (self.y + self.size) as u32 >= surface.get_height() { + if self.y_incr > 0 { + self.y_incr += 1; + self.y_incr = -self.y_incr; + } + self.y += self.y_incr * self.y_mult; + self.y_mult += 1; + } + } +} + +struct NxRngWrap(nx::rand::SplCsrngGenerator); + +impl RngCore for NxRngWrap { + fn next_u32(&mut self) -> u32 { + rand_core::impls::next_u32_via_fill(self) + } + + fn next_u64(&mut self) -> u64 { + rand_core::impls::next_u64_via_fill(self) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.random_bytes(dest.as_ptr() as _, dest.len()).unwrap() + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> core::result::Result<(), rand_core::Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl NxRngWrap { + fn new() -> Self { + Self(nx::rand::SplCsrngGenerator::new().unwrap()) + } +} + +#[no_mangle] +pub fn main() -> Result<()> { + let mut gpu_ctx = gpu::Context::new( + gpu::NvDrvServiceKind::Applet, + gpu::ViServiceKind::System, + 0x800000, + )?; + + let supported_style_tags = hid::NpadStyleTag::Handheld(); + let supported_npad_ids = [hid::NpadIdType::Handheld]; + let input_ctx = input::Context::new(supported_style_tags, &supported_npad_ids)?; + + let color_fmt = gpu::ColorFormat::A8B8G8R8; + + let c_white = ui2d::RGBA8::new_rgb(0xFF, 0xFF, 0xFF); + let c_black = ui2d::RGBA8::new_rgb(0, 0, 0); + + let font_data = include_bytes!("../Inter-Regular.ttf"); + let font = ui2d::Font::try_from_bytes(font_data as &[u8]).unwrap(); + + let mut surface = ui2d::SurfaceEx::from(gpu_ctx.create_stray_layer_surface( + "Default", + 2, + color_fmt, + gpu::PixelFormat::RGBA_8888, + gpu::Layout::BlockLinear, + )?); + + let mut rng = NxRngWrap::new(); + + let mut uwurandom = StateMachine::new(&mut rng); + + let mut result = String::from("Press + to exit\n"); + + loop { + let mut p_handheld = input_ctx.get_player(hid::NpadIdType::Handheld); + + let buttons_down = p_handheld.get_buttons_down(); + if buttons_down.contains(hid::NpadButton::A()) { + let (new_state, generated) = uwurandom.generate(&mut rng); + uwurandom = new_state; + result.push(generated); + if result.lines().last().unwrap().len() > 100 { + result.push('\n'); + } + } else if buttons_down.contains(hid::NpadButton::Plus()) { + // Exit if Plus/+ is pressed. + break; + } + + surface.start()?; + + surface.clear(c_white); + surface.draw_font_text(&font, result.clone(), c_black, 25.0, 10, 10, true); + // surface.draw_bitmap_text(result.clone(), c_black, 2, 10, 250, true); + + surface.end()?; + } + + Ok(()) +} + +#[panic_handler] +fn panic_handler(info: &panic::PanicInfo) -> ! { + util::simple_panic_handler::(info, abort::AbortLevel::FatalThrow()) +} diff --git a/ui2d/.cargo/config.toml b/ui2d/.cargo/config.toml new file mode 100644 index 0000000..f417b26 --- /dev/null +++ b/ui2d/.cargo/config.toml @@ -0,0 +1,3 @@ +[unstable] +build-std = ["core", "compiler_builtins", "alloc"] +build-std-features = ["compiler-builtins-mem"] \ No newline at end of file diff --git a/ui2d/Cargo.lock b/ui2d/Cargo.lock new file mode 100644 index 0000000..e4e2dcf --- /dev/null +++ b/ui2d/Cargo.lock @@ -0,0 +1,101 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13739d7177fbd22bb0ed28badfff9f372f8bef46c863db4e1c6248f6b223b6e" +dependencies = [ + "libm", +] + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "font8x8" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63201c624b8c8883921b1a1accc8916c4fa9dbfb15d122b26e4dde945b86bbf" + +[[package]] +name = "libm" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db" + +[[package]] +name = "linked_list_allocator" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "549ce1740e46b291953c4340adcd74c59bcf4308f4cac050fd33ba91b7168f4a" + +[[package]] +name = "logpacket" +version = "0.1.0" +source = "git+https://github.com/aarch64-switch-rs/logpacket#d807c993fb4578e3809d91e3484c7d97f59eb3db" + +[[package]] +name = "nx" +version = "0.1.0" +source = "git+https://github.com/aarch64-switch-rs/nx#bfa3d790e023acc6dbe07a3ac1f70987e6f62a28" +dependencies = [ + "arrayvec", + "linked_list_allocator", + "logpacket", + "paste", + "static_assertions", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "paste" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" + +[[package]] +name = "rusttype" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59" +dependencies = [ + "ab_glyph_rasterizer", + "libm", + "owned_ttf_parser", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "ttf-parser" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" + +[[package]] +name = "ui2d" +version = "0.1.0" +dependencies = [ + "font8x8", + "libm", + "nx", + "rusttype", +] diff --git a/ui2d/Cargo.toml b/ui2d/Cargo.toml new file mode 100644 index 0000000..6c19f7a --- /dev/null +++ b/ui2d/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "ui2d" +version = "0.1.0" +authors = ["XorTroll"] +edition = "2021" + +[dependencies] +nx = { git = "https://github.com/aarch64-switch-rs/nx", features = [ "gpu" ] } + +[dependencies.font8x8] +version = "0.2" +default-features = false +features = ["unicode"] + +[dependencies.rusttype] +version = "0.9.2" +default-features = false +features = ["libm-math"] + +[dependencies.libm] +version = "0.2.1" +default-features = false +features = [] diff --git a/ui2d/src/lib.rs b/ui2d/src/lib.rs new file mode 100644 index 0000000..882b369 --- /dev/null +++ b/ui2d/src/lib.rs @@ -0,0 +1,324 @@ +#![no_std] + +// Note: quite simple lib made for UI tests to easily render stuff + +use nx::result::*; +use nx::gpu; +use nx::arm; + +extern crate alloc; +use alloc::string::String; +use alloc::vec::Vec; +use core::ptr; +use core::mem; +use font8x8::UnicodeFonts; + +pub type Font<'a> = rusttype::Font<'a>; + +#[derive(Copy, Clone)] +pub struct RGBA8 { + pub r: u8, + pub g: u8, + pub b: u8, + pub a: u8, +} + +impl RGBA8 { + pub const fn new_rgba(r: u8, g: u8, b: u8, a: u8) -> Self { + Self { r: r, g: g, b: b, a: a } + } + + pub const fn new_rgb(r: u8, g: u8, b: u8) -> Self { + Self { r: r, g: g, b: b, a: 0xFF } + } + + const fn decode(raw: u32) -> (u8, u8, u8, u8) { + let a = (raw & 0xFF) as u8; + let b = ((raw >> 8) & 0xFF) as u8; + let c = ((raw >> 16) & 0xFF) as u8; + let d = ((raw >> 24) & 0xFF) as u8; + (a, b, c, d) + } + + pub const fn from_rgba(raw: u32) -> Self { + let (a, b, g, r) = Self::decode(raw); + Self::new_rgba(r, g, b, a) + } + + pub const fn from_abgr(raw: u32) -> Self { + let (r, g, b, a) = Self::decode(raw); + Self::new_rgba(r, g, b, a) + } + + const fn encode(a: u8, b: u8, c: u8, d: u8) -> u32 { + (a as u32 & 0xFF) | ((b as u32 & 0xFF) << 8) | ((c as u32 & 0xFF) << 16) | ((d as u32 & 0xFF) << 24) + } + + pub const fn encode_rgba(&self) -> u32 { + Self::encode(self.a, self.b, self.g, self.r) + } + + pub const fn encode_abgr(&self) -> u32 { + Self::encode(self.r, self.g, self.b, self.a) + } + + const fn blend_color_impl(src: u32, dst: u32, alpha: u32) -> u8 { + let one_minus_a = 0xFF - alpha; + ((dst * alpha + src * one_minus_a) / 0xFF) as u8 + } + + pub const fn blend_with(&self, other: Self) -> Self { + let r = Self::blend_color_impl(other.r as u32, self.r as u32, self.a as u32); + let g = Self::blend_color_impl(other.g as u32, self.g as u32, self.a as u32); + let b = Self::blend_color_impl(other.b as u32, self.b as u32, self.a as u32); + Self::new_rgb(r, g, b) + } +} + +pub struct SurfaceEx { + gpu_buf: *mut u32, + gpu_buf_size: usize, + linear_buf: *mut u32, + linear_buf_size: usize, + slot: i32, + fences: gpu::MultiFence, + surface_ref: gpu::surface::Surface, +} + +impl SurfaceEx { + pub fn from(surface: gpu::surface::Surface) -> Self { + let aligned_width = surface.compute_stride() as usize; + let aligned_height = ((surface.get_height() + 7) & !7) as usize; + let linear_buf_size = aligned_width * aligned_height; + unsafe { + let linear_buf_layout = alloc::alloc::Layout::from_size_align_unchecked(linear_buf_size, 8); + let linear_buf = alloc::alloc::alloc_zeroed(linear_buf_layout); + Self { gpu_buf: ptr::null_mut(), gpu_buf_size: 0, linear_buf: linear_buf as *mut u32, linear_buf_size: linear_buf_size, slot: 0, fences: mem::zeroed(), surface_ref: surface } + } + } + + pub fn start(&mut self) -> Result<()> { + let (buf, buf_size, slot, _has_fences, fences) = self.surface_ref.dequeue_buffer(true)?; + self.gpu_buf = buf as *mut u32; + self.gpu_buf_size = buf_size; + self.slot = slot; + self.fences = fences; + self.surface_ref.wait_fences(fences, -1) + } + + pub fn get_surface(&mut self) -> &mut gpu::surface::Surface { + &mut self.surface_ref + } + + fn convert_buffers_gob_impl(out_gob_buf: *mut u8, in_gob_buf: *mut u8, stride: u32) { + unsafe { + let mut tmp_out_gob_buf_128 = out_gob_buf as *mut u128; + for i in 0..32 { + let y = ((i >> 1) & 0x6) | (i & 0x1); + let x = ((i << 3) & 0x10) | ((i << 1) & 0x20); + let out_gob_buf_128 = tmp_out_gob_buf_128 as *mut u128; + let in_gob_buf_128 = in_gob_buf.offset((y * stride + x) as isize) as *mut u128; + *out_gob_buf_128 = *in_gob_buf_128; + tmp_out_gob_buf_128 = tmp_out_gob_buf_128.offset(1); + } + } + } + + fn convert_buffers_impl(out_buf: *mut u8, in_buf: *mut u8, stride: u32, height: u32) { + let block_height_gobs = 1 << gpu::BLOCK_HEIGHT_LOG2; + let block_height_px = 8 << gpu::BLOCK_HEIGHT_LOG2; + + let width_blocks = stride >> 6; + let height_blocks = (height + block_height_px - 1) >> (3 + gpu::BLOCK_HEIGHT_LOG2); + let mut tmp_out_buf = out_buf; + + for block_y in 0..height_blocks { + for block_x in 0..width_blocks { + for gob_y in 0..block_height_gobs { + unsafe { + let x = block_x * 64; + let y = block_y * block_height_px + gob_y * 8; + if y < height { + let in_gob_buf = in_buf.offset((y * stride + x) as isize); + Self::convert_buffers_gob_impl(tmp_out_buf, in_gob_buf, stride); + } + tmp_out_buf = tmp_out_buf.offset(512); + } + } + } + } + } + + pub fn end(&mut self) -> Result<()> { + Self::convert_buffers_impl(self.gpu_buf as *mut u8, self.linear_buf as *mut u8, self.surface_ref.compute_stride(), self.surface_ref.get_height()); + arm::cache_flush(self.gpu_buf as *mut u8, self.gpu_buf_size); + self.surface_ref.queue_buffer(self.slot, self.fences)?; + self.surface_ref.wait_vsync_event(-1) + } + + pub fn clear(&mut self, color: RGBA8) { + unsafe { + let buf_size_32 = self.linear_buf_size / mem::size_of::(); + for i in 0..buf_size_32 { + let cur = self.linear_buf.offset(i as isize); + *cur = color.encode_abgr(); + } + } + } + + pub fn draw_single(&mut self, x: i32, y: i32, color: RGBA8, blend: bool) { + unsafe { + let offset = ((self.surface_ref.compute_stride() / mem::size_of::() as u32) as i32 * y + x) as isize; + let cur = self.linear_buf.offset(offset); + let old_color = RGBA8::from_abgr(*cur); + let new_color = match blend { + true => color.blend_with(old_color), + false => color, + }; + *cur = new_color.encode_abgr(); + } + } + + fn clamp(max: i32, value: i32) -> i32 { + if value < 0 { + return 0; + } + if value > max { + return max; + } + value + } + + pub fn get_width(&self) -> u32 { + self.surface_ref.get_width() + } + + pub fn get_height(&self) -> u32 { + self.surface_ref.get_height() + } + + pub fn get_color_format(&self) -> gpu::ColorFormat { + self.surface_ref.get_color_format() + } + + pub fn draw(&mut self, x: i32, y: i32, width: i32, height: i32, color: RGBA8, blend: bool) { + let s_width = self.surface_ref.get_width() as i32; + let s_height = self.surface_ref.get_height() as i32; + let x0 = Self::clamp(s_width, x); + let x1 = Self::clamp(s_width, x + width); + let y0 = Self::clamp(s_height, y); + let y1 = Self::clamp(s_height, y + height); + for y in y0..y1 { + for x in x0..x1 { + self.draw_single(x, y, color, blend); + } + } + } + + fn draw_font_text_impl(&mut self, font: &rusttype::Font, text: &str, color: RGBA8, scale: rusttype::Scale, v_metrics: rusttype::VMetrics, x: i32, y: i32, blend: bool) { + let glyphs: Vec<_> = font.layout(&text[..], scale, rusttype::point(0.0, v_metrics.ascent)).collect(); + for glyph in &glyphs { + if let Some(bounding_box) = glyph.pixel_bounding_box() { + // Draw the glyph into the image per-pixel by using the draw closure + glyph.draw(|g_x, g_y, g_v| { + let mut pix_color = color; + // Different alpha depending on the pixel + pix_color.a = (g_v * 255.0) as u8; + self.draw_single(x + g_x as i32 + bounding_box.min.x as i32, y + g_y as i32 + bounding_box.min.y as i32, pix_color, blend); + }); + } + } + } + + pub fn draw_font_text(&mut self, font: &rusttype::Font, text: String, color: RGBA8, size: f32, x: i32, y: i32, blend: bool) { + let scale = rusttype::Scale::uniform(size); + let v_metrics = font.v_metrics(scale); + + let mut tmp_y = y; + for semi_text in text.lines() { + self.draw_font_text_impl(font, semi_text, color, scale, v_metrics, x, tmp_y, blend); + tmp_y += v_metrics.ascent as i32; + } + } + + pub fn draw_bitmap_text(&mut self, text: String, color: RGBA8, scale: i32, x: i32, y: i32, blend: bool) { + let mut tmp_x = x; + let mut tmp_y = y; + for c in text.chars() { + match c { + '\n' | '\r' => { + tmp_y += 8 * scale; + tmp_x = x; + }, + _ => { + if let Some(glyph) = font8x8::BASIC_FONTS.get(c) { + let char_tmp_x = tmp_x; + let char_tmp_y = tmp_y; + for gx in &glyph { + for bit in 0..8 { + match *gx & 1 << bit { + 0 => {}, + _ => { + self.draw(tmp_x, tmp_y, scale, scale, color, blend); + }, + } + tmp_x += scale; + } + tmp_y += scale; + tmp_x = char_tmp_x; + } + tmp_x += 8 * scale; + tmp_y = char_tmp_y; + } + } + } + } + } +} + +impl Drop for SurfaceEx { + fn drop(&mut self) { + unsafe { + let linear_buf_layout = alloc::alloc::Layout::from_size_align_unchecked(self.linear_buf_size, 8); + alloc::alloc::dealloc(self.linear_buf as *mut u8, linear_buf_layout); + } + } +} + +// Needed by rusttype + +pub trait FloatExt { + fn floor(self) -> Self; + fn ceil(self) -> Self; + fn fract(self) -> Self; + fn trunc(self) -> Self; + fn round(self) -> Self; + fn abs(self) -> Self; +} + +impl FloatExt for f32 { + #[inline] + fn floor(self) -> Self { + libm::floorf(self) + } + #[inline] + fn ceil(self) -> Self { + libm::ceilf(self) + } + #[inline] + fn fract(self) -> Self { + self - self.trunc() + } + #[inline] + fn trunc(self) -> Self { + libm::truncf(self) + } + #[inline] + fn round(self) -> Self { + libm::roundf(self) + } + #[inline] + fn abs(self) -> Self { + libm::fabsf(self) + } +} \ No newline at end of file