Skip to content

Instantly share code, notes, and snippets.

@rtsuk
Created May 17, 2020 23:08
Show Gist options
  • Save rtsuk/bd7fd934c94c5569d271e737625c19b1 to your computer and use it in GitHub Desktop.
Save rtsuk/bd7fd934c94c5569d271e737625c19b1 to your computer and use it in GitHub Desktop.
#![no_std]
use {
playdate::{graphics::Graphics, system::System, Playdate},
playdate_sys::{
PDButtons_kButtonA, PDSystemEvent, PDSystemEvent_kEventInit, PlaydateAPI, LCD_COLUMNS,
LCD_ROWS, LCD_ROWSIZE,
},
rand::{rngs::SmallRng, Rng, SeedableRng},
};
const LIMIT: usize = (LCD_COLUMNS - 1) as usize;
fn ison(row: &'static [u8], x: usize) -> bool {
(row[x / 8] & (0x80 >> (x % 8))) == 0
}
fn val(row: &'static [u8], x: usize) -> u8 {
1 - ((row[x / 8] >> (7 - (x % 8))) & 1)
}
fn rowsum(row: &'static [u8], x: usize) -> u8 {
if x == 0 {
val(row, LIMIT) + val(row, x) + val(row, x + 1)
} else if x < LIMIT {
return val(row, x - 1) + val(row, x) + val(row, x + 1);
} else {
val(row, x - 1) + val(row, x) + val(row, 0)
}
}
fn middlerowsum(row: &'static [u8], x: usize) -> u8 {
if x == 0 {
val(row, LIMIT) + val(row, x + 1)
} else if x < LIMIT {
val(row, x - 1) + val(row, x + 1)
} else {
val(row, x - 1) + val(row, 0)
}
}
fn do_row<'a>(
lastrow: &'static [u8],
row: &'static [u8],
nextrow: &'static [u8],
outrow: &'a mut [u8],
) {
let mut b = 0;
let mut bitpos = 0x80;
for x in 0..(LCD_COLUMNS as usize) {
// If total is 3 cell is alive
// If total is 4, no change
// Else, cell is dead
let sum = rowsum(lastrow, x) + middlerowsum(row, x) + rowsum(nextrow, x);
if sum == 3 || (ison(row, x) && sum == 2) {
b |= bitpos;
}
bitpos >>= 1;
if bitpos == 0 {
outrow[x / 8] = !b;
b = 0;
bitpos = 0x80;
}
}
}
fn randomize(graphics: &Graphics, rng: &mut SmallRng) {
let frame = graphics.get_display_frame();
for element in &mut frame[..] {
*element = rng.gen();
}
}
struct State {
graphics: Graphics,
system: System,
rng: SmallRng,
started: bool,
}
const LAST_ROW_INDEX: usize = ((LCD_ROWS - 1) * LCD_ROWSIZE) as usize;
const LAST_ROW_LIMIT: usize = LAST_ROW_INDEX + LCD_ROWSIZE as usize;
impl State {
pub fn update(&mut self) {
if !self.started {
randomize(&self.graphics, &mut self.rng);
self.started = true;
}
let (_, pushed, _) = self.system.get_button_state();
if (pushed & PDButtons_kButtonA) != 0 {
randomize(&self.graphics, &mut self.rng);
}
let frame = self.graphics.get_frame();
if let Some(frame) = frame {
let last_frame = self.graphics.get_display_frame();
let mut last_row = &last_frame[LAST_ROW_INDEX..LAST_ROW_LIMIT];
let mut row = &last_frame[0..LCD_ROWSIZE as usize];
let mut next_row = &last_frame[LCD_ROWSIZE as usize..(LCD_ROWSIZE * 2) as usize];
for y in 0..LCD_ROWS {
let index = (y * LCD_ROWSIZE) as usize;
let limit = index + LCD_ROWSIZE as usize;
do_row(last_row, row, next_row, &mut frame[index..limit]);
last_row = row;
row = next_row;
let next_row_index = (y + 2) % LCD_ROWS;
let index = (next_row_index * LCD_ROWSIZE) as usize;
let limit = index + LCD_ROWSIZE as usize;
next_row = &last_frame[index..limit];
}
}
self.graphics.mark_updated_rows(-1, -1);
}
}
static mut STATE: Option<State> = None;
#[no_mangle]
extern "C" fn update(_user_data: *mut core::ffi::c_void) -> i32 {
let state = unsafe { STATE.as_mut().expect("state") };
state.update();
1
}
#[no_mangle]
extern "C" fn eventHandler(
playdate: *mut PlaydateAPI,
event: PDSystemEvent,
_arg: u32,
) -> playdate_sys::ctypes::c_int {
if event == PDSystemEvent_kEventInit {
let small_rng = SmallRng::seed_from_u64(3);
let playdate = Playdate::new(playdate);
let system = playdate.system();
let graphics = playdate.graphics();
system.set_update_callback(Some(update));
unsafe {
STATE = Some(State {
graphics: graphics,
system: system,
rng: small_rng,
started: false,
});
}
}
0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment