diff --git a/src/chunk_builder.rs b/src/chunk_builder.rs index bafd727..f44bfae 100644 --- a/src/chunk_builder.rs +++ b/src/chunk_builder.rs @@ -14,7 +14,7 @@ const NUM_WORKERS: usize = 8; pub struct ChunkBuilder { threads: Vec<(mpsc::Sender, thread::JoinHandle<()>)>, - free_builders: Vec<(usize, Vec)>, + free_builders: Vec<(usize, Vec, Vec)>, built_recv: mpsc::Receiver<(usize, BuildReply)>, models: Arc>, @@ -35,7 +35,7 @@ impl ChunkBuilder { let models = models.clone(); let id = i; threads.push((work_send, thread::spawn(move || build_func(id, models, work_recv, built_send)))); - free.push((i, vec![])); + free.push((i, vec![], vec![])); } ChunkBuilder { threads: threads, @@ -62,10 +62,12 @@ impl ChunkBuilder { if let Some(sec) = world.get_section_mut(val.position.0, val.position.1, val.position.2) { sec.cull_info = val.cull_info; renderer.update_chunk_solid(&mut sec.render_buffer, &val.solid_buffer, val.solid_count); + renderer.update_chunk_trans(&mut sec.render_buffer, &val.trans_buffer, val.trans_count); } val.solid_buffer.clear(); - self.free_builders.push((id, val.solid_buffer)); + val.trans_buffer.clear(); + self.free_builders.push((id, val.solid_buffer, val.trans_buffer)); } if self.free_builders.is_empty() { return; @@ -83,7 +85,8 @@ impl ChunkBuilder { self.threads[t_id.0].0.send(BuildReq { snapshot: snapshot, position: (x, y, z), - buffer: t_id.1, + solid_buffer: t_id.1, + trans_buffer: t_id.2, }).unwrap(); if self.free_builders.is_empty() { return; @@ -95,13 +98,16 @@ impl ChunkBuilder { struct BuildReq { snapshot: world::Snapshot, position: (i32, i32, i32), - buffer: Vec, + solid_buffer: Vec, + trans_buffer: Vec, } struct BuildReply { position: (i32, i32, i32), solid_buffer: Vec, solid_count: usize, + trans_buffer: Vec, + trans_count: usize, cull_info: CullInfo, } @@ -111,7 +117,8 @@ fn build_func(id: usize, models: Arc>, work_recv: mpsc::R let BuildReq { snapshot, position, - buffer, + mut solid_buffer, + mut trans_buffer, } = match work_recv.recv() { Ok(val) => val, Err(_) => return, @@ -124,14 +131,15 @@ fn build_func(id: usize, models: Arc>, work_recv: mpsc::R (position.0 as u32 ^ position.2 as u32) | 1, ]); - let mut solid_buffer = buffer; let mut solid_count = 0; + let mut trans_count = 0; for y in 0 .. 16 { for x in 0 .. 16 { for z in 0 .. 16 { let block = snapshot.get_block(x, y, z); - if !block.get_material().renderable { + let mat = block.get_material(); + if !mat.renderable { // Use one step of the rng so that // if a block is placed in an empty // location is variant doesn't change @@ -142,10 +150,17 @@ fn build_func(id: usize, models: Arc>, work_recv: mpsc::R // TODO Liquids need a special case let model_name = block.get_model(); let variant = block.get_model_variant(); - solid_count += model::Factory::get_state_model( - &models, &model_name.0, &model_name.1, &variant, &mut rng, - &snapshot, x, y, z, &mut solid_buffer - ); + if !mat.transparent { + solid_count += model::Factory::get_state_model( + &models, &model_name.0, &model_name.1, &variant, &mut rng, + &snapshot, x, y, z, &mut solid_buffer + ); + } else { + trans_count += model::Factory::get_state_model( + &models, &model_name.0, &model_name.1, &variant, &mut rng, + &snapshot, x, y, z, &mut trans_buffer + ); + } } } } @@ -156,6 +171,8 @@ fn build_func(id: usize, models: Arc>, work_recv: mpsc::R position: position, solid_buffer: solid_buffer, solid_count: solid_count, + trans_buffer: trans_buffer, + trans_count: trans_count, cull_info: cull_info, })).unwrap(); } diff --git a/src/render/mod.rs b/src/render/mod.rs index 214e000..c7a9cd0 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -320,16 +320,24 @@ impl Renderer { gl::ClearFlags::Depth, gl::NEAREST ); - trans.trans.bind(); gl::enable(gl::BLEND); gl::depth_mask(false); + trans.trans.bind(); gl::clear_color(0.0, 0.0, 0.0, 1.0); gl::clear(gl::ClearFlags::Color); gl::clear_buffer(gl::COLOR, 0, &[0.0, 0.0, 0.0, 1.0]); gl::clear_buffer(gl::COLOR, 1, &[0.0, 0.0, 0.0, 0.0]); gl::blend_func_separate(gl::ONE_FACTOR, gl::ONE_FACTOR, gl::ZERO_FACTOR, gl::ONE_MINUS_SRC_ALPHA); - // TODO: Draw chunks + for (pos, info) in world.get_render_list().into_iter().rev() { + if let Some(trans) = info.trans.as_ref() { + if trans.count > 0 { + self.chunk_shader_alpha.offset.set_int3(pos.0, pos.1 * 4096, pos.2); + trans.array.bind(); + gl::draw_elements(gl::TRIANGLES, trans.count, self.element_buffer_type, 0); + } + } + } gl::unbind_framebuffer(); gl::disable(gl::DEPTH_TEST); @@ -402,6 +410,51 @@ impl Renderer { info.count = count; } + pub fn update_chunk_trans(&mut self, buffer: &mut ChunkBuffer, data: &[u8], count: usize) { + self.ensure_element_buffer(count); + if count == 0 { + if buffer.trans.is_some() { + buffer.trans = None; + } + return; + } + let new = buffer.trans.is_none(); + if buffer.trans.is_none() { + buffer.trans = Some(ChunkRenderInfo { + array: gl::VertexArray::new(), + buffer: gl::Buffer::new(), + buffer_size: 0, + count: 0, + }); + } + let info = buffer.trans.as_mut().unwrap(); + + info.array.bind(); + self.chunk_shader_alpha.position.enable(); + self.chunk_shader_alpha.texture_info.enable(); + self.chunk_shader_alpha.texture_offset.enable(); + self.chunk_shader_alpha.color.enable(); + self.chunk_shader_alpha.lighting.enable(); + + self.element_buffer.bind(gl::ELEMENT_ARRAY_BUFFER); + + info.buffer.bind(gl::ARRAY_BUFFER); + if new || info.buffer_size < data.len() { + info.buffer_size = data.len(); + info.buffer.set_data(gl::ARRAY_BUFFER, data, gl::DYNAMIC_DRAW); + } else { + info.buffer.re_set_data(gl::ARRAY_BUFFER, data); + } + + self.chunk_shader_alpha.position.vertex_pointer(3, gl::FLOAT, false, 40, 0); + self.chunk_shader_alpha.texture_info.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 40, 12); + self.chunk_shader_alpha.texture_offset.vertex_pointer(3, gl::SHORT, false, 40, 20); + self.chunk_shader_alpha.color.vertex_pointer(3, gl::UNSIGNED_BYTE, true, 40, 28); + self.chunk_shader_alpha.lighting.vertex_pointer(2, gl::UNSIGNED_SHORT, false, 40, 32); + + info.count = count; + } + fn do_pending_textures(&mut self) { let len = { let tex = self.textures.read().unwrap(); @@ -483,7 +536,7 @@ impl Renderer { fn init_trans(&mut self, width: u32, height: u32) { self.trans = None; - self.trans = Some(TransInfo::new(width, height, &self.trans_shader)); + self.trans = Some(TransInfo::new(width, height, &self.chunk_shader_alpha, &self.trans_shader)); } pub fn get_textures(&self) -> Arc> { @@ -559,7 +612,7 @@ init_shader! { } impl TransInfo { - pub fn new(width: u32, height: u32, shader: &TransShader) -> TransInfo { + pub fn new(width: u32, height: u32, chunk_shader: &ChunkShaderAlpha, shader: &TransShader) -> TransInfo { let trans = gl::Framebuffer::new(); trans.bind(); @@ -584,9 +637,9 @@ impl TransInfo { trans_depth.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAX_LEVEL, gl::LINEAR); trans.texture_2d(gl::DEPTH_ATTACHMENT, gl::TEXTURE_2D, &trans_depth, 0); - shader.program.use_program(); - gl::bind_frag_data_location(&shader.program, 0, "accum"); - gl::bind_frag_data_location(&shader.program, 1, "revealage"); + chunk_shader.program.use_program(); + gl::bind_frag_data_location(&chunk_shader.program, 0, "accum"); + gl::bind_frag_data_location(&chunk_shader.program, 1, "revealage"); gl::draw_buffers(&[gl::COLOR_ATTACHMENT_0, gl::COLOR_ATTACHMENT_1]); @@ -605,6 +658,7 @@ impl TransInfo { gl::unbind_framebuffer(); + shader.program.use_program(); let array = gl::VertexArray::new(); array.bind(); let buffer = gl::Buffer::new(); diff --git a/src/world/block/mod.rs b/src/world/block/mod.rs index ebdab84..53cc540 100644 --- a/src/world/block/mod.rs +++ b/src/world/block/mod.rs @@ -212,6 +212,7 @@ pub struct Material { pub renderable: bool, pub should_cull_against: bool, pub force_shade: bool, + pub transparent: bool, } #[derive(Clone, Copy)] @@ -229,6 +230,7 @@ define_blocks! { renderable: false, should_cull_against: false, force_shade: false, + transparent: false, }, model { ("minecraft", "air" ) }, } @@ -246,6 +248,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", variant.as_string() ) }, } @@ -258,6 +261,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "grass" ) }, variant format!("snowy={}", snowy), @@ -270,6 +274,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "dirt" ) }, } @@ -280,6 +285,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "cobblestone" ) }, } @@ -290,6 +296,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "planks" ) }, } @@ -300,6 +307,7 @@ define_blocks! { renderable: true, should_cull_against: false, force_shade: false, + transparent: false, }, model { ("minecraft", "sapling" ) }, } @@ -310,6 +318,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "bedrock" ) }, } @@ -320,6 +329,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "water" ) }, } @@ -330,6 +340,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "water" ) }, } @@ -340,6 +351,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "lava" ) }, } @@ -350,6 +362,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "lava" ) }, } @@ -360,6 +373,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "sand" ) }, } @@ -370,6 +384,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "gravel" ) }, } @@ -380,6 +395,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "gold_ore" ) }, } @@ -390,6 +406,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "iron_ore" ) }, } @@ -400,6 +417,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", "coal_ore" ) }, } @@ -416,6 +434,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("minecraft", format!("{}_log", variant.as_string()) ) }, variant format!("axis={}", axis.as_string()), @@ -437,6 +456,7 @@ define_blocks! { renderable: true, should_cull_against: false, force_shade: true, + transparent: false, }, model { ("minecraft", format!("{}_leaves", variant.as_string()) ) }, tint TintType::Foliage, @@ -448,6 +468,7 @@ define_blocks! { renderable: true, should_cull_against: true, force_shade: false, + transparent: false, }, model { ("steven", "missing_block" ) }, } diff --git a/src/world/mod.rs b/src/world/mod.rs index 71c870f..f35cc77 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -514,7 +514,7 @@ pub struct Section { } impl Section { - fn new(x: i32, y: u8, z: i32) -> Section { + fn new(_x: i32, y: u8, _z: i32) -> Section { let mut section = Section { cull_info: chunk_builder::CullInfo::all_vis(), render_buffer: render::ChunkBuffer::new(),