Compare commits

...

2 commits

Author SHA1 Message Date
365035a64d basic rule editing 2024-05-01 00:05:20 +02:00
aa4cec6dbf refactor 2024-04-30 23:58:57 +02:00
2 changed files with 69 additions and 40 deletions

View file

@ -2,11 +2,8 @@ use rand::prelude::*;
pub const CHUNK_SIZE: usize = 32; pub const CHUNK_SIZE: usize = 32;
#[derive(Debug, Default, PartialEq, Clone)] #[derive(Default, Debug, PartialEq, Clone, Copy)]
pub struct Cell(pub u8, pub u8, pub u8); pub struct Cell(pub u16);
#[derive(Debug)]
pub struct Pos2(i8, i8);
#[derive(Debug)] #[derive(Debug)]
pub struct Dish { pub struct Dish {
@ -42,7 +39,7 @@ impl Chunk {
for col in self.contents.iter_mut() { for col in self.contents.iter_mut() {
for cell in col.iter_mut() { for cell in col.iter_mut() {
if random::<u8>() % 4 == 0 { if random::<u8>() % 4 == 0 {
*cell = Cell::PINK; *cell = Cell(1);
} }
} }
} }
@ -62,41 +59,42 @@ impl Dish {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
chunk: Chunk::new().fill_random(), chunk: Chunk::new().fill_random(),
rules: vec![ rules: vec![
Rule { Rule {
from: RulePattern { from: RulePattern {
width: 1, width: 1,
height: 2, height: 2,
contents: vec![Some(Cell::PINK), Some(Cell::EMPTY)], contents: vec![Some(Cell(1)), Some(Cell(0))],
}, },
to: RulePattern { to: RulePattern {
width: 1, width: 1,
height: 2, height: 2,
contents: vec![Some(Cell::EMPTY), Some(Cell::PINK)], contents: vec![Some(Cell(0)), Some(Cell(1))],
}, },
}, },
Rule { Rule {
from: RulePattern { from: RulePattern {
width: 2, width: 2,
height: 2, height: 2,
contents: vec![Some(Cell::PINK), None, Some(Cell::PINK), Some(Cell::EMPTY)], contents: vec![Some(Cell(1)), None, Some(Cell(1)), Some(Cell(0))],
}, },
to: RulePattern { to: RulePattern {
width: 2, width: 2,
height: 2, height: 2,
contents: vec![Some(Cell::EMPTY), None, Some(Cell::PINK), Some(Cell::PINK)], contents: vec![Some(Cell(0)), None, Some(Cell(1)), Some(Cell(1))],
}, },
}, },
Rule { Rule {
from: RulePattern { from: RulePattern {
width: 2, width: 2,
height: 2, height: 2,
contents: vec![None, Some(Cell::PINK), Some(Cell::EMPTY), Some(Cell::PINK)], contents: vec![None, Some(Cell(1)), Some(Cell(0)), Some(Cell(1))],
}, },
to: RulePattern { to: RulePattern {
width: 2, width: 2,
height: 2, height: 2,
contents: vec![None, Some(Cell::EMPTY), Some(Cell::PINK), Some(Cell::PINK)], contents: vec![None, Some(Cell(0)), Some(Cell(1)), Some(Cell(1))],
}, },
}, },
], ],
@ -158,12 +156,6 @@ impl Dish {
} }
} }
impl Cell {
pub const EMPTY: Self = Self(0, 0, 0);
pub const WHITE: Self = Self(255, 255, 255);
pub const PINK: Self = Self(255, 147, 219);
}
#[derive(Debug)] #[derive(Debug)]
pub struct RulePattern { pub struct RulePattern {
width: usize, width: usize,
@ -180,6 +172,14 @@ impl RulePattern {
} }
} }
pub fn get_mut(&mut self, x: usize, y: usize) -> Option<&mut Cell> {
if x >= self.width || y >= self.height {
None
} else {
self.contents[x + self.width * y].as_mut()
}
}
pub fn height(&self) -> usize { pub fn height(&self) -> usize {
self.height self.height
} }
@ -188,3 +188,10 @@ impl RulePattern {
self.width self.width
} }
} }
impl Cell {
pub const EMPTY: Self = Cell(0);
pub fn id(&self) -> usize {
self.0 as usize
}
}

View file

