main: render light map

This commit is contained in:
Matthias Schiffer 2023-03-04 20:36:25 +01:00
parent 116e7e5fb6
commit fbf212b55f
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C

View file

@ -6,7 +6,12 @@ use std::{
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use clap::Parser; use clap::Parser;
use minedmap::{io::storage, resource, types::*, world}; use minedmap::{
io::storage,
resource,
types::*,
world::{self, layer::BlockLightArray},
};
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
struct Args { struct Args {
@ -22,6 +27,7 @@ type ProcessedRegion = ChunkArray<Option<Box<world::layer::BlockInfoArray>>>;
struct Config { struct Config {
region_dir: PathBuf, region_dir: PathBuf,
processed_dir: PathBuf, processed_dir: PathBuf,
light_dir: PathBuf,
map_dir: PathBuf, map_dir: PathBuf,
} }
@ -29,11 +35,13 @@ impl Config {
fn new(args: Args) -> Self { fn new(args: Args) -> Self {
let region_dir = [&args.input_dir, Path::new("region")].iter().collect(); let region_dir = [&args.input_dir, Path::new("region")].iter().collect();
let processed_dir = [&args.output_dir, Path::new("processed")].iter().collect(); let processed_dir = [&args.output_dir, Path::new("processed")].iter().collect();
let light_dir = [&args.output_dir, Path::new("light/0")].iter().collect();
let map_dir = [&args.output_dir, Path::new("map/0")].iter().collect(); let map_dir = [&args.output_dir, Path::new("map/0")].iter().collect();
Config { Config {
region_dir, region_dir,
processed_dir, processed_dir,
light_dir,
map_dir, map_dir,
} }
} }
@ -48,6 +56,16 @@ impl Config {
[&self.processed_dir, Path::new(&filename)].iter().collect() [&self.processed_dir, Path::new(&filename)].iter().collect()
} }
fn light_path(&self, coords: RegionCoords, temp: bool) -> PathBuf {
let filename = format!(
"r.{}.{}.png{}",
coords.0,
coords.1,
if temp { ".tmp" } else { "" },
);
[&self.light_dir, Path::new(&filename)].iter().collect()
}
fn map_path(&self, coords: RegionCoords, temp: bool) -> PathBuf { fn map_path(&self, coords: RegionCoords, temp: bool) -> PathBuf {
let filename = format!( let filename = format!(
"r.{}.{}.png{}", "r.{}.{}.png{}",
@ -101,11 +119,29 @@ impl<'a> RegionProcessor<'a> {
fn process_chunk( fn process_chunk(
&self, &self,
data: world::de::Chunk, data: world::de::Chunk,
) -> Result<Option<Box<world::layer::BlockInfoArray>>> { ) -> Result<
Option<(
Box<world::layer::BlockInfoArray>,
Box<world::layer::BlockLightArray>,
)>,
> {
let chunk = world::chunk::Chunk::new(&data, &self.block_types)?; let chunk = world::chunk::Chunk::new(&data, &self.block_types)?;
world::layer::top_layer(&chunk) world::layer::top_layer(&chunk)
} }
fn chunk_lightmap(block_light: Box<BlockLightArray>) -> image::GrayAlphaImage {
const N: u32 = BLOCKS_PER_CHUNK as u32;
image::GrayAlphaImage::from_fn(N, N, |x, z| {
let v: f32 = block_light[LayerBlockCoords {
x: BlockX(x as u8),
z: BlockZ(z as u8),
}]
.into();
image::LumaA([0, (192.0 * (1.0 - v / 15.0)) as u8])
})
}
fn save_region(&self, coords: RegionCoords, processed_region: &ProcessedRegion) -> Result<()> { fn save_region(&self, coords: RegionCoords, processed_region: &ProcessedRegion) -> Result<()> {
let tmp_path = self.config.processed_path(coords, true); let tmp_path = self.config.processed_path(coords, true);
storage::write(&tmp_path, processed_region)?; storage::write(&tmp_path, processed_region)?;
@ -122,26 +158,52 @@ impl<'a> RegionProcessor<'a> {
Ok(()) Ok(())
} }
fn save_lightmap(&self, coords: RegionCoords, lightmap: &image::GrayAlphaImage) -> Result<()> {
let tmp_path = self.config.light_path(coords, true);
lightmap
.save_with_format(&tmp_path, image::ImageFormat::Png)
.context("Failed to save image")?;
let output_path = self.config.light_path(coords, false);
fs::rename(&tmp_path, &output_path).with_context(|| {
format!(
"Failed to rename {} to {}",
tmp_path.display(),
output_path.display(),
)
})?;
Ok(())
}
/// Processes a single region file /// Processes a single region file
fn process_region(&self, path: &Path, coords: RegionCoords) -> Result<()> { fn process_region(&self, path: &Path, coords: RegionCoords) -> Result<()> {
const N: u32 = (BLOCKS_PER_CHUNK * CHUNKS_PER_REGION) as u32;
println!("Processing region r.{}.{}.mca", coords.0, coords.1); println!("Processing region r.{}.{}.mca", coords.0, coords.1);
let mut processed_region = ProcessedRegion::default(); let mut processed_region = ProcessedRegion::default();
let mut lightmap = image::GrayAlphaImage::new(N, N);
minedmap::io::region::from_file(path)?.foreach_chunk( minedmap::io::region::from_file(path)?.foreach_chunk(
|chunk_coords, data: world::de::Chunk| { |chunk_coords, data: world::de::Chunk| {
let Some(processed_chunk) = self let Some((processed_chunk, block_light)) = self
.process_chunk(data) .process_chunk(data)
.with_context(|| format!("Failed to process chunk {:?}", chunk_coords))? .with_context(|| format!("Failed to process chunk {:?}", chunk_coords))?
else { else {
return Ok(()); return Ok(());
}; };
processed_region[chunk_coords] = Some(processed_chunk); processed_region[chunk_coords] = Some(processed_chunk);
let chunk_lightmap = Self::chunk_lightmap(block_light);
overlay_chunk(&mut lightmap, &chunk_lightmap, chunk_coords);
Ok(()) Ok(())
}, },
)?; )?;
self.save_region(coords, &processed_region)?; self.save_region(coords, &processed_region)?;
self.save_lightmap(coords, &lightmap)?;
Ok(()) Ok(())
} }
@ -163,6 +225,12 @@ impl<'a> RegionProcessor<'a> {
self.config.processed_dir.display(), self.config.processed_dir.display(),
) )
})?; })?;
fs::create_dir_all(&self.config.light_dir).with_context(|| {
format!(
"Failed to create directory {}",
self.config.light_dir.display(),
)
})?;
let mut ret = Vec::new(); let mut ret = Vec::new();