diff --git a/src/chunk_builder.rs b/src/chunk_builder.rs index 591aa5f..41b1085 100644 --- a/src/chunk_builder.rs +++ b/src/chunk_builder.rs @@ -35,9 +35,12 @@ impl ChunkBuilder { } } - pub fn tick(&mut self, world: &mut world::World) { + pub fn tick(&mut self, world: &mut world::World, renderer: &mut render::Renderer) { while let Ok((id, val)) = self.built_recv.try_recv() { world.reset_building_flag(val.position); + + renderer.update_chunk_solid(val.position, &val.solid_buffer, val.solid_count); + self.free_builders.push(id); } if self.free_builders.is_empty() { @@ -67,17 +70,21 @@ struct BuildReq { struct BuildReply { position: (i32, i32, i32), solid_buffer: Vec, + solid_count: usize, } fn build_func(id: usize, textures: Arc>, work_recv: mpsc::Receiver, built_send: mpsc::Sender<(usize, BuildReply)>) { + use rand::{self, Rng}; loop { let BuildReq { snapshot, position, } = work_recv.recv().unwrap(); - println!("Build request for {:?}", position); let mut solid_buffer = vec![]; + let mut solid_count = 0; + + let mut rng = rand::thread_rng(); for y in 0 .. 16 { for x in 0 .. 16 { @@ -88,9 +95,14 @@ fn build_func(id: usize, textures: Arc>, work_rec } for verts in &PRECOMPUTED_VERTS { + let stone = render::Renderer::get_texture(&textures, rng.choose(&[ + "minecraft:blocks/lava_flow", + "minecraft:blocks/stone", + "minecraft:blocks/melon_side", + "minecraft:blocks/sand", + ]).unwrap()); + solid_count += 6; for vert in verts { - let stone = render::Renderer::get_texture(&textures, "minecraft:blocks/stone"); - let mut vert = vert.clone(); // TODO vert.r = 255; @@ -101,6 +113,9 @@ fn build_func(id: usize, textures: Arc>, work_rec vert.y += y as f32; vert.z += z as f32; + vert.toffsetx *= stone.get_width() as i16 * 16; + vert.toffsety *= stone.get_height() as i16 * 16; + // TODO vert.block_light = 15 * 4000; vert.sky_light = 15 * 4000; @@ -119,10 +134,10 @@ fn build_func(id: usize, textures: Arc>, work_rec } } - println!("> Build request for {:?}", position); built_send.send((id, BuildReply { position: position, solid_buffer: solid_buffer, + solid_count: solid_count, })).unwrap(); } } @@ -138,7 +153,7 @@ const PRECOMPUTED_VERTS: [[BlockVertex; 4]; 6] = [ BlockVertex::base(0.0, 0.0, 0.0, 0, 1), BlockVertex::base(0.0, 0.0, 1.0, 0, 0), BlockVertex::base(1.0, 0.0, 0.0, 1, 1), - BlockVertex::base(1.0, 0.0, 1.0, 1, 1), + BlockVertex::base(1.0, 0.0, 1.0, 1, 0), ], [ // North BlockVertex::base(0.0, 0.0, 0.0, 1, 1), diff --git a/src/main.rs b/src/main.rs index e300a5d..b850b4e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -124,13 +124,13 @@ fn main() { let textures = renderer.get_textures(); let mut game = Game { + server: server::Server::dummy_server(resource_manager.clone()), renderer: renderer, screen_sys: screen_sys, resource_manager: resource_manager, console: con, should_close: false, mouse_pos: (0, 0), - server: server::Server::dummy_server(), chunk_builder: chunk_builder::ChunkBuilder::new(textures), }; @@ -145,7 +145,18 @@ fn main() { let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time; let (width, height) = window.get_inner_size_pixels().unwrap(); - game.chunk_builder.tick(&mut game.server.world); + // TODO: TEMP + game.renderer.camera.pos.x = 0.5; + game.renderer.camera.pos.z = 0.5; + game.renderer.camera.pos.y = 15.0; + game.renderer.camera.yaw += 0.005 * delta; + if game.renderer.camera.yaw > ::std::f64::consts::PI * 2.0 { + game.renderer.camera.yaw = 0.0; + } + + game.server.tick(); + + game.chunk_builder.tick(&mut game.server.world, &mut game.renderer); game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container); game.console diff --git a/src/render/mod.rs b/src/render/mod.rs index c55a24d..49c4ab7 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -20,6 +20,7 @@ pub mod ui; use std::collections::HashMap; use std::sync::{Arc, RwLock}; +use std::io::Write; use resources; use gl; use image; @@ -54,7 +55,12 @@ pub struct Renderer { chunk_shader_alpha: ChunkShaderAlpha, trans_shader: TransShader, - camera: Camera, + chunks: HashMap<(i32, i32, i32), ChunkBuffer>, + element_buffer: gl::Buffer, + element_buffer_size: usize, + element_buffer_type: gl::Type, + + pub camera: Camera, perspective_matrix: cgmath::Matrix4, trans: Option, @@ -63,6 +69,20 @@ pub struct Renderer { last_height: u32, } +struct ChunkBuffer { + position: (i32, i32, i32), + + solid: Option, + trans: Option, +} + +struct ChunkRenderInfo { + array: gl::VertexArray, + buffer: gl::Buffer, + buffer_size: usize, + count: usize, +} + init_shader! { Program ChunkShader { vert = "chunk_vertex", @@ -163,6 +183,11 @@ impl Renderer { chunk_shader_alpha: chunk_shader_alpha, trans_shader: trans_shader, + chunks: HashMap::new(), + element_buffer: gl::Buffer::new(), + element_buffer_size: 0, + element_buffer_type: gl::UNSIGNED_BYTE, + last_width: 0, last_height: 0, @@ -242,6 +267,14 @@ impl Renderer { self.chunk_shader.light_level.set_float(LIGHT_LEVEL); self.chunk_shader.sky_offset.set_float(SKY_OFFSET); + for (pos, info) in &self.chunks { + if let Some(solid) = info.solid.as_ref() { + self.chunk_shader.offset.set_int3(pos.0, pos.1 * 4096, pos.2); + solid.array.bind(); + gl::draw_elements(gl::TRIANGLES, solid.count, self.element_buffer_type, 0); + } + } + // Line rendering // Model rendering // Cloud rendering @@ -284,6 +317,67 @@ impl Renderer { self.ui.tick(width, height); } + fn ensure_element_buffer(&mut self, size: usize) { + if self.element_buffer_size < size { + let (data, ty) = self::generate_element_buffer(size); + self.element_buffer_type = ty; + self.element_buffer.bind(gl::ELEMENT_ARRAY_BUFFER); + self.element_buffer.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW); + self.element_buffer_size = size; + } + } + + pub fn update_chunk_solid(&mut self, pos: (i32, i32, i32), data: &[u8], count: usize) { + self.ensure_element_buffer(count); + let buffer = self.chunks.entry(pos).or_insert(ChunkBuffer { + position: pos, + solid: None, + trans: None, + }); + if count == 0 { + if buffer.solid.is_some() { + buffer.solid = None; + } + return; + } + let new = buffer.solid.is_none(); + if buffer.solid.is_none() { + buffer.solid = Some(ChunkRenderInfo { + array: gl::VertexArray::new(), + buffer: gl::Buffer::new(), + buffer_size: 0, + count: 0, + }); + } + let info = buffer.solid.as_mut().unwrap(); + + info.array.bind(); + self.chunk_shader.position.enable(); + self.chunk_shader.texture_info.enable(); + self.chunk_shader.texture_offset.enable(); + self.chunk_shader.color.enable(); + self.chunk_shader.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 { + let mut target = info.buffer.map(gl::ARRAY_BUFFER, gl::WRITE_ONLY, data.len()); + target.write_all(data).unwrap(); + } + + self.chunk_shader.position.vertex_pointer(3, gl::FLOAT, false, 40, 0); + self.chunk_shader.texture_info.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 40, 12); + self.chunk_shader.texture_offset.vertex_pointer(3, gl::SHORT, false, 40, 20); + self.chunk_shader.color.vertex_pointer(3, gl::UNSIGNED_BYTE, true, 40, 28); + self.chunk_shader.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(); @@ -404,6 +498,7 @@ impl Renderer { val } else { t.load_texture(name); + println!("{:?} {:?}", name, t.textures); t.get_texture(name).unwrap() } } @@ -746,10 +841,8 @@ impl TextureManager { let missing = self.get_texture("steven:missing_texture").unwrap(); let mut full_name = String::new(); - if plugin != "minecraft" { - full_name.push_str(plugin); - full_name.push_str(":"); - } + full_name.push_str(plugin); + full_name.push_str(":"); full_name.push_str(name); let t = Texture { diff --git a/src/render/ui.rs b/src/render/ui.rs index 6f206af..b332b55 100644 --- a/src/render/ui.rs +++ b/src/render/ui.rs @@ -164,6 +164,7 @@ impl UIState { self.shader.screensize.set_float2(width as f32, height as f32); self.buffer.bind(gl::ARRAY_BUFFER); + self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER); if self.data.len() > self.prev_size { self.prev_size = self.data.len(); self.buffer.set_data(gl::ARRAY_BUFFER, &self.data, gl::STREAM_DRAW); diff --git a/src/server.rs b/src/server.rs index 24db244..e1df329 100644 --- a/src/server.rs +++ b/src/server.rs @@ -16,14 +16,19 @@ use protocol; use world; use world::block; use rand::{self, Rng}; +use std::sync::{Arc, RwLock}; +use resources; pub struct Server { conn: Option, pub world: world::World, + + resources: Arc>, + version: usize, } impl Server { - pub fn dummy_server() -> Server { + pub fn dummy_server(resources: Arc>) -> Server { let mut world = world::World::new(); let mut rng = rand::thread_rng(); for x in -7*16 .. 7*16 { @@ -34,9 +39,21 @@ impl Server { } } } + let version = resources.read().unwrap().version(); Server { conn: None, world: world, + + version: version, + resources: resources, + } + } + + pub fn tick(&mut self) { + let version = self.resources.read().unwrap().version(); + if version != self.version { + self.version = version; + self.world.flag_dirty_all(); } } } diff --git a/src/world/mod.rs b/src/world/mod.rs index b37c279..8c01b7b 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -68,6 +68,16 @@ impl World { } } + pub fn flag_dirty_all(&mut self) { + for (_, chunk) in &mut self.chunks { + for sec in &mut chunk.sections { + if let Some(sec) = sec.as_mut() { + sec.dirty = true; + } + } + } + } + pub fn capture_snapshot(&self, x: i32, y: i32, z: i32, w: i32, h: i32, d: i32) -> Snapshot { use std::cmp::{min, max}; let mut snapshot = Snapshot {