aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dimension.rs64
-rw-r--r--src/main.rs136
-rw-r--r--src/render/composite.rs31
-rw-r--r--src/render/mod.rs102
-rw-r--r--src/render/models.rs12
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),
+ }
+}