@ -1,5 +1,5 @@
use eframe::{ use eframe::{
egui::{CentralPanel, Color32, Painter, Rect, SidePanel, Ui, Vec2}, egui::{CentralPanel, Color32, Painter, Rect, Sense, SidePanel, Ui, Vec2},
NativeOptions, NativeOptions,
}; };
use petri::{Chunk, Dish, Rule, CHUNK_SIZE}; use petri::{Chunk, Dish, Rule, CHUNK_SIZE};
@ -16,11 +16,24 @@ fn main() {
#[derive(Debug)] #[derive(Debug)]
struct UScope { struct UScope {
dish: Dish, dish: Dish,
celltypes: Vec<CellData>,
}
#[derive(Default, Debug)]
pub struct CellData {
name: String,
color: Color32,
} }
impl UScope { impl UScope {
fn new(_cc: &eframe::CreationContext<'_>) -> Self { fn new(_cc: &eframe::CreationContext<'_>) -> Self {
Self { dish: Dish::new() } Self {
dish: Dish::new(),
celltypes: vec![
CellData::new("air", 0, 0, 0),
CellData::new("pink_sand", 255, 147, 219),
],
}
} }
} }
@ -37,18 +50,18 @@ impl eframe::App for UScope {
dbg!(&self.dish.rules); dbg!(&self.dish.rules);
} }
for rule in &mut self.dish.rules { for rule in &mut self.dish.rules {
rule_editor(ui, rule); rule_editor(ui, rule, &self.celltypes);
} }
}); });
CentralPanel::default().show(ctx, |ui| { CentralPanel::default().show(ctx, |ui| {
let bounds = ui.available_rect_before_wrap(); let bounds = ui.available_rect_before_wrap();
let painter = ui.painter_at(bounds); let painter = ui.painter_at(bounds);
paint_chunk(painter, &self.dish.chunk); paint_chunk(painter, &self.dish.chunk, &self.celltypes);
}); });
} }
} }
fn paint_chunk(painter: Painter, chunk: &Chunk) { fn paint_chunk(painter: Painter, chunk: &Chunk, cells: &[CellData]) {
let bounds = painter.clip_rect(); let bounds = painter.clip_rect();
let size = 16.; let size = 16.;
for x in 0..CHUNK_SIZE { for x in 0..CHUNK_SIZE {
@ -56,17 +69,18 @@ fn paint_chunk(painter: Painter, chunk: &Chunk) {
let cell = &chunk.get_cell(x, y); let cell = &chunk.get_cell(x, y);
let corner = bounds.min + (Vec2::from((x as f32, y as f32)) * size); let corner = bounds.min + (Vec2::from((x as f32, y as f32)) * size);
let rect = Rect::from_min_size(corner, Vec2::splat(size)); let rect = Rect::from_min_size(corner, Vec2::splat(size));
let color = Color32::from_rgb(cell.0, cell.1, cell.2); let color = cells[cell.id()].color;
painter.rect(rect, 0., color, (1., Color32::GRAY)); painter.rect(rect, 0., color, (1., Color32::GRAY));
} }
} }
} }
fn rule_editor(ui: &mut Ui, rule: &mut Rule) { fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData]) {
let patt_height = rule.from.height(); let patt_height = rule.from.height();
let patt_width = rule.from.height(); let patt_width = rule.from.height();
const CSIZE: f32 = 24.; const CSIZE: f32 = 24.;
const OUTLINE: (f32, Color32) = (1., Color32::GRAY);
let (_, bounds) = ui.allocate_space(Vec2::new( let (_, bounds) = ui.allocate_space(Vec2::new(
CSIZE * (patt_width * 2 + 1) as f32, CSIZE * (patt_width * 2 + 1) as f32,
@ -78,25 +92,33 @@ fn rule_editor(ui: &mut Ui, rule: &mut Rule) {
bounds.min + Vec2::from((x as f32, y as f32)) * CSIZE, bounds.min + Vec2::from((x as f32, y as f32)) * CSIZE,
Vec2::splat(CSIZE), Vec2::splat(CSIZE),
); );
if let Some(cell) = rule.from.get(x, y) { if let Some(cell) = rule.from.get_mut(x, y) {
ui.painter().rect( let color = cells[cell.id()].color;
rect, ui.painter().rect(rect, 2., color, OUTLINE);
2., let a = ui.allocate_rect(rect, Sense::click());
Color32::from_rgb(cell.0, cell.1, cell.2), if a.clicked() {
(1., Color32::GRAY), cell.0 = (cell.0 + 1) % cells.len() as u16;
); }
} }
if let Some(cell) = rule.to.get(x, y) { if let Some(cell) = rule.to.get_mut(x, y) {
let rect = rect.translate(Vec2::X * (patt_width as f32 + 1.) * CSIZE); let rect = rect.translate(Vec2::X * (patt_width as f32 + 1.) * CSIZE);
let color = cells[cell.id()].color;
ui.painter().rect(rect, 2., color, OUTLINE);
let a = ui.allocate_rect(rect, Sense::click());
if a.clicked() {
cell.0 = (cell.0 + 1) % cells.len() as u16;
}
}
}
}
}
ui.painter().rect( impl CellData {
rect, fn new(name: &str, r: u8, g: u8, b: u8) -> Self {
2., Self {
Color32::from_rgb(cell.0, cell.1, cell.2), name: name.to_owned(),
(1., Color32::GRAY), color: Color32::from_rgb(r, g, b),
);
}
} }
} }
} }