feat: use frame buffer for rendering
This commit is contained in:
parent
432191b718
commit
a265b857d0
5 changed files with 85 additions and 154 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
|||
use flake
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
/target
|
||||
.direnv
|
||||
*.fd
|
||||
esp
|
||||
|
|
68
Cargo.lock
generated
68
Cargo.lock
generated
|
@ -14,37 +14,12 @@ version = "2.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
|
||||
dependencies = [
|
||||
"hash32",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
|
@ -62,22 +37,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ptr_meta"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607"
|
||||
checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90"
|
||||
dependencies = [
|
||||
"ptr_meta_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta_derive"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2"
|
||||
checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -89,23 +64,6 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.92"
|
||||
|
@ -128,9 +86,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uefi"
|
||||
version = "0.33.0"
|
||||
version = "0.34.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6679b7fc2f6d6d2ea2f67555ef3ed9d71d30c5021faf9193091a5192db7dc468"
|
||||
checksum = "c25038e420a68d30a0e8002a3b51c075ad2342f5ae7a2383f042bd41fef73272"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
|
@ -146,30 +104,28 @@ dependencies = [
|
|||
name = "uefi-gol"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"heapless",
|
||||
"log",
|
||||
"uefi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uefi-macros"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b24e77d3fc1e617051e630f99da24bcae6328abab37b8f9216bb68d06804f9a"
|
||||
checksum = "72cb3027736dad1b6f23437c63249025d960377fe7f9f769a111dfbc0dd2bdda"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.92",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uefi-raw"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6d465de2c918779dafb769a5a4fe8d6e4fb7cc4cc6cb1a735f2f6ec68beea4"
|
||||
checksum = "d246ed5d6fd71c0331f0ac774a6aefb6cb9170a46f83148cacc70b09f82c87bb"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"ptr_meta",
|
||||
"uguid",
|
||||
]
|
||||
|
||||
|
|
|
@ -6,6 +6,5 @@ authors = [ "Tim Schubert <dadada@dadada.li>"]
|
|||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
heapless = "0.8.0"
|
||||
log = "0.4.22"
|
||||
uefi = { version = "0.33.0", features = ["logger", "panic_handler"] }
|
||||
uefi = { version = "0.34.0", features = ["logger", "global_allocator", "panic_handler"] }
|
||||
|
|
166
src/main.rs
166
src/main.rs
|
@ -1,55 +1,45 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use core::{
|
||||
fmt::Write,
|
||||
iter::repeat,
|
||||
ops::{Deref, DerefMut},
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use core::iter::repeat;
|
||||
|
||||
use uefi::{
|
||||
prelude::*,
|
||||
proto::console::gop::{BltOp::BufferToVideo, BltPixel, BltRegion, GraphicsOutput},
|
||||
Result,
|
||||
};
|
||||
|
||||
use heapless::{String, Vec};
|
||||
use system::with_stdout;
|
||||
use uefi::prelude::*;
|
||||
|
||||
const WIDTH: usize = 30;
|
||||
const HEIGHT: usize = 30;
|
||||
|
||||
type Matrix = Vec<Vec<bool, WIDTH>, HEIGHT>;
|
||||
const ALIVE: BltPixel = BltPixel::new(0xff, 0xff, 0xff);
|
||||
const DEAD: BltPixel = BltPixel::new(0, 0, 0);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Life {
|
||||
matrix: Matrix,
|
||||
}
|
||||
|
||||
impl Deref for Life {
|
||||
type Target = Matrix;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.matrix
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Life {
|
||||
fn default() -> Self {
|
||||
let mut matrix: Vec<Vec<bool, WIDTH>, HEIGHT> = Vec::default();
|
||||
for _ in 0..HEIGHT {
|
||||
matrix.push(repeat(false).take(WIDTH).collect()).unwrap();
|
||||
}
|
||||
Life { matrix }
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Life {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.matrix
|
||||
}
|
||||
height: usize,
|
||||
matrix: Vec<BltPixel>,
|
||||
width: usize,
|
||||
}
|
||||
|
||||
impl Life {
|
||||
fn with_starter(starter: &[(usize, usize)]) -> Self {
|
||||
let mut life = Self::default();
|
||||
fn new(width: usize, height: usize) -> Self {
|
||||
let mut matrix = Vec::default();
|
||||
for _ in 0..height {
|
||||
matrix.extend(repeat(DEAD).take(width));
|
||||
}
|
||||
Life {
|
||||
matrix,
|
||||
width,
|
||||
height,
|
||||
}
|
||||
}
|
||||
|
||||
fn with_starter(width: usize, height: usize, starter: &[(usize, usize)]) -> Self {
|
||||
let mut life = Self::new(width, height);
|
||||
for (i, j) in starter.iter() {
|
||||
life[*i][*j] = true;
|
||||
life.matrix[i * width + j] = ALIVE;
|
||||
}
|
||||
life
|
||||
}
|
||||
|
@ -65,85 +55,69 @@ impl Life {
|
|||
(1, 0),
|
||||
(1, 1),
|
||||
];
|
||||
let mut future = Life::default();
|
||||
self.iter().enumerate().for_each(|(row, line)| {
|
||||
line.iter().enumerate().for_each(|(column, alive)| {
|
||||
let mut future = Self::new(self.width, self.height);
|
||||
for h in 0..self.height {
|
||||
for w in 0..self.width {
|
||||
let alive = self.matrix[h * self.width + w];
|
||||
let neighbors = OFFSETS
|
||||
.iter()
|
||||
.filter(|offset| {
|
||||
let height = (row as i64) + offset.0;
|
||||
let width = (column as i64) + offset.1;
|
||||
height >= 0
|
||||
&& width >= 0
|
||||
&& (height as usize) < HEIGHT
|
||||
&& (width as usize) < WIDTH
|
||||
&& self[height as usize][width as usize]
|
||||
let height = (h as i64) + offset.0;
|
||||
let width = (w as i64) + offset.1;
|
||||
self.is_neighbor_alive(height, width)
|
||||
})
|
||||
.count();
|
||||
future[row][column] = neighbors == 3 || *alive && neighbors == 2;
|
||||
})
|
||||
});
|
||||
future.matrix[h * self.width + w] = if can_replicate(alive, neighbors) {
|
||||
ALIVE
|
||||
} else {
|
||||
DEAD
|
||||
};
|
||||
}
|
||||
}
|
||||
future
|
||||
}
|
||||
|
||||
/// Buffers output into one string per frame since println does not buffer output in uefi-rs.
|
||||
fn render(&self) -> Frame {
|
||||
let mut frame = Frame::default();
|
||||
for l in self.iter() {
|
||||
for cell in l.iter() {
|
||||
if *cell {
|
||||
frame.push('X').unwrap()
|
||||
} else {
|
||||
frame.push(' ').unwrap()
|
||||
}
|
||||
fn is_neighbor_alive(&self, height: i64, width: i64) -> bool {
|
||||
height >= 0
|
||||
&& width >= 0
|
||||
&& (height as usize) < self.height
|
||||
&& (width as usize) < self.width
|
||||
&& {
|
||||
let neighbor = self.matrix[height as usize * self.width + width as usize];
|
||||
neighbor.blue != 0 || neighbor.green != 0 || neighbor.red != 0
|
||||
}
|
||||
frame.push('\n').unwrap()
|
||||
}
|
||||
frame
|
||||
}
|
||||
|
||||
/// Blits entire display
|
||||
fn render(&self, gop: &mut GraphicsOutput) -> Result {
|
||||
gop.blt(BufferToVideo {
|
||||
buffer: &self.matrix,
|
||||
src: BltRegion::Full,
|
||||
dest: (0, 0),
|
||||
dims: (self.width, self.height),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type FrameBuffer = String<{ (WIDTH * HEIGHT) + HEIGHT }>;
|
||||
|
||||
#[derive(Default)]
|
||||
struct Frame {
|
||||
buffer: FrameBuffer,
|
||||
fn can_replicate(alive: BltPixel, neighbors: usize) -> bool {
|
||||
neighbors == 3 || (alive.blue != 0 || alive.green != 0 || alive.red != 0) && neighbors == 2
|
||||
}
|
||||
|
||||
impl Deref for Frame {
|
||||
type Target = FrameBuffer;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Frame {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
const BREEDER: &[(usize, usize)] = &[(15, 16), (16, 15), (16, 16), (17, 16), (17, 17)];
|
||||
const RENDER_DELAY: usize = 100_000;
|
||||
const BREEDER: &[(usize, usize)] = &[(415, 416), (416, 415), (416, 416), (417, 416), (417, 417)];
|
||||
|
||||
#[entry]
|
||||
fn main() -> Status {
|
||||
uefi::helpers::init().unwrap();
|
||||
|
||||
let mut life = Life::with_starter(BREEDER);
|
||||
let mut life = Life::with_starter(800, 600, BREEDER);
|
||||
let gop_handle = boot::get_handle_for_protocol::<GraphicsOutput>().unwrap();
|
||||
let mut gop = boot::open_protocol_exclusive::<GraphicsOutput>(gop_handle).unwrap();
|
||||
|
||||
for _ in repeat(()) {
|
||||
life = life.play();
|
||||
|
||||
let frame = life.render();
|
||||
with_stdout(|stdout| {
|
||||
stdout.reset(true).unwrap();
|
||||
stdout.write_str(&frame).unwrap()
|
||||
});
|
||||
// Stall the loop a bit so it is easier to watch
|
||||
boot::stall(RENDER_DELAY);
|
||||
life.render(&mut gop).unwrap();
|
||||
}
|
||||
|
||||
Status::SUCCESS
|
||||
unreachable!()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue