Transparent renderering

This commit is contained in:
Thinkofname 2016-03-25 01:17:03 +00:00
parent 93abbcc7cb
commit d7bc0b2b0f
4 changed files with 112 additions and 20 deletions

View File

@ -14,7 +14,7 @@ const NUM_WORKERS: usize = 8;
pub struct ChunkBuilder { pub struct ChunkBuilder {
threads: Vec<(mpsc::Sender<BuildReq>, thread::JoinHandle<()>)>, threads: Vec<(mpsc::Sender<BuildReq>, thread::JoinHandle<()>)>,
free_builders: Vec<(usize, Vec<u8>)>, free_builders: Vec<(usize, Vec<u8>, Vec<u8>)>,
built_recv: mpsc::Receiver<(usize, BuildReply)>, built_recv: mpsc::Receiver<(usize, BuildReply)>,
models: Arc<RwLock<model::Factory>>, models: Arc<RwLock<model::Factory>>,
@ -35,7 +35,7 @@ impl ChunkBuilder {
let models = models.clone(); let models = models.clone();
let id = i; let id = i;
threads.push((work_send, thread::spawn(move || build_func(id, models, work_recv, built_send)))); 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 { ChunkBuilder {
threads: threads, 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) { if let Some(sec) = world.get_section_mut(val.position.0, val.position.1, val.position.2) {
sec.cull_info = val.cull_info; sec.cull_info = val.cull_info;
renderer.update_chunk_solid(&mut sec.render_buffer, &val.solid_buffer, val.solid_count); 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(); 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() { if self.free_builders.is_empty() {
return; return;
@ -83,7 +85,8 @@ impl ChunkBuilder {
self.threads[t_id.0].0.send(BuildReq { self.threads[t_id.0].0.send(BuildReq {
snapshot: snapshot, snapshot: snapshot,
position: (x, y, z), position: (x, y, z),
buffer: t_id.1, solid_buffer: t_id.1,
trans_buffer: t_id.2,
}).unwrap(); }).unwrap();
if self.free_builders.is_empty() { if self.free_builders.is_empty() {
return; return;
@ -95,13 +98,16 @@ impl ChunkBuilder {
struct BuildReq { struct BuildReq {
snapshot: world::Snapshot, snapshot: world::Snapshot,
position: (i32, i32, i32), position: (i32, i32, i32),
buffer: Vec<u8>, solid_buffer: Vec<u8>,
trans_buffer: Vec<u8>,
} }
struct BuildReply { struct BuildReply {
position: (i32, i32, i32), position: (i32, i32, i32),
solid_buffer: Vec<u8>, solid_buffer: Vec<u8>,
solid_count: usize, solid_count: usize,
trans_buffer: Vec<u8>,
trans_count: usize,
cull_info: CullInfo, cull_info: CullInfo,
} }
@ -111,7 +117,8 @@ fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::R
let BuildReq { let BuildReq {
snapshot, snapshot,
position, position,
buffer, mut solid_buffer,
mut trans_buffer,
} = match work_recv.recv() { } = match work_recv.recv() {
Ok(val) => val, Ok(val) => val,
Err(_) => return, Err(_) => return,
@ -124,14 +131,15 @@ fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::R
(position.0 as u32 ^ position.2 as u32) | 1, (position.0 as u32 ^ position.2 as u32) | 1,
]); ]);
let mut solid_buffer = buffer;
let mut solid_count = 0; let mut solid_count = 0;
let mut trans_count = 0;
for y in 0 .. 16 { for y in 0 .. 16 {
for x in 0 .. 16 { for x in 0 .. 16 {
for z in 0 .. 16 { for z in 0 .. 16 {
let block = snapshot.get_block(x, y, z); 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 // Use one step of the rng so that
// if a block is placed in an empty // if a block is placed in an empty
// location is variant doesn't change // location is variant doesn't change
@ -142,10 +150,17 @@ fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::R
// TODO Liquids need a special case // TODO Liquids need a special case
let model_name = block.get_model(); let model_name = block.get_model();
let variant = block.get_model_variant(); let variant = block.get_model_variant();
solid_count += model::Factory::get_state_model( if !mat.transparent {
&models, &model_name.0, &model_name.1, &variant, &mut rng, solid_count += model::Factory::get_state_model(
&snapshot, x, y, z, &mut solid_buffer &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<RwLock<model::Factory>>, work_recv: mpsc::R
position: position, position: position,
solid_buffer: solid_buffer, solid_buffer: solid_buffer,
solid_count: solid_count, solid_count: solid_count,
trans_buffer: trans_buffer,
trans_count: trans_count,
cull_info: cull_info, cull_info: cull_info,
})).unwrap(); })).unwrap();
} }

View File

@ -320,16 +320,24 @@ impl Renderer {
gl::ClearFlags::Depth, gl::NEAREST gl::ClearFlags::Depth, gl::NEAREST
); );
trans.trans.bind();
gl::enable(gl::BLEND); gl::enable(gl::BLEND);
gl::depth_mask(false); gl::depth_mask(false);
trans.trans.bind();
gl::clear_color(0.0, 0.0, 0.0, 1.0); gl::clear_color(0.0, 0.0, 0.0, 1.0);
gl::clear(gl::ClearFlags::Color); gl::clear(gl::ClearFlags::Color);
gl::clear_buffer(gl::COLOR, 0, &[0.0, 0.0, 0.0, 1.0]); 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::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); 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::unbind_framebuffer();
gl::disable(gl::DEPTH_TEST); gl::disable(gl::DEPTH_TEST);
@ -402,6 +410,51 @@ impl Renderer {
info.count = count; 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) { fn do_pending_textures(&mut self) {
let len = { let len = {
let tex = self.textures.read().unwrap(); let tex = self.textures.read().unwrap();
@ -483,7 +536,7 @@ impl Renderer {
fn init_trans(&mut self, width: u32, height: u32) { fn init_trans(&mut self, width: u32, height: u32) {
self.trans = None; 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<RwLock<TextureManager>> { pub fn get_textures(&self) -> Arc<RwLock<TextureManager>> {
@ -559,7 +612,7 @@ init_shader! {
} }
impl TransInfo { 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(); let trans = gl::Framebuffer::new();
trans.bind(); trans.bind();
@ -584,9 +637,9 @@ impl TransInfo {
trans_depth.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAX_LEVEL, gl::LINEAR); 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); trans.texture_2d(gl::DEPTH_ATTACHMENT, gl::TEXTURE_2D, &trans_depth, 0);
shader.program.use_program(); chunk_shader.program.use_program();
gl::bind_frag_data_location(&shader.program, 0, "accum"); gl::bind_frag_data_location(&chunk_shader.program, 0, "accum");
gl::bind_frag_data_location(&shader.program, 1, "revealage"); gl::bind_frag_data_location(&chunk_shader.program, 1, "revealage");
gl::draw_buffers(&[gl::COLOR_ATTACHMENT_0, gl::COLOR_ATTACHMENT_1]); gl::draw_buffers(&[gl::COLOR_ATTACHMENT_0, gl::COLOR_ATTACHMENT_1]);
@ -605,6 +658,7 @@ impl TransInfo {
gl::unbind_framebuffer(); gl::unbind_framebuffer();
shader.program.use_program();
let array = gl::VertexArray::new(); let array = gl::VertexArray::new();
array.bind(); array.bind();
let buffer = gl::Buffer::new(); let buffer = gl::Buffer::new();

View File

@ -212,6 +212,7 @@ pub struct Material {
pub renderable: bool, pub renderable: bool,
pub should_cull_against: bool, pub should_cull_against: bool,
pub force_shade: bool, pub force_shade: bool,
pub transparent: bool,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -229,6 +230,7 @@ define_blocks! {
renderable: false, renderable: false,
should_cull_against: false, should_cull_against: false,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "air" ) }, model { ("minecraft", "air" ) },
} }
@ -246,6 +248,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", variant.as_string() ) }, model { ("minecraft", variant.as_string() ) },
} }
@ -258,6 +261,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "grass" ) }, model { ("minecraft", "grass" ) },
variant format!("snowy={}", snowy), variant format!("snowy={}", snowy),
@ -270,6 +274,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "dirt" ) }, model { ("minecraft", "dirt" ) },
} }
@ -280,6 +285,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "cobblestone" ) }, model { ("minecraft", "cobblestone" ) },
} }
@ -290,6 +296,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "planks" ) }, model { ("minecraft", "planks" ) },
} }
@ -300,6 +307,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: false, should_cull_against: false,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "sapling" ) }, model { ("minecraft", "sapling" ) },
} }
@ -310,6 +318,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "bedrock" ) }, model { ("minecraft", "bedrock" ) },
} }
@ -320,6 +329,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "water" ) }, model { ("minecraft", "water" ) },
} }
@ -330,6 +340,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "water" ) }, model { ("minecraft", "water" ) },
} }
@ -340,6 +351,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "lava" ) }, model { ("minecraft", "lava" ) },
} }
@ -350,6 +362,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "lava" ) }, model { ("minecraft", "lava" ) },
} }
@ -360,6 +373,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "sand" ) }, model { ("minecraft", "sand" ) },
} }
@ -370,6 +384,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "gravel" ) }, model { ("minecraft", "gravel" ) },
} }
@ -380,6 +395,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "gold_ore" ) }, model { ("minecraft", "gold_ore" ) },
} }
@ -390,6 +406,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "iron_ore" ) }, model { ("minecraft", "iron_ore" ) },
} }
@ -400,6 +417,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", "coal_ore" ) }, model { ("minecraft", "coal_ore" ) },
} }
@ -416,6 +434,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("minecraft", format!("{}_log", variant.as_string()) ) }, model { ("minecraft", format!("{}_log", variant.as_string()) ) },
variant format!("axis={}", axis.as_string()), variant format!("axis={}", axis.as_string()),
@ -437,6 +456,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: false, should_cull_against: false,
force_shade: true, force_shade: true,
transparent: false,
}, },
model { ("minecraft", format!("{}_leaves", variant.as_string()) ) }, model { ("minecraft", format!("{}_leaves", variant.as_string()) ) },
tint TintType::Foliage, tint TintType::Foliage,
@ -448,6 +468,7 @@ define_blocks! {
renderable: true, renderable: true,
should_cull_against: true, should_cull_against: true,
force_shade: false, force_shade: false,
transparent: false,
}, },
model { ("steven", "missing_block" ) }, model { ("steven", "missing_block" ) },
} }

View File

@ -514,7 +514,7 @@ pub struct Section {
} }
impl 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 { let mut section = Section {
cull_info: chunk_builder::CullInfo::all_vis(), cull_info: chunk_builder::CullInfo::all_vis(),
render_buffer: render::ChunkBuffer::new(), render_buffer: render::ChunkBuffer::new(),