diff --git a/src/chunk_builder.rs b/src/chunk_builder.rs index f44bfae..fcf6c23 100644 --- a/src/chunk_builder.rs +++ b/src/chunk_builder.rs @@ -5,6 +5,7 @@ use std::sync::{Arc, RwLock}; use std::io::Write; use byteorder::{WriteBytesExt, NativeEndian}; use world; +use world::block; use render; use resources; use model; @@ -147,7 +148,20 @@ fn build_func(id: usize, models: Arc>, work_recv: mpsc::R continue; } - // TODO Liquids need a special case + match block { + block::Block::Water{..} | block::Block::FlowingWater{..} => { + let tex = models.read().unwrap().textures.clone(); + trans_count += model::liquid::render_liquid(tex, false, &snapshot, x, y, z, &mut trans_buffer); + continue; + }, + block::Block::Lava{..} | block::Block::FlowingLava{..} => { + let tex = models.read().unwrap().textures.clone(); + solid_count += model::liquid::render_liquid(tex, true, &snapshot, x, y, z, &mut solid_buffer); + continue; + }, + _ => {}, + } + let model_name = block.get_model(); let variant = block.get_model_variant(); if !mat.transparent { diff --git a/src/model/liquid.rs b/src/model/liquid.rs new file mode 100644 index 0000000..2c4b078 --- /dev/null +++ b/src/model/liquid.rs @@ -0,0 +1,139 @@ + +use std::io::Write; +use std::sync::{Arc, RwLock}; +use world::{self, block}; +use chunk_builder::Direction; +use render; + +pub fn render_liquid(textures: Arc>,lava: bool, snapshot: &world::Snapshot, x: i32, y: i32, z: i32, buf: &mut W) -> usize { + let get_liquid = if lava { + get_lava_level + } else { + get_water_level + }; + + let mut count = 0; + + let (tl, tr, bl, br) = if get_liquid(snapshot, x, y + 1, z).is_some() { + (8, 8, 8, 8) + } else { + ( + average_liquid_level(get_liquid, snapshot, x, y, z), + average_liquid_level(get_liquid, snapshot, x+1, y, z), + average_liquid_level(get_liquid, snapshot, x, y, z+1), + average_liquid_level(get_liquid, snapshot, x+1, y, z+1) + ) + }; + + let tex = match snapshot.get_block(x, y, z) { + block::Block::Water{..} => render::Renderer::get_texture(&textures, "minecraft:blocks/water_still"), + block::Block::FlowingWater{..} => render::Renderer::get_texture(&textures, "minecraft:blocks/water_flow"), + block::Block::Lava{..} => render::Renderer::get_texture(&textures, "minecraft:blocks/lava_still"), + block::Block::FlowingLava{..} => render::Renderer::get_texture(&textures, "minecraft:blocks/lava_flow"), + _ => unreachable!(), + }; + let ux1 = 0i16; + let ux2 = 16i16 * tex.get_width() as i16; + let uy1 = 0i16; + let uy2 = 16i16 * tex.get_height() as i16; + + for dir in Direction::all() { + let (ox, oy, oz) = dir.get_offset(); + let special = dir == Direction::Up && (tl < 8 || tr < 8 || bl < 8 || br < 8); + let block = snapshot.get_block(x+ox, y+oy, z+oz); + if special || (!block.get_material().should_cull_against && get_liquid(snapshot, x+ox, y+oy, z+oz).is_none()) { + let verts = dir.get_verts(); + for vert in verts { + let mut vert = vert.clone(); + vert.tx = tex.get_x() as u16; + vert.ty = tex.get_y() as u16; + vert.tw = tex.get_width() as u16; + vert.th = tex.get_height() as u16; + vert.tatlas = tex.atlas as i16; + vert.r = 255; + vert.g = 255; + vert.b = 255; + + if vert.y == 0.0 { + vert.y = y as f32; + } else { + let height = match (vert.x, vert.z) { + (0.0, 0.0) => ((16.0 / 8.0) * (tl as f32)) as i32, + (_, 0.0) => ((16.0 / 8.0) * (tr as f32)) as i32, + (0.0, _) => ((16.0 / 8.0) * (bl as f32)) as i32, + (_, _) => ((16.0 / 8.0) * (br as f32)) as i32, + }; + vert.y = (height as f32)/16.0 + (y as f32); + } + + vert.x += x as f32; + vert.z += z as f32; + + let (bl, sl) = super::calculate_light( + &snapshot, + x, y, z, + vert.x as f64, + vert.y as f64, + vert.z as f64, + dir, + !lava, + false + ); + vert.block_light = bl; + vert.sky_light = sl; + + if vert.toffsetx == 0 { + vert.toffsetx = ux1; + } else { + vert.toffsetx = ux2; + } + + if vert.toffsety == 0 { + vert.toffsety = uy1; + } else { + vert.toffsety = uy2; + } + + vert.write(buf); + } + count += 6; + } + } + + count +} + +fn average_liquid_level( + get: fn(&world::Snapshot, i32, i32, i32) -> Option, + snapshot: &world::Snapshot, x: i32, y: i32, z: i32 +) -> i32 { + let mut level = 0; + for xx in -1 .. 1 { + for zz in -1 .. 1 { + if get(snapshot, x+xx, y+1, z+zz).is_some() { + return 8; + } + if let Some(l) = get(snapshot, x+xx, y, z+zz) { + let nl = 7 - (l & 0x7); + if nl > level { + level = nl; + } + } + } + } + level +} + +fn get_water_level(snapshot: &world::Snapshot, x: i32, y: i32, z: i32) -> Option { + match snapshot.get_block(x, y, z) { + block::Block::Water{level} | block::Block::FlowingWater{level} => Some(level), + _ => None, + } +} + +fn get_lava_level(snapshot: &world::Snapshot, x: i32, y: i32, z: i32) -> Option { + match snapshot.get_block(x, y, z) { + block::Block::Lava{level} | block::Block::FlowingLava{level} => Some(level), + _ => None, + } +} diff --git a/src/model/mod.rs b/src/model/mod.rs index 6c4662c..24860c4 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -1,4 +1,6 @@ +pub mod liquid; + use std::sync::{Arc, RwLock}; use std::collections::HashMap; use std::io::Write; @@ -17,7 +19,7 @@ use image::{self, GenericImage}; pub struct Factory { resources: Arc>, - textures: Arc>, + pub textures: Arc>, models: HashMap>, diff --git a/src/render/mod.rs b/src/render/mod.rs index c7a9cd0..8c0f310 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -138,7 +138,7 @@ init_shader! { offset => "offset", texture => "textures", light_level => "lightLevel", - sky_offset => "sky_offset", + sky_offset => "skyOffset", }, } } diff --git a/src/world/block/mod.rs b/src/world/block/mod.rs index 53cc540..9c361be 100644 --- a/src/world/block/mod.rs +++ b/src/world/block/mod.rs @@ -322,34 +322,40 @@ define_blocks! { }, model { ("minecraft", "bedrock" ) }, } - FlowingWater { // TODO + FlowingWater { props { + level: i32 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], }, + data Some(level as usize), material Material { renderable: true, - should_cull_against: true, + should_cull_against: false, force_shade: false, - transparent: false, + transparent: true, }, model { ("minecraft", "water" ) }, } - Water { // TODO + Water { props { + level: i32 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], }, + data Some(level as usize), material Material { renderable: true, - should_cull_against: true, + should_cull_against: false, force_shade: false, - transparent: false, + transparent: true, }, model { ("minecraft", "water" ) }, } - FlowingLava { // TODO + FlowingLava { props { + level: i32 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], }, + data Some(level as usize), material Material { renderable: true, - should_cull_against: true, + should_cull_against: false, force_shade: false, transparent: false, }, @@ -357,10 +363,12 @@ define_blocks! { } Lava { props { + level: i32 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], }, + data Some(level as usize), material Material { renderable: true, - should_cull_against: true, + should_cull_against: false, force_shade: false, transparent: false, },