Initial rendering implementation
This commit is contained in:
parent
ad81ef8f17
commit
6bee18b68c
|
@ -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() {
|
while let Ok((id, val)) = self.built_recv.try_recv() {
|
||||||
world.reset_building_flag(val.position);
|
world.reset_building_flag(val.position);
|
||||||
|
|
||||||
|
renderer.update_chunk_solid(val.position, &val.solid_buffer, val.solid_count);
|
||||||
|
|
||||||
self.free_builders.push(id);
|
self.free_builders.push(id);
|
||||||
}
|
}
|
||||||
if self.free_builders.is_empty() {
|
if self.free_builders.is_empty() {
|
||||||
|
@ -67,17 +70,21 @@ struct BuildReq {
|
||||||
struct BuildReply {
|
struct BuildReply {
|
||||||
position: (i32, i32, i32),
|
position: (i32, i32, i32),
|
||||||
solid_buffer: Vec<u8>,
|
solid_buffer: Vec<u8>,
|
||||||
|
solid_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_recv: mpsc::Receiver<BuildReq>, built_send: mpsc::Sender<(usize, BuildReply)>) {
|
fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_recv: mpsc::Receiver<BuildReq>, built_send: mpsc::Sender<(usize, BuildReply)>) {
|
||||||
|
use rand::{self, Rng};
|
||||||
loop {
|
loop {
|
||||||
let BuildReq {
|
let BuildReq {
|
||||||
snapshot,
|
snapshot,
|
||||||
position,
|
position,
|
||||||
} = work_recv.recv().unwrap();
|
} = work_recv.recv().unwrap();
|
||||||
println!("Build request for {:?}", position);
|
|
||||||
|
|
||||||
let mut solid_buffer = vec![];
|
let mut solid_buffer = vec![];
|
||||||
|
let mut solid_count = 0;
|
||||||
|
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
for y in 0 .. 16 {
|
for y in 0 .. 16 {
|
||||||
for x in 0 .. 16 {
|
for x in 0 .. 16 {
|
||||||
|
@ -88,9 +95,14 @@ fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_rec
|
||||||
}
|
}
|
||||||
|
|
||||||
for verts in &PRECOMPUTED_VERTS {
|
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 {
|
for vert in verts {
|
||||||
let stone = render::Renderer::get_texture(&textures, "minecraft:blocks/stone");
|
|
||||||
|
|
||||||
let mut vert = vert.clone();
|
let mut vert = vert.clone();
|
||||||
// TODO
|
// TODO
|
||||||
vert.r = 255;
|
vert.r = 255;
|
||||||
|
@ -101,6 +113,9 @@ fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_rec
|
||||||
vert.y += y as f32;
|
vert.y += y as f32;
|
||||||
vert.z += z as f32;
|
vert.z += z as f32;
|
||||||
|
|
||||||
|
vert.toffsetx *= stone.get_width() as i16 * 16;
|
||||||
|
vert.toffsety *= stone.get_height() as i16 * 16;
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
vert.block_light = 15 * 4000;
|
vert.block_light = 15 * 4000;
|
||||||
vert.sky_light = 15 * 4000;
|
vert.sky_light = 15 * 4000;
|
||||||
|
@ -119,10 +134,10 @@ fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_rec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("> Build request for {:?}", position);
|
|
||||||
built_send.send((id, BuildReply {
|
built_send.send((id, BuildReply {
|
||||||
position: position,
|
position: position,
|
||||||
solid_buffer: solid_buffer,
|
solid_buffer: solid_buffer,
|
||||||
|
solid_count: solid_count,
|
||||||
})).unwrap();
|
})).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, 0.0, 0, 1),
|
||||||
BlockVertex::base(0.0, 0.0, 1.0, 0, 0),
|
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, 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
|
[ // North
|
||||||
BlockVertex::base(0.0, 0.0, 0.0, 1, 1),
|
BlockVertex::base(0.0, 0.0, 0.0, 1, 1),
|
||||||
|
|
15
src/main.rs
15
src/main.rs
|
@ -124,13 +124,13 @@ fn main() {
|
||||||
|
|
||||||
let textures = renderer.get_textures();
|
let textures = renderer.get_textures();
|
||||||
let mut game = Game {
|
let mut game = Game {
|
||||||
|
server: server::Server::dummy_server(resource_manager.clone()),
|
||||||
renderer: renderer,
|
renderer: renderer,
|
||||||
screen_sys: screen_sys,
|
screen_sys: screen_sys,
|
||||||
resource_manager: resource_manager,
|
resource_manager: resource_manager,
|
||||||
console: con,
|
console: con,
|
||||||
should_close: false,
|
should_close: false,
|
||||||
mouse_pos: (0, 0),
|
mouse_pos: (0, 0),
|
||||||
server: server::Server::dummy_server(),
|
|
||||||
chunk_builder: chunk_builder::ChunkBuilder::new(textures),
|
chunk_builder: chunk_builder::ChunkBuilder::new(textures),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -145,7 +145,18 @@ fn main() {
|
||||||
let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
|
let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
|
||||||
let (width, height) = window.get_inner_size_pixels().unwrap();
|
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.screen_sys.tick(delta, &mut game.renderer, &mut ui_container);
|
||||||
game.console
|
game.console
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub mod ui;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
use std::io::Write;
|
||||||
use resources;
|
use resources;
|
||||||
use gl;
|
use gl;
|
||||||
use image;
|
use image;
|
||||||
|
@ -54,7 +55,12 @@ pub struct Renderer {
|
||||||
chunk_shader_alpha: ChunkShaderAlpha,
|
chunk_shader_alpha: ChunkShaderAlpha,
|
||||||
trans_shader: TransShader,
|
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<f32>,
|
perspective_matrix: cgmath::Matrix4<f32>,
|
||||||
|
|
||||||
trans: Option<TransInfo>,
|
trans: Option<TransInfo>,
|
||||||
|
@ -63,6 +69,20 @@ pub struct Renderer {
|
||||||
last_height: u32,
|
last_height: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ChunkBuffer {
|
||||||
|
position: (i32, i32, i32),
|
||||||
|
|
||||||
|
solid: Option<ChunkRenderInfo>,
|
||||||
|
trans: Option<ChunkRenderInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ChunkRenderInfo {
|
||||||
|
array: gl::VertexArray,
|
||||||
|
buffer: gl::Buffer,
|
||||||
|
buffer_size: usize,
|
||||||
|
count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
init_shader! {
|
init_shader! {
|
||||||
Program ChunkShader {
|
Program ChunkShader {
|
||||||
vert = "chunk_vertex",
|
vert = "chunk_vertex",
|
||||||
|
@ -163,6 +183,11 @@ impl Renderer {
|
||||||
chunk_shader_alpha: chunk_shader_alpha,
|
chunk_shader_alpha: chunk_shader_alpha,
|
||||||
trans_shader: trans_shader,
|
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_width: 0,
|
||||||
last_height: 0,
|
last_height: 0,
|
||||||
|
|
||||||
|
@ -242,6 +267,14 @@ impl Renderer {
|
||||||
self.chunk_shader.light_level.set_float(LIGHT_LEVEL);
|
self.chunk_shader.light_level.set_float(LIGHT_LEVEL);
|
||||||
self.chunk_shader.sky_offset.set_float(SKY_OFFSET);
|
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
|
// Line rendering
|
||||||
// Model rendering
|
// Model rendering
|
||||||
// Cloud rendering
|
// Cloud rendering
|
||||||
|
@ -284,6 +317,67 @@ impl Renderer {
|
||||||
self.ui.tick(width, height);
|
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) {
|
fn do_pending_textures(&mut self) {
|
||||||
let len = {
|
let len = {
|
||||||
let tex = self.textures.read().unwrap();
|
let tex = self.textures.read().unwrap();
|
||||||
|
@ -404,6 +498,7 @@ impl Renderer {
|
||||||
val
|
val
|
||||||
} else {
|
} else {
|
||||||
t.load_texture(name);
|
t.load_texture(name);
|
||||||
|
println!("{:?} {:?}", name, t.textures);
|
||||||
t.get_texture(name).unwrap()
|
t.get_texture(name).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -746,10 +841,8 @@ impl TextureManager {
|
||||||
let missing = self.get_texture("steven:missing_texture").unwrap();
|
let missing = self.get_texture("steven:missing_texture").unwrap();
|
||||||
|
|
||||||
let mut full_name = String::new();
|
let mut full_name = String::new();
|
||||||
if plugin != "minecraft" {
|
full_name.push_str(plugin);
|
||||||
full_name.push_str(plugin);
|
full_name.push_str(":");
|
||||||
full_name.push_str(":");
|
|
||||||
}
|
|
||||||
full_name.push_str(name);
|
full_name.push_str(name);
|
||||||
|
|
||||||
let t = Texture {
|
let t = Texture {
|
||||||
|
|
|
@ -164,6 +164,7 @@ impl UIState {
|
||||||
self.shader.screensize.set_float2(width as f32, height as f32);
|
self.shader.screensize.set_float2(width as f32, height as f32);
|
||||||
|
|
||||||
self.buffer.bind(gl::ARRAY_BUFFER);
|
self.buffer.bind(gl::ARRAY_BUFFER);
|
||||||
|
self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
|
||||||
if self.data.len() > self.prev_size {
|
if self.data.len() > self.prev_size {
|
||||||
self.prev_size = self.data.len();
|
self.prev_size = self.data.len();
|
||||||
self.buffer.set_data(gl::ARRAY_BUFFER, &self.data, gl::STREAM_DRAW);
|
self.buffer.set_data(gl::ARRAY_BUFFER, &self.data, gl::STREAM_DRAW);
|
||||||
|
|
|
@ -16,14 +16,19 @@ use protocol;
|
||||||
use world;
|
use world;
|
||||||
use world::block;
|
use world::block;
|
||||||
use rand::{self, Rng};
|
use rand::{self, Rng};
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
use resources;
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
conn: Option<protocol::Conn>,
|
conn: Option<protocol::Conn>,
|
||||||
pub world: world::World,
|
pub world: world::World,
|
||||||
|
|
||||||
|
resources: Arc<RwLock<resources::Manager>>,
|
||||||
|
version: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
pub fn dummy_server() -> Server {
|
pub fn dummy_server(resources: Arc<RwLock<resources::Manager>>) -> Server {
|
||||||
let mut world = world::World::new();
|
let mut world = world::World::new();
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
for x in -7*16 .. 7*16 {
|
for x in -7*16 .. 7*16 {
|
||||||
|
@ -34,9 +39,21 @@ impl Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let version = resources.read().unwrap().version();
|
||||||
Server {
|
Server {
|
||||||
conn: None,
|
conn: None,
|
||||||
world: world,
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
pub fn capture_snapshot(&self, x: i32, y: i32, z: i32, w: i32, h: i32, d: i32) -> Snapshot {
|
||||||
use std::cmp::{min, max};
|
use std::cmp::{min, max};
|
||||||
let mut snapshot = Snapshot {
|
let mut snapshot = Snapshot {
|
||||||
|
|
Loading…
Reference in New Issue