diff options
author | metamuffin <metamuffin@disroot.org> | 2022-10-17 20:40:21 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2022-10-17 20:40:21 +0200 |
commit | 781dc2ade098b0cb4e3e68a03477476dbadbf985 (patch) | |
tree | 709f6f1a464d3997b29f65c0baea3a458aac5dad /src | |
parent | d55dc04fd9f223ada252a6d9e71cabde5f6dd355 (diff) | |
download | trash-map-781dc2ade098b0cb4e3e68a03477476dbadbf985.tar trash-map-781dc2ade098b0cb4e3e68a03477476dbadbf985.tar.bz2 trash-map-781dc2ade098b0cb4e3e68a03477476dbadbf985.tar.zst |
works
Diffstat (limited to 'src')
-rw-r--r-- | src/dimension.rs | 64 | ||||
-rw-r--r-- | src/main.rs | 136 | ||||
-rw-r--r-- | src/render/composite.rs | 31 | ||||
-rw-r--r-- | src/render/mod.rs | 102 | ||||
-rw-r--r-- | src/render/models.rs | 12 |
5 files changed, 200 insertions, 145 deletions
diff --git a/src/dimension.rs b/src/dimension.rs new file mode 100644 index 0000000..39a7fff --- /dev/null +++ b/src/dimension.rs @@ -0,0 +1,64 @@ +use chashmap::{CHashMap, ReadGuard, WriteGuard}; +use fastanvil::{Block, Chunk, CurrentJavaChunk, Region, RegionFileLoader, RegionLoader}; +use log::{info, debug}; +use std::{fs::File, path::Path}; + +pub struct Dimension { + loader: RegionFileLoader, + regions: CHashMap<(isize, isize), Option<Region<File>>>, + chunks: CHashMap<(isize, isize), Option<CurrentJavaChunk>>, +} +impl Dimension { + pub fn new(path: &str) -> Self { + let loader = fastanvil::RegionFileLoader::new(Path::new(path).to_path_buf()); + Self { + loader, + regions: Default::default(), + chunks: Default::default(), + } + } + pub fn region( + &self, + rx: isize, + rz: isize, + ) -> WriteGuard<'_, (isize, isize), Option<Region<File>>> { + if self.regions.contains_key(&(rx, rz)) { + self.regions.get_mut(&(rx, rz)).unwrap() + } else { + info!("loading region {:?}", (rx, rz)); + self.regions.insert( + (rx, rz), + self.loader + .region(fastanvil::RCoord(rx), fastanvil::RCoord(rz)), + ); + self.region(rx, rz) + } + } + pub fn chunk( + &self, + cx: isize, + cz: isize, + ) -> ReadGuard<'_, (isize, isize), Option<CurrentJavaChunk>> { + if self.chunks.contains_key(&(cx, cz)) { + self.chunks.get(&(cx, cz)).unwrap() + } else { + let mut guard = self.region(cx / 32, cz / 32); + let reg = guard.as_mut().unwrap(); + debug!("loading chunk {:?}", (cx, cz)); + let chunk: Option<CurrentJavaChunk> = reg + .read_chunk(cx.rem_euclid(32) as usize, cz.rem_euclid(32) as usize) + .ok() + .flatten() + .map(|chunk| fastnbt::from_bytes(&chunk).ok()) + .flatten(); + self.chunks.insert((cx, cz), chunk); + self.chunk(cx, cz) + } + } + pub fn block(&self, x: isize, y: isize, z: isize) -> Option<Block> { + self.chunk(x / 16, z / 16) + .as_ref()? + .block(x.rem_euclid(16) as usize, y, z.rem_euclid(16) as usize) + .map(|e| e.to_owned()) + } +} diff --git a/src/main.rs b/src/main.rs index 07cb629..d21735e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,9 @@ +pub mod dimension; pub mod render; -use crate::render::{ - composite::image_buffer_blit, models::processed_block_texture, processing::Texture, -}; -use chashmap::{CHashMap, ReadGuard, WriteGuard}; -use fastanvil::{Block, Chunk, CurrentJavaChunk, Region, RegionFileLoader, RegionLoader}; -use image::ImageBuffer; -use log::{debug, info}; -use std::{collections::HashMap, fs::File, path::Path}; - -const SEG_SIZE: isize = 128; +use crate::dimension::Dimension; +use log::info; +use render::Renderer; fn main() { env_logger::builder() @@ -18,122 +12,12 @@ fn main() { .init(); let dim = Dimension::new("/home/muffin/containers/games/home/user/server/world/region/"); - let solid = |x: isize, y: isize, z: isize| { - dim.block(x, y, z) - .map(|b| match b.name() { - "minecraft:air" | "minecraft:cave_air" => (false, false), - "minecraft:water" => (false, true), - _ => (true, true), - }) - .unwrap_or((true, true)) - }; - - let mut textures = HashMap::<String, Texture>::new(); - - let mut view: Texture = - ImageBuffer::new(16 * (SEG_SIZE + 1) as u32, 16 * (SEG_SIZE + 1) as u32); - - let mut visible = Vec::<((isize, isize, isize), (isize, isize, isize))>::new(); - - for ix in 0..SEG_SIZE { - for iy in 0..(SEG_SIZE * 2) { - for off in 0..=1 { - let mut y = 100; - let mut x = -ix + iy + off; - let mut z = ix + iy; - loop { - let (solid, has_texture) = solid(x, y, z); - if has_texture { - visible.push(((x, y, z), (ix, iy, off))); - } - if solid { - break; - } - y -= 1; - x -= 1; - z -= 1; - } - } - } - } - info!("{} visible blocks", visible.len()); - visible.sort_by_cached_key(|((x, y, z), _)| x + y + z); - - info!("compositing textures"); - for ((x, y, z), (ix, iy, off)) in visible { - let name = match dim.block(x, y, z) { - Some(block) => block.name().to_owned(), - None => "minecraft:debug".to_owned(), - }; - let name = &name["minecraft:".len()..]; - let texture = textures - .entry(name.to_owned()) - .or_insert_with(|| processed_block_texture(name)); - - let ix = ix * 16 + off * 8; - let iy = iy * 8 + off * 4; - image_buffer_blit(&mut view, texture, (ix as u32, iy as u32)); - } - info!("saving png"); - view.save(format!("/tmp/a.png")).unwrap(); -} - -struct Dimension { - loader: RegionFileLoader, - regions: CHashMap<(isize, isize), Option<Region<File>>>, - chunks: CHashMap<(isize, isize), Option<CurrentJavaChunk>>, -} -impl Dimension { - pub fn new(path: &str) -> Self { - let loader = fastanvil::RegionFileLoader::new(Path::new(path).to_path_buf()); - Self { - loader, - regions: Default::default(), - chunks: Default::default(), + let renderer = Renderer::new(dim); + for sx in 0..4 { + for sy in 0..4 { + let view = renderer.render_segment(sx, sy); + info!("saving png"); + view.save(format!("/tmp/seg.{sx}.{sy}.png")).unwrap(); } } - pub fn region( - &self, - rx: isize, - rz: isize, - ) -> WriteGuard<'_, (isize, isize), Option<Region<File>>> { - if self.regions.contains_key(&(rx, rz)) { - self.regions.get_mut(&(rx, rz)).unwrap() - } else { - info!("loading region {:?}", (rx, rz)); - self.regions.insert( - (rx, rz), - self.loader - .region(fastanvil::RCoord(rx), fastanvil::RCoord(rz)), - ); - self.region(rx, rz) - } - } - pub fn chunk( - &self, - cx: isize, - cz: isize, - ) -> ReadGuard<'_, (isize, isize), Option<CurrentJavaChunk>> { - if self.chunks.contains_key(&(cx, cz)) { - self.chunks.get(&(cx, cz)).unwrap() - } else { - let mut guard = self.region(cx / 32, cz / 32); - let reg = guard.as_mut().unwrap(); - debug!("loading chunk {:?}", (cx, cz)); - let chunk: Option<CurrentJavaChunk> = reg - .read_chunk(cx.rem_euclid(32) as usize, cz.rem_euclid(32) as usize) - .ok() - .flatten() - .map(|chunk| fastnbt::from_bytes(&chunk).ok()) - .flatten(); - self.chunks.insert((cx, cz), chunk); - self.chunk(cx, cz) - } - } - pub fn block(&self, x: isize, y: isize, z: isize) -> Option<Block> { - self.chunk(x / 16, z / 16) - .as_ref()? - .block(x.rem_euclid(16) as usize, y, z.rem_euclid(16) as usize) - .map(|e| e.to_owned()) - } } diff --git a/src/render/composite.rs b/src/render/composite.rs index 7409478..99950f1 100644 --- a/src/render/composite.rs +++ b/src/render/composite.rs @@ -1,8 +1,5 @@ use image::ImageBuffer; use image::Rgba; - -use crate::SEG_SIZE; - pub const REGION_SIZE: usize = 16 * 8; pub const CHUNK_HEIGHT: usize = 320; pub const CHUNK_SIZE: usize = 16; @@ -28,21 +25,21 @@ pub fn image_buffer_blit( } } -pub fn isometric_coord_mapping(x: i32, y: i32, z: i32) -> (u32, u32) { - // const BASE_X: i32 = 1016; - const BASE_X: i32 = (SEG_SIZE as i32 * 8) - 8; - const BASE_Y: i32 = 2040; +// pub fn isometric_coord_mapping(x: i32, y: i32, z: i32) -> (u32, u32) { +// // const BASE_X: i32 = 1016; +// const BASE_X: i32 = (SEG_SIZE as i32 * 8) - 8; +// const BASE_Y: i32 = 2040; - const XDIFF: (i32, i32) = (-8, 4); - const ZDIFF: (i32, i32) = (8, 4); - const YDIFF: (i32, i32) = (0, -8); +// const XDIFF: (i32, i32) = (-8, 4); +// const ZDIFF: (i32, i32) = (8, 4); +// const YDIFF: (i32, i32) = (0, -8); - let diff = ( - XDIFF.0 * x + YDIFF.0 * y + ZDIFF.0 * z, - XDIFF.1 * x + YDIFF.1 * y + ZDIFF.1 * z, - ); +// let diff = ( +// XDIFF.0 * x + YDIFF.0 * y + ZDIFF.0 * z, +// XDIFF.1 * x + YDIFF.1 * y + ZDIFF.1 * z, +// ); - let coords = (BASE_X + diff.0, BASE_Y + diff.1); +// let coords = (BASE_X + diff.0, BASE_Y + diff.1); - (coords.0 as u32, coords.1 as u32) -} +// (coords.0 as u32, coords.1 as u32) +// } diff --git a/src/render/mod.rs b/src/render/mod.rs index cd9856e..293e566 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,3 +1,101 @@ -pub mod processing; -pub mod models; +use std::time::Instant; + +use chashmap::{CHashMap, ReadGuard}; +use image::ImageBuffer; +use log::info; + +use crate::{ + dimension::Dimension, + render::{ + composite::image_buffer_blit, + models::{block_properties, processed_block_texture}, + }, +}; + +use self::processing::Texture; pub mod composite; +pub mod models; +pub mod processing; + +const SEG_SIZE: isize = 128; +const BLOCK_NAMESPACE_LEN: usize = "minecraft:".len(); + +pub struct Renderer { + dimension: Dimension, + textures: CHashMap<String, Texture>, +} +impl Renderer { + pub fn new(dimension: Dimension) -> Self { + Self { + dimension, + textures: Default::default(), + } + } + pub fn load_texture(&self, name: &str) -> ReadGuard<'_, std::string::String, Texture> { + match self.textures.contains_key(name) { + true => self.textures.get(name).unwrap(), + false => { + self.textures + .insert(name.to_owned(), processed_block_texture(name)); + self.load_texture(name) + } + } + } + + pub fn render_segment(&self, sx: isize, sy: isize) -> Texture { + let start_time = Instant::now(); + + let solid = |x: isize, y: isize, z: isize| { + self.dimension + .block(x, y, z) + .map(|b| block_properties(&b.name()[BLOCK_NAMESPACE_LEN..])) + .unwrap_or((true, true)) + }; + + let mut view: Texture = + ImageBuffer::new(16 * (SEG_SIZE + 1) as u32, 16 * (SEG_SIZE + 1) as u32); + + let mut visible = Vec::<((isize, isize, isize), (isize, isize, isize))>::new(); + + for ix in (sx * SEG_SIZE)..((sx + 1) * SEG_SIZE) { + for iy in (sy * (SEG_SIZE * 2))..((sy + 1) * (SEG_SIZE * 2)) { + for off in 0..=1 { + let mut y = 319; + let mut x = -ix + iy; + let mut z = ix + iy + off; + loop { + let (solid, has_texture) = solid(x, y, z); + if has_texture { + visible.push(((x, y, z), (ix, iy, off))); + } + if solid { + break; + } + y -= 1; + x -= 1; + z -= 1; + } + } + } + } + info!("{} visible blocks", visible.len()); + visible.sort_by_cached_key(|((x, y, z), _)| x + y + z); + + info!("compositing textures"); + for ((x, y, z), (ix, iy, off)) in visible { + let name = match self.dimension.block(x, y, z) { + Some(block) => block.name().to_owned(), + None => "minecraft:debug".to_owned(), + }; + let name = &name[BLOCK_NAMESPACE_LEN..]; + let texture = &self.load_texture(name); + let ix = ix * 16 + off * 8; + let iy = iy * 8 + off * 4; + image_buffer_blit(&mut view, texture, (ix as u32, iy as u32)); + } + + let end_time = Instant::now(); + info!("segment rendered in {:?}", end_time - start_time); + view + } +} diff --git a/src/render/models.rs b/src/render/models.rs index 24e7817..4a8673d 100644 --- a/src/render/models.rs +++ b/src/render/models.rs @@ -37,3 +37,15 @@ pub fn processed_block_texture(name: &str) -> ImageBuffer<Rgba<u8>, Vec<u8>> { } } } + +pub fn block_properties(name: &str) -> (bool, bool) { + match name { + "air" | "cave_air" => (false, false), + + "oak_leaves" | "birch_leaves" | "acacia_leaves" | "jungle_leaves" | "dark_oak_leaves" + | "spruce_leaves" => (false, true), + "water" => (false, true), + + _ => (true, true), + } +} |