--- a/rust/land2d/src/lib.rs Thu Nov 08 00:00:58 2018 +0100
+++ b/rust/land2d/src/lib.rs Thu Nov 08 07:15:22 2018 +0300
@@ -84,7 +84,7 @@
}
#[inline]
- pub fn rows(&self) -> impl Iterator<Item = &[T]> {
+ pub fn rows(&self) -> impl DoubleEndedIterator<Item = &[T]> {
self.pixels.rows()
}
--- a/rust/mapgen/src/lib.rs Thu Nov 08 00:00:58 2018 +0100
+++ b/rust/mapgen/src/lib.rs Thu Nov 08 07:15:22 2018 +0300
@@ -108,6 +108,7 @@
pub fn make_texture(&self, land: &Land2D<u8>, theme: &Theme) -> Vec2D<u32> {
let mut texture = Vec2D::new(land.size(), 0);
+
if let Some(land_sprite) = theme.land_texture() {
for (row_index, (land_row, tex_row)) in land.rows()
.zip(texture.rows_mut())
@@ -136,10 +137,106 @@
}
}
}
+
+ if let Some(border_sprite) = theme.border_texture() {
+ assert!(border_sprite.height() <= 512);
+ let border_width = (border_sprite.height() / 2) as u8;
+
+ let mut offsets = vec![255u8; land.width()];
+
+ land_border_pass(
+ land.rows().rev().zip(texture.rows_mut().rev()),
+ &mut offsets,
+ border_width,
+ |x, y| border_sprite.get_pixel(
+ x % border_sprite.width(),
+ border_sprite.height() - 1 - y,
+ )
+ );
+
+ offsets.iter_mut().for_each(|v| *v = 255);
+
+ land_border_pass(
+ land.rows().zip(texture.rows_mut()),
+ &mut offsets,
+ border_width,
+ |x, y| border_sprite.get_pixel(
+ x % border_sprite.width(),
+ y,
+ )
+ );
+ }
+
texture
}
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+struct Color(u32);
+
+impl Color {
+ #[inline]
+ fn red(self) -> u8 {
+ (self.0 >> 0 & 0xFF) as u8
+ }
+
+ #[inline]
+ fn green(self) -> u8 {
+ (self.0 >> 8 & 0xFF) as u8
+ }
+
+ #[inline]
+ fn blue(self) -> u8 {
+ (self.0 >> 16 & 0xFF) as u8
+ }
+
+ #[inline]
+ fn alpha(self) -> u8 {
+ (self.0 >> 24 & 0xFF) as u8
+ }
+}
+
+#[inline]
+fn lerp(from: u8, to: u8, coef: u8) -> u8 {
+ ((from as u16 * (256 - coef as u16) + to as u16 * coef as u16) / 256) as u8
+}
+
+#[inline]
+fn blend(source: u32, target: u32) -> u32 {
+ let source = Color(source);
+ let target = Color(target);
+ let alpha = lerp(target.alpha(), 255, source.alpha());
+ let red = lerp(target.red(), source.red(), source.alpha());
+ let green = lerp(target.green(), source.green(), source.alpha());
+ let blue = lerp(target.blue(), source.blue(), source.alpha());
+ (red as u32) << 0 | (green as u32) << 8 | (blue as u32) << 16 | (alpha as u32) << 24
+}
+
+fn land_border_pass<'a, T, F>(rows: T, offsets: &mut [u8], border_width: u8, pixel_getter: F)
+ where T: Iterator<Item = (&'a [u8], &'a mut [u32])>,
+ F: (Fn(usize, usize) -> u32)
+{
+ for (land_row, tex_row) in rows {
+ for (x, ((land_v, tex_v), offset_v)) in land_row.iter()
+ .zip(tex_row.iter_mut())
+ .zip(offsets.iter_mut())
+ .enumerate()
+ {
+ *offset_v = if *land_v == 0 {
+ if *offset_v < border_width {
+ *tex_v = blend(
+ pixel_getter(x, *offset_v as usize),
+ *tex_v,
+ )
+ }
+ offset_v.saturating_add(1)
+ } else {
+ 0
+ }
+ }
+ }
+}
+
fn tex_row_copy(land_row: &[u8], tex_row: &mut [u32], sprite_row: &[u32]) {
for ((land_v, tex_v), sprite_v) in
land_row.iter().zip(tex_row.iter_mut()).zip(sprite_row)
--- a/rust/mapgen/src/theme.rs Thu Nov 08 00:00:58 2018 +0100
+++ b/rust/mapgen/src/theme.rs Thu Nov 08 07:15:22 2018 +0300
@@ -38,7 +38,7 @@
}
#[inline]
- pub fn rows(&self) -> impl Iterator<Item = &[u32]> {
+ pub fn rows(&self) -> impl DoubleEndedIterator<Item = &[u32]> {
self.pixels.rows()
}
@@ -46,16 +46,26 @@
pub fn get_row(&self, index: usize) -> &[u32] {
&self.pixels[index]
}
+
+ #[inline]
+ pub fn get_pixel(&self, x: usize, y: usize) -> u32 {
+ self.pixels[y][x]
+ }
}
pub struct Theme {
- land_texture: Option<ThemeSprite>
+ land_texture: Option<ThemeSprite>,
+ border_texture: Option<ThemeSprite>
}
impl Theme {
pub fn land_texture(&self) -> Option<&ThemeSprite> {
self.land_texture.as_ref()
}
+
+ pub fn border_texture(&self) -> Option<&ThemeSprite> {
+ self.border_texture.as_ref()
+ }
}
#[derive(Debug)]
@@ -80,7 +90,8 @@
impl Theme {
pub fn new() -> Self {
Theme {
- land_texture: None
+ land_texture: None,
+ border_texture: None,
}
}
@@ -90,23 +101,9 @@
for entry in read_dir(path)? {
let file = entry?;
if file.file_name() == "LandTex.png" {
- let decoder = Decoder::new(
- BufReader::new(File::open(file.path())?));
- let (info, mut reader) = decoder.read_info()?;
-
- if info.color_type != ColorType::RGBA {
- return Err(ThemeLoadError::Format(
- format!("Unexpected format: {:?}", info.color_type)));
- }
- let size = Size::new(info.width as usize, info.height as usize);
-
- let mut buffer: Vec2D<u32> = Vec2D::new(size, 0);
- reader.next_frame(slice_u32_to_u8_mut(buffer.as_mut_slice()))?;
-
- let land_tex = ThemeSprite {
- pixels: buffer
- };
- theme.land_texture = Some(land_tex)
+ theme.land_texture = Some(load_sprite(&file.path())?)
+ } else if file.file_name() == "Border.png" {
+ theme.border_texture = Some(load_sprite(&file.path())?)
}
}
@@ -114,6 +111,23 @@
}
}
+fn load_sprite(path: &Path) -> Result<ThemeSprite, ThemeLoadError> {
+ let decoder = Decoder::new(
+ BufReader::new(File::open(path)?));
+ let (info, mut reader) = decoder.read_info()?;
+
+ if info.color_type != ColorType::RGBA {
+ return Err(ThemeLoadError::Format(
+ format!("Unexpected format: {:?}", info.color_type)));
+ }
+ let size = Size::new(info.width as usize, info.height as usize);
+
+ let mut pixels: Vec2D<u32> = Vec2D::new(size, 0);
+ reader.next_frame(slice_u32_to_u8_mut(pixels.as_mut_slice()))?;
+
+ Ok(ThemeSprite { pixels })
+}
+
pub fn slice_u32_to_u8(slice_u32: &[u32]) -> &[u8] {
unsafe {
from_raw_parts::<u8>(
--- a/rust/vec2d/src/lib.rs Thu Nov 08 00:00:58 2018 +0100
+++ b/rust/vec2d/src/lib.rs Thu Nov 08 07:15:22 2018 +0300
@@ -86,12 +86,12 @@
}
#[inline]
- pub fn rows(&self) -> impl Iterator<Item = &[T]> {
+ pub fn rows(&self) -> impl DoubleEndedIterator<Item = &[T]> {
self.data.chunks(self.width())
}
#[inline]
- pub fn rows_mut(&mut self) -> impl Iterator<Item = &mut [T]> {
+ pub fn rows_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut [T]> {
let width = self.width();
self.data.chunks_mut(width)
}