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
|
/target
|
||||||
|
.direnv
|
||||||
*.fd
|
*.fd
|
||||||
esp
|
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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "byteorder"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
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]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.22"
|
version = "0.4.22"
|
||||||
|
@ -62,22 +37,22 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ptr_meta"
|
name = "ptr_meta"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607"
|
checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ptr_meta_derive",
|
"ptr_meta_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ptr_meta_derive"
|
name = "ptr_meta_derive"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2"
|
checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -89,23 +64,6 @@ dependencies = [
|
||||||
"proc-macro2",
|
"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]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.92"
|
version = "2.0.92"
|
||||||
|
@ -128,9 +86,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uefi"
|
name = "uefi"
|
||||||
version = "0.33.0"
|
version = "0.34.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6679b7fc2f6d6d2ea2f67555ef3ed9d71d30c5021faf9193091a5192db7dc468"
|
checksum = "c25038e420a68d30a0e8002a3b51c075ad2342f5ae7a2383f042bd41fef73272"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
@ -146,30 +104,28 @@ dependencies = [
|
||||||
name = "uefi-gol"
|
name = "uefi-gol"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heapless",
|
|
||||||
"log",
|
"log",
|
||||||
"uefi",
|
"uefi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uefi-macros"
|
name = "uefi-macros"
|
||||||
version = "0.17.0"
|
version = "0.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b24e77d3fc1e617051e630f99da24bcae6328abab37b8f9216bb68d06804f9a"
|
checksum = "72cb3027736dad1b6f23437c63249025d960377fe7f9f769a111dfbc0dd2bdda"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.92",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uefi-raw"
|
name = "uefi-raw"
|
||||||
version = "0.9.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f6d465de2c918779dafb769a5a4fe8d6e4fb7cc4cc6cb1a735f2f6ec68beea4"
|
checksum = "d246ed5d6fd71c0331f0ac774a6aefb6cb9170a46f83148cacc70b09f82c87bb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"ptr_meta",
|
|
||||||
"uguid",
|
"uguid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,5 @@ authors = [ "Tim Schubert <dadada@dadada.li>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
heapless = "0.8.0"
|
|
||||||
log = "0.4.22"
|
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_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
use core::{
|
extern crate alloc;
|
||||||
fmt::Write,
|
|
||||||
iter::repeat,
|
use alloc::vec::Vec;
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
|
use core::iter::repeat;
|
||||||
|
|
||||||
|
use uefi::{
|
||||||
|
prelude::*,
|
||||||
|
proto::console::gop::{BltOp::BufferToVideo, BltPixel, BltRegion, GraphicsOutput},
|
||||||
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
use heapless::{String, Vec};
|
const ALIVE: BltPixel = BltPixel::new(0xff, 0xff, 0xff);
|
||||||
use system::with_stdout;
|
const DEAD: BltPixel = BltPixel::new(0, 0, 0);
|
||||||
use uefi::prelude::*;
|
|
||||||
|
|
||||||
const WIDTH: usize = 30;
|
|
||||||
const HEIGHT: usize = 30;
|
|
||||||
|
|
||||||
type Matrix = Vec<Vec<bool, WIDTH>, HEIGHT>;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Life {
|
struct Life {
|
||||||
matrix: Matrix,
|
height: usize,
|
||||||
}
|
matrix: Vec<BltPixel>,
|
||||||
|
width: usize,
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Life {
|
impl Life {
|
||||||
fn with_starter(starter: &[(usize, usize)]) -> Self {
|
fn new(width: usize, height: usize) -> Self {
|
||||||
let mut life = Self::default();
|
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() {
|
for (i, j) in starter.iter() {
|
||||||
life[*i][*j] = true;
|
life.matrix[i * width + j] = ALIVE;
|
||||||
}
|
}
|
||||||
life
|
life
|
||||||
}
|
}
|
||||||
|
@ -65,85 +55,69 @@ impl Life {
|
||||||
(1, 0),
|
(1, 0),
|
||||||
(1, 1),
|
(1, 1),
|
||||||
];
|
];
|
||||||
let mut future = Life::default();
|
let mut future = Self::new(self.width, self.height);
|
||||||
self.iter().enumerate().for_each(|(row, line)| {
|
for h in 0..self.height {
|
||||||
line.iter().enumerate().for_each(|(column, alive)| {
|
for w in 0..self.width {
|
||||||
|
let alive = self.matrix[h * self.width + w];
|
||||||
let neighbors = OFFSETS
|
let neighbors = OFFSETS
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|offset| {
|
.filter(|offset| {
|
||||||
let height = (row as i64) + offset.0;
|
let height = (h as i64) + offset.0;
|
||||||
let width = (column as i64) + offset.1;
|
let width = (w as i64) + offset.1;
|
||||||
height >= 0
|
self.is_neighbor_alive(height, width)
|
||||||
&& width >= 0
|
|
||||||
&& (height as usize) < HEIGHT
|
|
||||||
&& (width as usize) < WIDTH
|
|
||||||
&& self[height as usize][width as usize]
|
|
||||||
})
|
})
|
||||||
.count();
|
.count();
|
||||||
future[row][column] = neighbors == 3 || *alive && neighbors == 2;
|
future.matrix[h * self.width + w] = if can_replicate(alive, neighbors) {
|
||||||
})
|
ALIVE
|
||||||
});
|
} else {
|
||||||
|
DEAD
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
future
|
future
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Buffers output into one string per frame since println does not buffer output in uefi-rs.
|
fn is_neighbor_alive(&self, height: i64, width: i64) -> bool {
|
||||||
fn render(&self) -> Frame {
|
height >= 0
|
||||||
let mut frame = Frame::default();
|
&& width >= 0
|
||||||
for l in self.iter() {
|
&& (height as usize) < self.height
|
||||||
for cell in l.iter() {
|
&& (width as usize) < self.width
|
||||||
if *cell {
|
&& {
|
||||||
frame.push('X').unwrap()
|
let neighbor = self.matrix[height as usize * self.width + width as usize];
|
||||||
} else {
|
neighbor.blue != 0 || neighbor.green != 0 || neighbor.red != 0
|
||||||
frame.push(' ').unwrap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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 }>;
|
fn can_replicate(alive: BltPixel, neighbors: usize) -> bool {
|
||||||
|
neighbors == 3 || (alive.blue != 0 || alive.green != 0 || alive.red != 0) && neighbors == 2
|
||||||
#[derive(Default)]
|
|
||||||
struct Frame {
|
|
||||||
buffer: FrameBuffer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Frame {
|
const BREEDER: &[(usize, usize)] = &[(415, 416), (416, 415), (416, 416), (417, 416), (417, 417)];
|
||||||
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;
|
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> Status {
|
fn main() -> Status {
|
||||||
uefi::helpers::init().unwrap();
|
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(()) {
|
for _ in repeat(()) {
|
||||||
life = life.play();
|
life = life.play();
|
||||||
|
|
||||||
let frame = life.render();
|
life.render(&mut gop).unwrap();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Status::SUCCESS
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue