mirror of
https://github.com/neocturne/MinedMap.git
synced 2025-03-04 17:23:33 +01:00
minedmap: add mipmapping
This commit is contained in:
parent
86382772c3
commit
216aa6ceec
2 changed files with 128 additions and 0 deletions
|
@ -1,5 +1,6 @@
|
|||
mod common;
|
||||
mod region_processor;
|
||||
mod tile_mipmapper;
|
||||
mod tile_renderer;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
@ -9,6 +10,7 @@ use clap::Parser;
|
|||
|
||||
use common::Config;
|
||||
use region_processor::RegionProcessor;
|
||||
use tile_mipmapper::TileMipmapper;
|
||||
use tile_renderer::TileRenderer;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
|
@ -25,6 +27,7 @@ fn main() -> Result<()> {
|
|||
|
||||
let regions = RegionProcessor::new(&config).run()?;
|
||||
TileRenderer::new(&config).run(regions.iter().copied())?;
|
||||
TileMipmapper::new(&config).run(regions)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
125
src/bin/minedmap/tile_mipmapper.rs
Normal file
125
src/bin/minedmap/tile_mipmapper.rs
Normal file
|
@ -0,0 +1,125 @@
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use minedmap::{io::fs, types::*};
|
||||
|
||||
use super::common::*;
|
||||
|
||||
pub struct TileMipmapper<'a> {
|
||||
config: &'a Config,
|
||||
}
|
||||
|
||||
impl<'a> TileMipmapper<'a> {
|
||||
pub fn new(config: &'a Config) -> Self {
|
||||
TileMipmapper { config }
|
||||
}
|
||||
|
||||
fn done(tiles: &BTreeSet<TileCoords>) -> bool {
|
||||
tiles
|
||||
.into_iter()
|
||||
.all(|TileCoords { x, z }| (-1..=0).contains(x) && (-1..=0).contains(z))
|
||||
}
|
||||
|
||||
fn map_coords(tiles: &BTreeSet<TileCoords>) -> BTreeSet<TileCoords> {
|
||||
let mut ret = BTreeSet::new();
|
||||
|
||||
for coords in tiles {
|
||||
ret.insert(TileCoords {
|
||||
x: coords.x >> 1,
|
||||
z: coords.z >> 1,
|
||||
});
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
fn render_mipmap<P: image::PixelWithColorType>(
|
||||
&self,
|
||||
kind: TileKind,
|
||||
level: usize,
|
||||
coords: TileCoords,
|
||||
prev: &BTreeSet<TileCoords>,
|
||||
) -> Result<()>
|
||||
where
|
||||
[P::Subpixel]: image::EncodableLayout,
|
||||
image::ImageBuffer<P, Vec<P::Subpixel>>: Into<image::DynamicImage>,
|
||||
{
|
||||
const N: u32 = (BLOCKS_PER_CHUNK * CHUNKS_PER_REGION) as u32;
|
||||
|
||||
let output_path = self.config.tile_path(kind, level, coords);
|
||||
|
||||
println!(
|
||||
"Rendering mipmap tile {}",
|
||||
output_path
|
||||
.strip_prefix(&self.config.output_dir)
|
||||
.expect("tile path must be in output directory")
|
||||
.display(),
|
||||
);
|
||||
|
||||
let mut image: image::DynamicImage =
|
||||
image::ImageBuffer::<P, Vec<P::Subpixel>>::new(N, N).into();
|
||||
|
||||
for (dx, dz) in [(0, 0), (0, 1), (1, 0), (1, 1)] {
|
||||
let source_coords = TileCoords {
|
||||
x: 2 * coords.x + dx,
|
||||
z: 2 * coords.z + dz,
|
||||
};
|
||||
if !prev.contains(&source_coords) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let source_path = self.config.tile_path(kind, level - 1, source_coords);
|
||||
let source = match image::open(&source_path) {
|
||||
Ok(source) => source,
|
||||
Err(err) => {
|
||||
eprintln!(
|
||||
"Failed to read source image {}: {}",
|
||||
source_path.display(),
|
||||
err,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let resized = source.resize(N / 2, N / 2, image::imageops::FilterType::Triangle);
|
||||
image::imageops::overlay(
|
||||
&mut image,
|
||||
&resized,
|
||||
dx as i64 * (N / 2) as i64,
|
||||
dz as i64 * (N / 2) as i64,
|
||||
);
|
||||
}
|
||||
|
||||
fs::create_with_tmpfile(&output_path, |file| {
|
||||
image
|
||||
.write_to(file, image::ImageFormat::Png)
|
||||
.context("Failed to save image")
|
||||
})
|
||||
}
|
||||
|
||||
pub fn run(self, tiles: BTreeSet<TileCoords>) -> Result<Vec<BTreeSet<TileCoords>>> {
|
||||
let mut tile_stack = vec![tiles];
|
||||
|
||||
loop {
|
||||
let level = tile_stack.len();
|
||||
let prev = &tile_stack[level - 1];
|
||||
if Self::done(prev) {
|
||||
break;
|
||||
}
|
||||
|
||||
fs::create_dir_all(&self.config.tile_dir(TileKind::Map, level))?;
|
||||
fs::create_dir_all(&self.config.tile_dir(TileKind::Lightmap, level))?;
|
||||
|
||||
let next = Self::map_coords(prev);
|
||||
|
||||
for &coords in &next {
|
||||
self.render_mipmap::<image::Rgba<u8>>(TileKind::Map, level, coords, prev)?;
|
||||
self.render_mipmap::<image::LumaA<u8>>(TileKind::Lightmap, level, coords, prev)?;
|
||||
}
|
||||
|
||||
tile_stack.push(next);
|
||||
}
|
||||
|
||||
Ok(tile_stack)
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue