use crate::map::PARALLAX_DIVISOR;
use crate::*;
use fixed::types::I27F5;
use ndarray::{s, Array2};
use vek::num_traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub};
use vek::Extent2;
impl TwMap {
#[must_use]
pub fn extend_layers(
mut self,
up_left: Extent2<u16>,
down_right: Extent2<u16>,
) -> Option<TwMap> {
let tiles_up_left = up_left.checked_as()?;
let tiles_down_right = down_right.numcast()?;
let object_offset = up_left.checked_as()?;
for group in &mut self.groups {
for layer in &mut group.layers {
use Layer::*;
match layer {
Game(l) => extend_layer(l, tiles_up_left, tiles_down_right)?,
Tiles(l) => extend_layer(l, tiles_up_left, tiles_down_right)?,
Quads(l) => l.shift(object_offset.into())?,
Front(l) => extend_layer(l, tiles_up_left, tiles_down_right)?,
Tele(l) => extend_layer(l, tiles_up_left, tiles_down_right)?,
Speedup(l) => extend_layer(l, tiles_up_left, tiles_down_right)?,
Switch(l) => extend_layer(l, tiles_up_left, tiles_down_right)?,
Tune(l) => extend_layer(l, tiles_up_left, tiles_down_right)?,
Sounds(l) => l.shift(object_offset.into())?,
Invalid(_) => {}
}
}
let group_up_left: Extent2<I27F5> = up_left.checked_as()?;
let group_up_left_parallaxed = group_up_left
.checked_mul(&group.parallax.checked_as()?.into())?
.checked_div(&PARALLAX_DIVISOR.checked_as()?.into())?;
group.offset = group
.offset
.checked_add(&group_up_left.into())?
.checked_sub(&group_up_left_parallaxed.into())?;
if !group.is_physics_group() {
let new_group_pos = group.clip.position().checked_add(&group_up_left.into())?;
group.clip.x = new_group_pos.x;
group.clip.y = new_group_pos.y;
}
}
Some(self)
}
}
pub fn edge_extend_ndarray<T: Default + Copy>(
ndarray: &Array2<T>,
up_left: Extent2<usize>,
down_right: Extent2<usize>,
) -> Option<Array2<T>> {
let up = up_left.h;
let down = down_right.h;
let left = up_left.w;
let right = down_right.w;
let old_height = ndarray.nrows();
let new_height = old_height.checked_add(up)?.checked_add(down)?;
let old_width = ndarray.ncols();
let new_width = old_width.checked_add(left)?.checked_add(right)?;
let mut new_ndarray = Array2::default((new_height, new_width));
new_ndarray
.slice_mut(s![up..up + ndarray.nrows(), left..left + ndarray.ncols()])
.assign(ndarray);
let corners = vec![
((0..up, 0..left), ndarray[(0, 0)]), (
(0..up, new_width - right..new_width),
ndarray[(0, old_width - 1)],
), (
(new_height - down..new_height, 0..left),
ndarray[(old_height - 1, 0)],
), (
(new_height - down..new_height, new_width - right..new_width),
ndarray[(old_height - 1, old_width - 1)],
),
];
for ((y_slice, x_slice), corner) in corners {
new_ndarray
.slice_mut(s![y_slice, x_slice])
.map_inplace(|e| *e = corner);
}
let vertical_edge_ranges = vec![
(ndarray.row(0), (0..up, left..left + old_width)), (
ndarray.row(old_height - 1),
(up + old_height..new_height, left..left + old_width),
), ];
let horizontal_edge_ranges = vec![
(ndarray.column(0), (up..up + old_height, 0..left)), (
ndarray.column(old_width - 1),
(up..up + old_height, left + old_width..new_width),
), ];
for (edge, (y_slice, x_slice)) in vertical_edge_ranges {
new_ndarray
.slice_mut(s![y_slice, x_slice])
.rows_mut()
.into_iter()
.for_each(|mut row| row.assign(&edge))
}
for (edge, (y_slice, x_slice)) in horizontal_edge_ranges {
new_ndarray
.slice_mut(s![y_slice, x_slice])
.columns_mut()
.into_iter()
.for_each(|mut row| row.assign(&edge))
}
Some(new_ndarray)
}
fn extend_layer<T: TilemapLayer>(
layer: &mut T,
up_left: Extent2<usize>,
down_right: Extent2<usize>,
) -> Option<()> {
*layer.tiles_mut().unwrap_mut() =
edge_extend_ndarray(layer.tiles().unwrap_ref(), up_left, down_right)?;
Some(())
}