diff --git a/Cargo.lock b/Cargo.lock index 931bdf6..3c53295 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -268,6 +268,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "glam" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad83ab008a4fa3b31dfa713dd41b5a9bdea1e94e4cf1e2fc274ffbd49b0271d3" + [[package]] name = "heck" version = "0.4.1" @@ -368,6 +374,7 @@ dependencies = [ "enumflags2", "fastnbt", "flate2", + "glam", "image", "itertools", "num-integer", diff --git a/Cargo.toml b/Cargo.toml index 9a82052..59b435c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ clap = { version = "4.1.4", features = ["derive"] } enumflags2 = "0.7.5" fastnbt = "2.3.2" flate2 = "1.0.25" +glam = "0.24.0" image = { version = "0.24.5", default-features = false, features = ["png"] } itertools = "0.10.5" num-integer = "0.1.45" diff --git a/src/resource/biomes.rs b/src/resource/biomes.rs index 036cafc..cf0db4b 100644 --- a/src/resource/biomes.rs +++ b/src/resource/biomes.rs @@ -60,6 +60,18 @@ impl Biome { ..self } } + + fn decode(val: i8) -> f32 { + f32::from(val) / 20.0 + } + + pub fn temp(&self) -> f32 { + Self::decode(self.temp) + } + + pub fn downfall(&self) -> f32 { + Self::decode(self.downfall) + } } // Data extracted from Minecraft code decompiled using https://github.com/Hexeption/MCP-Reborn diff --git a/src/resource/block_color.rs b/src/resource/block_color.rs index 31434de..21cd5c7 100644 --- a/src/resource/block_color.rs +++ b/src/resource/block_color.rs @@ -1,10 +1,95 @@ -use super::{Biome, BlockType}; +use super::{Biome, BlockType, Color}; -pub fn block_color(block: BlockType, _biome: &Biome, depth: f32) -> [u8; 4] { - let h = 0.5 + 0.005 * depth; - let c = block - .color - .0 - .map(|v| (f32::from(v) * h).clamp(0.0, 255.0) as u8); - [c[0], c[1], c[2], 255] +use glam::Vec3; + +fn color_vec(color: Color) -> Vec3 { + Vec3::from_array(color.0.map(f32::from)) +} + +fn color_from_params(colors: &[Vec3; 3], biome: &Biome, depth: f32) -> Vec3 { + let temp = (biome.temp() - f32::max((depth - 64.0) / 600.0, 0.0)).clamp(0.0, 1.0); + let downfall = biome.downfall().clamp(0.0, 1.0) * temp; + + colors[0] + temp * colors[1] + downfall * colors[2] +} + +trait BiomeExt { + fn grass_color(&self, depth: f32) -> Vec3; + fn foliage_color(&self, depth: f32) -> Vec3; + fn water_color(&self) -> Vec3; +} + +impl BiomeExt for Biome { + fn grass_color(&self, depth: f32) -> Vec3 { + const GRASS_COLORS: [Vec3; 3] = [ + Vec3::new(0.502, 0.706, 0.592), // lower right + Vec3::new(0.247, 0.012, -0.259), // lower left - lower right + Vec3::new(-0.471, 0.086, -0.133), // upper left - lower left + ]; + + self.grass_color + .map(color_vec) + .unwrap_or_else(|| color_from_params(&GRASS_COLORS, self, depth)) + } + + fn foliage_color(&self, depth: f32) -> Vec3 { + use super::BiomeGrassColorModifier::*; + + const FOLIAGE_COLORS: [Vec3; 3] = [ + Vec3::new(0.502, 0.706, 0.592), // lower right + Vec3::new(0.247, 0.012, -0.259), // lower left - lower right + Vec3::new(-0.471, 0.086, -0.133), // upper left - lower left + ]; + const DARK_FOREST_COLOR: Vec3 = Vec3::new(0.157, 0.204, 0.039); // == color_vec(Color([40, 52, 10])) + const SWAMP_FOLIAGE_COLOR: Vec3 = Vec3::new(0.416, 0.439, 0.224); // == color_vec(Color([106, 112, 57])) + + let regular_color = || { + self.foliage_color + .map(color_vec) + .unwrap_or_else(|| color_from_params(&FOLIAGE_COLORS, self, depth)) + }; + + match self.grass_color_modifier { + Some(DarkForest) => 0.5 * (regular_color() + DARK_FOREST_COLOR), + Some(Swamp) => SWAMP_FOLIAGE_COLOR, + None => regular_color(), + } + } + + fn water_color(&self) -> Vec3 { + const DEFAULT_WATER_COLOR: Vec3 = Vec3::new(0.247, 0.463, 0.894); // == color_vec(Color([63, 118, 228])) + + self.water_color + .map(color_vec) + .unwrap_or(DEFAULT_WATER_COLOR) + } +} + +const BIRCH_COLOR: Vec3 = Vec3::new(0.502, 0.655, 0.333); // == color_vec(Color([128, 167, 85])) +const EVERGREEN_COLOR: Vec3 = Vec3::new(0.380, 0.600, 0.380); // == color_vec(Color([97, 153, 97])) + +pub fn block_color(block: BlockType, biome: &Biome, depth: f32) -> [u8; 4] { + use super::BlockFlag::*; + + let mut color = color_vec(block.color); + + if block.is(Grass) { + color *= biome.grass_color(depth); + } + if block.is(Foliage) { + color *= biome.foliage_color(depth); + } + if block.is(Birch) { + color *= BIRCH_COLOR; + } + if block.is(Spruce) { + color *= EVERGREEN_COLOR; + } + if block.is(Water) { + color *= biome.water_color(); + } + + color *= 0.5 + 0.005 * depth; + + [color[0] as u8, color[1] as u8, color[2] as u8, 255] } diff --git a/src/resource/mod.rs b/src/resource/mod.rs index a1abaf8..7095f68 100644 --- a/src/resource/mod.rs +++ b/src/resource/mod.rs @@ -90,7 +90,7 @@ impl BlockTypes { } } -pub use biomes::Biome; +pub use biomes::{Biome, BiomeGrassColorModifier}; pub use block_color::block_color; #[derive(Debug)]