Compare commits
2 commits
bff268515d
...
365035a64d
Author | SHA1 | Date | |
---|---|---|---|
365035a64d | |||
aa4cec6dbf |
2 changed files with 69 additions and 40 deletions
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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(
|
ui.painter().rect(rect, 2., color, OUTLINE);
|
||||||
rect,
|
let a = ui.allocate_rect(rect, Sense::click());
|
||||||
2.,
|
if a.clicked() {
|
||||||
Color32::from_rgb(cell.0, cell.1, cell.2),
|
cell.0 = (cell.0 + 1) % cells.len() as u16;
|
||||||
(1., Color32::GRAY),
|
}
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CellData {
|
||||||
|
fn new(name: &str, r: u8, g: u8, b: u8) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_owned(),
|
||||||
|
color: Color32::from_rgb(r, g, b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue