minetest_worldmapper/
terrain.rsuse crate::color::Color;
use crate::mapblock::CHUNK_SIZE;
use minetestworld::MAPBLOCK_LENGTH;
#[derive(Default, Clone, Copy, Debug)]
pub struct TerrainCell {
ground_color: Option<Color>,
pub height: Option<i16>,
}
impl TerrainCell {
pub fn alpha(&self) -> u8 {
self.ground_color.map(|c| c.alpha()).unwrap_or(0)
}
pub fn add_background(&mut self, color: Color) {
let new_color = self
.ground_color
.map(|c| c.with_background(&color))
.unwrap_or(color);
self.ground_color = Some(new_color);
}
pub fn set_height(&mut self, height: i16) {
if self.height.is_none() {
self.height = Some(height)
}
}
}
pub struct Terrain {
width: usize,
height: usize,
flat_data: Vec<TerrainCell>,
}
impl Terrain {
pub fn new(width: usize, height: usize) -> Self {
Terrain {
width,
height,
flat_data: vec![Default::default(); width * height],
}
}
pub fn width(&self) -> usize {
self.width
}
pub fn height(&self) -> usize {
self.height
}
fn get_cell_mut(&mut self, x: u32, y: u32) -> &mut TerrainCell {
self.flat_data
.get_mut(y as usize * self.width + x as usize)
.unwrap_or_else(|| panic!("Trying to get Terrain[{x}, {y}]"))
}
pub fn get_color(&self, x: u32, y: u32) -> Option<Color> {
self.get_cell(x, y)?.ground_color
}
pub fn get_cell(&self, x: u32, y: u32) -> Option<&TerrainCell> {
self.flat_data.get(y as usize * self.width + x as usize)
}
pub fn insert_chunk(&mut self, offset: (u32, u32), chunk: [TerrainCell; CHUNK_SIZE]) {
for (i, cell) in chunk.into_iter().enumerate() {
let (mut x, mut y) = offset;
x += i as u32 % MAPBLOCK_LENGTH as u32;
y += MAPBLOCK_LENGTH as u32 - i as u32 / MAPBLOCK_LENGTH as u32 - 1;
*self.get_cell_mut(x, y) = cell;
}
}
pub fn height_diff_x(&self, x: u32, y: u32) -> Option<i16> {
let a = self
.get_cell(x.saturating_sub(1), y)
.or_else(|| self.get_cell(x, y))?;
let this_cell = self.get_cell(x, y)?.height?;
let b = self.get_cell(x + 1, y).or_else(|| self.get_cell(x, y))?;
let mut ascent = b.height? - this_cell;
ensure_nonnegative(&mut ascent);
let mut descent = a.height? - this_cell;
ensure_nonnegative(&mut descent);
Some(ascent.saturating_sub(descent))
}
pub fn height_diff_y(&self, x: u32, y: u32) -> Option<i16> {
let a = self
.get_cell(x, y.saturating_sub(1))
.or_else(|| self.get_cell(x, y))?;
let this_cell = self.get_cell(x, y)?.height?;
let b = self.get_cell(x, y + 1).or_else(|| self.get_cell(x, y))?;
let mut ascent = b.height? - this_cell;
ensure_nonnegative(&mut ascent);
let mut descent = a.height? - this_cell;
ensure_nonnegative(&mut descent);
Some(ascent.saturating_sub(descent))
}
}
fn ensure_nonnegative(value: &mut i16) {
if *value < 0 {
*value = 0;
}
}