pub(crate) const GRAIN_SIGMA: f32 = 2.0;
pub(crate) const CELLS: u32 = 32;
const GRID: usize = CELLS as usize + 2;
const CELL_AMPLITUDE: f32 = 150.0;
const RIDGE_GAIN: f32 = 90.0;
const RIDGE_CEILING: f32 = 30.0;
const MID_LEVEL: f32 = 128.0;
const RIDGE_BIAS: f32 = 15.0;
const LEVEL_FLOOR: f32 = 24.0;
const LEVEL_CEILING: f32 = 231.0;
#[derive(Clone, Copy)]
struct Cell {
x: f32,
y: f32,
level: f32,
}
pub(crate) struct Texture {
cells: Vec<Cell>,
cell_size_x: f32,
cell_size_y: f32,
}
impl Texture {
pub(crate) fn new(seed: u64, width: u32, height: u32) -> Self {
let mixed = seed.wrapping_mul(0x9E37_79B9_7F4A_7C15) | 1;
let mut cells = Vec::with_capacity(GRID * GRID);
for row in 0..GRID {
for column in 0..GRID {
let gx = column as i32 - 1;
let gy = row as i32 - 1;
cells.push(Cell {
x: gx as f32 + unit(mixed, gx, gy, 11),
y: gy as f32 + unit(mixed, gx, gy, 13),
level: (unit(mixed, gx, gy, 17) - 0.5) * CELL_AMPLITUDE,
});
}
}
Self {
cells,
cell_size_x: Self::cell_size(width),
cell_size_y: Self::cell_size(height),
}
}
fn cell_size(side: u32) -> f32 {
side as f32 / CELLS as f32
}
pub(crate) fn base_levels(&self, x: u32, y: u32) -> [f32; 3] {
let fx = x as f32 / self.cell_size_x;
let fy = y as f32 / self.cell_size_y;
let cx = fx.floor() as i32;
let cy = fy.floor() as i32;
let (mut first, mut second) = (f32::MAX, f32::MAX);
let mut nearest_level = 0.0f32;
for oy in -1..=1 {
for ox in -1..=1 {
let Some(cell) = self.cell(cx + ox, cy + oy) else {
continue;
};
let distance = (fx - cell.x).hypot(fy - cell.y);
if distance < first {
second = first;
first = distance;
nearest_level = cell.level;
} else if distance < second {
second = distance;
}
}
}
let ridge = ((second - first) * RIDGE_GAIN).min(RIDGE_CEILING);
let level =
(MID_LEVEL + nearest_level + ridge - RIDGE_BIAS).clamp(LEVEL_FLOOR, LEVEL_CEILING);
[level, level * 0.98 + 3.0, level * 0.94 + 8.0]
}
fn cell(&self, gx: i32, gy: i32) -> Option<Cell> {
let column = usize::try_from(gx + 1).ok()?;
let row = usize::try_from(gy + 1).ok()?;
if column >= GRID || row >= GRID {
return None;
}
self.cells.get(row * GRID + column).copied()
}
}
fn unit(seed: u64, x: i32, y: i32, channel: i32) -> f32 {
(hash(seed, x, y, channel) >> 40) as f32 / 16_777_216.0
}
fn hash(seed: u64, x: i32, y: i32, channel: i32) -> u64 {
let mut mixed = seed
^ (x as i64 as u64).wrapping_mul(0xA24B_AED4_963E_E407)
^ (y as i64 as u64).wrapping_mul(0x9FB2_1C65_1E98_DF25)
^ (channel as i64 as u64).wrapping_mul(0xD6E8_FEB8_6659_FD93);
mixed ^= mixed >> 32;
mixed = mixed.wrapping_mul(0xD6E8_FEB8_6659_FD93);
mixed ^= mixed >> 29;
mixed
}
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used)]
#![allow(clippy::panic)]
use super::*;
const SIDE: u32 = 2000;
#[test]
fn one_cell_is_one_thumbnail_pixel() {
assert_eq!(Texture::cell_size(SIDE), SIDE as f32 / 32.0);
assert_eq!(Texture::cell_size(2000), 62.5);
assert_eq!(Texture::cell_size(2500), 2500.0 / 32.0);
let rectangle = Texture::new(0x5EED, 2000, 4000);
assert_eq!(rectangle.cell_size_x, 2000.0 / 32.0);
assert_eq!(rectangle.cell_size_y, 4000.0 / 32.0);
}
#[test]
fn no_base_level_approaches_the_ends_of_the_range() {
for (width, height) in [(SIDE, SIDE), (SIDE, 2 * SIDE), (3 * SIDE, SIDE)] {
let texture = Texture::new(0x5EED, width, height);
for y in (0..height).step_by(37) {
for x in (0..width).step_by(37) {
for level in texture.base_levels(x, y) {
assert!(
(LEVEL_FLOOR..=LEVEL_CEILING).contains(&level),
"level {level} at ({x}, {y}) is outside the safe range"
);
assert!(level > 10.0 * GRAIN_SIGMA);
assert!(level < 255.0 - 10.0 * GRAIN_SIGMA);
}
}
}
}
}
#[test]
fn the_field_is_reproducible_from_its_seed() {
let first = Texture::new(7, SIDE, SIDE);
let again = Texture::new(7, SIDE, SIDE);
let other = Texture::new(8, SIDE, SIDE);
let mut differs = false;
for (x, y) in [(0u32, 0u32), (1, 999), (1999, 1999), (500, 1200)] {
assert_eq!(first.base_levels(x, y), again.base_levels(x, y));
differs |= first.base_levels(x, y) != other.base_levels(x, y);
}
assert!(differs, "two seeds must not produce the same field");
}
#[test]
fn the_grid_covers_every_neighbour_of_every_pixel() {
let texture = Texture::new(1, SIDE, SIDE);
assert!(texture.cell(-1, -1).is_some());
assert!(texture.cell(CELLS as i32, CELLS as i32).is_some());
assert!(texture.cell(-2, 0).is_none());
assert!(texture.cell(0, CELLS as i32 + 1).is_none());
}
#[test]
fn the_three_planes_are_not_one_plane_repeated() {
let levels = Texture::new(3, SIDE, SIDE).base_levels(640, 480);
assert!(levels[0] != levels[1] || levels[1] != levels[2]);
}
}