Add colors

This commit is contained in:
mindv0rtex 2021-03-02 16:18:04 -05:00
parent 9dbe6144f0
commit 0c2158a408
4 changed files with 136 additions and 15 deletions

View File

@ -13,7 +13,7 @@ impl Blur {
}
}
/// Blur an image with 3 box filter passes. The result will be written to the src slice, while
/// Blur an image with 2 box filter passes. The result will be written to the src slice, while
/// the buf slice is used as a scratch space.
pub fn run(
&mut self,

View File

@ -1,5 +1,6 @@
mod blur;
mod grid;
pub mod model;
pub mod trig;
mod palette;
pub mod trig; // for benchmarking
mod util;

View File

@ -1,9 +1,13 @@
use crate::grid::{combine, Grid, PopulationConfig};
use crate::{
grid::{combine, Grid, PopulationConfig},
palette::{random_palette, Palette},
};
use rand::{seq::SliceRandom, Rng};
use rand_distr::{Distribution, Normal};
use rayon::prelude::*;
use itertools::multizip;
use std::f32::consts::TAU;
/// A single Physarum agent. The x and y positions are continuous, hence we use floating point
@ -46,7 +50,6 @@ impl Agent {
}
/// Top-level simulation class.
#[derive(Debug)]
pub struct Model {
// Physarum agents.
agents: Vec<Agent>,
@ -62,6 +65,8 @@ pub struct Model {
// Current model iteration.
iteration: i32,
palette: Palette,
}
impl Model {
@ -117,6 +122,7 @@ impl Model {
attraction_table,
diffusivity,
iteration: 0,
palette: random_palette(),
}
}
@ -138,8 +144,7 @@ impl Model {
pub fn step(&mut self) {
// Combine grids
let grids = &mut self.grids;
let attraction_table = &self.attraction_table;
combine(grids, attraction_table);
combine(grids, &self.attraction_table);
self.agents.par_iter_mut().for_each(|agent| {
let grid = &grids[agent.population_id];
@ -159,7 +164,8 @@ impl Model {
let xr = agent.x + (agent.angle + sensor_angle).cos() * sensor_distance;
let yr = agent.y + (agent.angle + sensor_angle).sin() * sensor_distance;
// Sense
// Sense. We sense from the buffer because this is where we previously combined data
// from all the grid.
let trail_c = grid.get_buf(xc, yc);
let trail_l = grid.get_buf(xl, yl);
let trail_r = grid.get_buf(xr, yr);
@ -185,16 +191,35 @@ impl Model {
/// Output the current trail layer as a grayscale image.
pub fn save_to_image(&self, name: &str) {
let mut img =
image::GrayImage::new(self.grids[0].width as u32, self.grids[0].height as u32);
let max_value = self.grids[0].quantile(0.999);
let (width, height) = (self.grids[0].width, self.grids[0].height);
let mut img = image::RgbImage::new(width as u32, height as u32);
for (i, value) in self.grids[0].data().iter().enumerate() {
let x = (i % self.grids[0].width) as u32;
let y = (i / self.grids[0].width) as u32;
let c = (value / max_value).clamp(0.0, 1.0) * 255.0;
img.put_pixel(x, y, image::Luma([c as u8]));
let max_values: Vec<_> = self
.grids
.iter()
.map(|grid| grid.quantile(0.999) * 1.5)
.collect();
for y in 0..height {
for x in 0..width {
let i = y * width + x;
let (mut r, mut g, mut b) = (0.0_f32, 0.0_f32, 0.0_f32);
for (grid, max_value, color) in
multizip((&self.grids, &max_values, &self.palette.colors))
{
let mut t = (grid.data()[i] / max_value).clamp(0.0, 1.0);
t = t.powf(1.0 / 2.2); // gamma correction
r += color.0[0] as f32 * t;
g += color.0[1] as f32 * t;
b += color.0[2] as f32 * t;
}
r = r.clamp(0.0, 255.0);
g = g.clamp(0.0, 255.0);
b = b.clamp(0.0, 255.0);
img.put_pixel(x as u32, y as u32, image::Rgb([r as u8, g as u8, b as u8]));
}
}
img.save(name).unwrap();
}
}

95
src/palette.rs Normal file
View File

@ -0,0 +1,95 @@
use rand::{seq::SliceRandom, thread_rng, Rng};
#[derive(Clone, Copy)]
pub struct Palette {
pub colors: [image::Rgb<u8>; 5],
}
pub fn random_palette() -> Palette {
let mut rng = thread_rng();
let mut palette = PALETTES[rng.gen_range(0..PALETTES.len())];
palette.colors.shuffle(&mut rng);
palette
}
const fn hex_to_color(c: usize) -> image::Rgb<u8> {
let r = (c >> 16) & 0xff;
let g = (c >> 8) & 0xff;
let b = (c >> 0) & 0xff;
image::Rgb::<u8>([r as u8, g as u8, b as u8])
}
const PALETTES: [Palette; 8] = [
Palette {
colors: [
hex_to_color(0xFA2B31),
hex_to_color(0xFFBF1F),
hex_to_color(0xFFF146),
hex_to_color(0xABE319),
hex_to_color(0x00C481),
],
},
Palette {
colors: [
hex_to_color(0x004358),
hex_to_color(0x1F8A70),
hex_to_color(0xBEDB39),
hex_to_color(0xFFE11A),
hex_to_color(0xFD7400),
],
},
Palette {
colors: [
hex_to_color(0x334D5C),
hex_to_color(0x45B29D),
hex_to_color(0xEFC94C),
hex_to_color(0xE27A3F),
hex_to_color(0xDF5A49),
],
},
Palette {
colors: [
hex_to_color(0xFF8000),
hex_to_color(0xFFD933),
hex_to_color(0xCCCC52),
hex_to_color(0x8FB359),
hex_to_color(0x192B33),
],
},
Palette {
colors: [
hex_to_color(0x730046),
hex_to_color(0xBFBB11),
hex_to_color(0xFFC200),
hex_to_color(0xE88801),
hex_to_color(0xC93C00),
],
},
Palette {
colors: [
hex_to_color(0xE6DD00),
hex_to_color(0x8CB302),
hex_to_color(0x008C74),
hex_to_color(0x004C66),
hex_to_color(0x332B40),
],
},
Palette {
colors: [
hex_to_color(0xF15A5A),
hex_to_color(0xF0C419),
hex_to_color(0x4EBA6F),
hex_to_color(0x2D95BF),
hex_to_color(0x955BA5),
],
},
Palette {
colors: [
hex_to_color(0xF41C54),
hex_to_color(0xFF9F00),
hex_to_color(0xFBD506),
hex_to_color(0xA8BF12),
hex_to_color(0x00AAB5),
],
},
];