Make adding/removing blocks work on the entire world
This commit is contained in:
parent
65f0a706d3
commit
6c6a321a0c
7 changed files with 274 additions and 65 deletions
77
src/chunk.rs
77
src/chunk.rs
|
@ -2,7 +2,7 @@ use std::{collections::VecDeque, convert::TryInto, usize};
|
|||
|
||||
use crate::{cube, quad::Quad, vertex::Vertex};
|
||||
use ahash::{AHashMap, AHashSet};
|
||||
use cgmath::{InnerSpace, Vector3};
|
||||
use cgmath::{InnerSpace, Vector3, Zero};
|
||||
use noise::utils::{NoiseMapBuilder, PlaneMapBuilder};
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
@ -58,7 +58,6 @@ type ChunkBlocks = [[[Option<Block>; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE];
|
|||
|
||||
pub struct Chunk {
|
||||
pub blocks: ChunkBlocks,
|
||||
pub highlighted: Option<Vector3<usize>>,
|
||||
}
|
||||
|
||||
impl Chunk {
|
||||
|
@ -139,10 +138,7 @@ impl Chunk {
|
|||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
blocks,
|
||||
highlighted: None,
|
||||
}
|
||||
Self { blocks }
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
@ -221,9 +217,12 @@ impl Chunk {
|
|||
offset: Vector3<i32>,
|
||||
culled: AHashMap<(usize, usize), (BlockType, FaceFlags)>,
|
||||
queue: &mut VecDeque<(usize, usize)>,
|
||||
) -> Vec<(BlockType, i32, Vector3<i32>, Quad, bool, FaceFlags)> {
|
||||
let mut quads: Vec<(BlockType, i32, Vector3<i32>, Quad, bool, FaceFlags)> = Vec::new();
|
||||
highlighted: Option<&(Vector3<usize>, Vector3<i32>)>,
|
||||
) -> Vec<(BlockType, i32, Vector3<i32>, Quad, Vector3<i32>, FaceFlags)> {
|
||||
let mut quads: Vec<(BlockType, i32, Vector3<i32>, Quad, Vector3<i32>, FaceFlags)> =
|
||||
Vec::new();
|
||||
let mut visited = AHashSet::new();
|
||||
let hl = highlighted.map(|h| h.0);
|
||||
while let Some((x, z)) = queue.pop_front() {
|
||||
if visited.contains(&(x, z)) {
|
||||
continue;
|
||||
|
@ -233,15 +232,29 @@ impl Chunk {
|
|||
if let Some(&(block_type, visible_faces)) = &culled.get(&(x, z)) {
|
||||
let mut quad_faces = visible_faces;
|
||||
|
||||
if self.highlighted == Some(Vector3::new(x, y, z)) {
|
||||
if hl == Some(Vector3::new(x, y, z)) {
|
||||
let quad = Quad::new(x as i32, z as i32, 1, 1);
|
||||
quads.push((block_type, y as i32, offset, quad, true, quad_faces));
|
||||
quads.push((
|
||||
block_type,
|
||||
y as i32,
|
||||
offset,
|
||||
quad,
|
||||
highlighted.unwrap().1,
|
||||
quad_faces,
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
if block_type == BlockType::Water {
|
||||
let quad = Quad::new(x as i32, z as i32, 1, 1);
|
||||
quads.push((block_type, y as i32, offset, quad, false, quad_faces));
|
||||
quads.push((
|
||||
block_type,
|
||||
y as i32,
|
||||
offset,
|
||||
quad,
|
||||
Vector3::zero(),
|
||||
quad_faces,
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -250,9 +263,7 @@ impl Chunk {
|
|||
for x_ in x..CHUNK_SIZE {
|
||||
xmax = x_ + 1;
|
||||
|
||||
if visited.contains(&(xmax, z))
|
||||
|| self.highlighted == Some(Vector3::new(xmax, y, z))
|
||||
{
|
||||
if visited.contains(&(xmax, z)) || hl == Some(Vector3::new(xmax, y, z)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -274,9 +285,7 @@ impl Chunk {
|
|||
zmax = z_ + 1;
|
||||
|
||||
for x_ in x..xmax {
|
||||
if visited.contains(&(x_, zmax))
|
||||
|| self.highlighted == Some(Vector3::new(x_, y, zmax))
|
||||
{
|
||||
if visited.contains(&(x_, zmax)) || hl == Some(Vector3::new(x_, y, zmax)) {
|
||||
break 'z;
|
||||
}
|
||||
|
||||
|
@ -296,7 +305,14 @@ impl Chunk {
|
|||
}
|
||||
|
||||
let quad = Quad::new(x as i32, z as i32, (xmax - x) as i32, (zmax - z) as i32);
|
||||
quads.push((block_type, y as i32, offset, quad, false, quad_faces));
|
||||
quads.push((
|
||||
block_type,
|
||||
y as i32,
|
||||
offset,
|
||||
quad,
|
||||
Vector3::zero(),
|
||||
quad_faces,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,7 +320,7 @@ impl Chunk {
|
|||
}
|
||||
|
||||
fn quads_to_geometry(
|
||||
quads: Vec<(BlockType, i32, Vector3<i32>, Quad, bool, FaceFlags)>,
|
||||
quads: Vec<(BlockType, i32, Vector3<i32>, Quad, Vector3<i32>, FaceFlags)>,
|
||||
) -> (Vec<Vertex>, Vec<u16>) {
|
||||
let mut vertices = Vec::new();
|
||||
let mut indices = Vec::new();
|
||||
|
@ -329,12 +345,17 @@ impl Chunk {
|
|||
(vertices, indices)
|
||||
}
|
||||
|
||||
pub fn to_geometry(&self, offset: Vector3<i32>) -> (Vec<Vertex>, Vec<u16>) {
|
||||
let mut quads: Vec<(BlockType, i32, Vector3<i32>, Quad, bool, FaceFlags)> = Vec::new();
|
||||
pub fn to_geometry(
|
||||
&self,
|
||||
offset: Vector3<i32>,
|
||||
highlighted: Option<&(Vector3<usize>, Vector3<i32>)>,
|
||||
) -> (Vec<Vertex>, Vec<u16>) {
|
||||
let mut quads: Vec<(BlockType, i32, Vector3<i32>, Quad, Vector3<i32>, FaceFlags)> =
|
||||
Vec::new();
|
||||
|
||||
for y in 0..CHUNK_SIZE {
|
||||
let (culled, mut queue) = self.cull_layer(y);
|
||||
let mut layer_quads = self.layer_to_quads(y, offset, culled, &mut queue);
|
||||
let mut layer_quads = self.layer_to_quads(y, offset, culled, &mut queue, highlighted);
|
||||
quads.append(&mut layer_quads);
|
||||
}
|
||||
|
||||
|
@ -342,11 +363,11 @@ impl Chunk {
|
|||
}
|
||||
|
||||
pub fn get_block(&self, x: usize, y: usize, z: usize) -> Option<&Block> {
|
||||
self.blocks
|
||||
.get(y)
|
||||
.and_then(|blocks| blocks.get(z))
|
||||
.and_then(|blocks| blocks.get(x))
|
||||
.and_then(|block| block.as_ref())
|
||||
if x >= CHUNK_SIZE || y >= CHUNK_SIZE || z >= CHUNK_SIZE {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.blocks[y][z][x].as_ref()
|
||||
}
|
||||
|
||||
fn calc_scale(vector: Vector3<f32>, scalar: f32) -> f32 {
|
||||
|
@ -360,9 +381,11 @@ impl Chunk {
|
|||
#[allow(dead_code)]
|
||||
pub fn raycast(
|
||||
&self,
|
||||
chunk_position: Vector3<usize>,
|
||||
origin: Vector3<f32>,
|
||||
direction: Vector3<f32>,
|
||||
) -> Option<(Vector3<usize>, Vector3<i32>)> {
|
||||
let origin = origin - chunk_position.map(|x| (x * 16) as f32);
|
||||
let scale = Vector3::new(
|
||||
Self::calc_scale(direction, direction.x),
|
||||
Self::calc_scale(direction, direction.y),
|
||||
|
|
10
src/cube.rs
10
src/cube.rs
|
@ -14,7 +14,7 @@ pub fn vertices(
|
|||
z_height: f32,
|
||||
offset: Vector3<i32>,
|
||||
texture_indices: (usize, usize, usize, usize, usize, usize),
|
||||
highlighted: bool,
|
||||
highlighted: Vector3<i32>,
|
||||
visible_faces: FaceFlags,
|
||||
start_index: u16,
|
||||
) -> (Vec<Vertex>, Vec<u16>) {
|
||||
|
@ -27,14 +27,15 @@ pub fn vertices(
|
|||
let z = (quad.y + offset.z) as f32;
|
||||
|
||||
let t = texture_indices;
|
||||
let highlighted = highlighted as i32;
|
||||
|
||||
let mut current_index = start_index;
|
||||
let mut vertices = Vec::new();
|
||||
let mut indices = Vec::new();
|
||||
let highlighted: [f32; 3] = (-highlighted).map(|x| x as f32).into();
|
||||
|
||||
if visible_faces & FACE_LEFT == FACE_LEFT {
|
||||
let normal = [-1.0, 0.0, 0.0];
|
||||
let highlighted = (normal == highlighted) as i32;
|
||||
vertices.extend(&[
|
||||
Vertex { position: [x, y, z ], texture_coordinates: [h, 1.0, t.0 as f32], normal, highlighted },
|
||||
Vertex { position: [x, y, z + h], texture_coordinates: [0.0, 1.0, t.0 as f32], normal, highlighted },
|
||||
|
@ -50,6 +51,7 @@ pub fn vertices(
|
|||
|
||||
if visible_faces & FACE_RIGHT == FACE_RIGHT {
|
||||
let normal = [1.0, 0.0, 0.0];
|
||||
let highlighted = (normal == highlighted) as i32;
|
||||
vertices.extend(&[
|
||||
Vertex { position: [x + w, y, z ], texture_coordinates: [0.0, 1.0, t.1 as f32], normal, highlighted },
|
||||
Vertex { position: [x + w, y, z + h], texture_coordinates: [h, 1.0, t.1 as f32], normal, highlighted },
|
||||
|
@ -65,6 +67,7 @@ pub fn vertices(
|
|||
|
||||
if visible_faces & FACE_BACK == FACE_BACK {
|
||||
let normal = [0.0, 0.0, -1.0];
|
||||
let highlighted = (normal == highlighted) as i32;
|
||||
vertices.extend(&[
|
||||
Vertex { position: [x, y, z], texture_coordinates: [w, 1.0, t.2 as f32], normal, highlighted },
|
||||
Vertex { position: [x, y + zh, z], texture_coordinates: [w, 0.0, t.2 as f32], normal, highlighted },
|
||||
|
@ -80,6 +83,7 @@ pub fn vertices(
|
|||
|
||||
if visible_faces & FACE_FRONT == FACE_FRONT {
|
||||
let normal = [0.0, 0.0, 1.0];
|
||||
let highlighted = (normal == highlighted) as i32;
|
||||
vertices.extend(&[
|
||||
Vertex { position: [x, y, z + h], texture_coordinates: [0.0, 1.0, t.3 as f32], normal, highlighted },
|
||||
Vertex { position: [x, y + zh, z + h], texture_coordinates: [0.0, 0.0, t.3 as f32], normal, highlighted },
|
||||
|
@ -95,6 +99,7 @@ pub fn vertices(
|
|||
|
||||
if visible_faces & FACE_BOTTOM == FACE_BOTTOM {
|
||||
let normal = [0.0, -1.0, 0.0];
|
||||
let highlighted = (normal == highlighted) as i32;
|
||||
vertices.extend(&[
|
||||
Vertex { position: [x, y, z ], texture_coordinates: [w, 0.0, t.4 as f32], normal, highlighted },
|
||||
Vertex { position: [x, y, z + h], texture_coordinates: [w, h, t.4 as f32], normal, highlighted },
|
||||
|
@ -110,6 +115,7 @@ pub fn vertices(
|
|||
|
||||
if visible_faces & FACE_TOP == FACE_TOP {
|
||||
let normal = [0.0, 1.0, 0.0];
|
||||
let highlighted = (normal == highlighted) as i32;
|
||||
vertices.extend(&[
|
||||
Vertex { position: [x, y + zh, z ], texture_coordinates: [0.0, 0.0, t.5 as f32], normal, highlighted },
|
||||
Vertex { position: [x, y + zh, z + h], texture_coordinates: [0.0, h, t.5 as f32], normal, highlighted },
|
||||
|
|
|
@ -30,6 +30,8 @@ struct VertexOutput {
|
|||
[[location(3)]] highlighted: i32;
|
||||
};
|
||||
|
||||
let pi: f32 = 3.14159265359;
|
||||
|
||||
[[stage(vertex)]]
|
||||
fn main(model: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
|
@ -80,7 +82,7 @@ fn main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
|
|||
|
||||
var result: vec3<f32> = (ambient_color + diffuse_color + specular_color) * object_color.xyz;
|
||||
if (in.highlighted != 0) {
|
||||
result = result + 0.3;
|
||||
result = result + 0.25 + sin(time.time * pi) * 0.07;
|
||||
}
|
||||
|
||||
return vec4<f32>(result, object_color.a);
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
mod hud;
|
||||
mod world;
|
||||
pub mod hud_state;
|
||||
pub mod world_state;
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use cgmath::{EuclideanSpace, InnerSpace, Rad, Vector3, Zero};
|
||||
use cgmath::{EuclideanSpace, InnerSpace, Rad, Vector3};
|
||||
use winit::{
|
||||
event::{DeviceEvent, ElementState, KeyboardInput, VirtualKeyCode},
|
||||
window::Window,
|
||||
};
|
||||
|
||||
use hud::HudState;
|
||||
use world::WorldState;
|
||||
use hud_state::HudState;
|
||||
use world_state::WorldState;
|
||||
|
||||
use crate::chunk::{Block, BlockType};
|
||||
use crate::chunk::{Block, BlockType, CHUNK_SIZE};
|
||||
|
||||
pub struct State {
|
||||
pub window_size: winit::dpi::PhysicalSize<u32>,
|
||||
|
@ -30,6 +30,7 @@ pub struct State {
|
|||
forward_speed: f32,
|
||||
up_speed: f32,
|
||||
pub mouse_grabbed: bool,
|
||||
sprinting: bool,
|
||||
}
|
||||
|
||||
impl State {
|
||||
|
@ -111,6 +112,7 @@ impl State {
|
|||
right_speed: 0.0,
|
||||
forward_speed: 0.0,
|
||||
up_speed: 0.0,
|
||||
sprinting: false,
|
||||
mouse_grabbed: false,
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +143,8 @@ impl State {
|
|||
VirtualKeyCode::S => self.forward_speed -= amount,
|
||||
VirtualKeyCode::A => self.right_speed -= amount,
|
||||
VirtualKeyCode::D => self.right_speed += amount,
|
||||
VirtualKeyCode::LControl => self.up_speed -= amount,
|
||||
VirtualKeyCode::LShift => self.up_speed -= amount,
|
||||
VirtualKeyCode::LControl => self.sprinting = state == &ElementState::Pressed,
|
||||
VirtualKeyCode::Space => self.up_speed += amount,
|
||||
VirtualKeyCode::F1 if state == &ElementState::Pressed => self
|
||||
.world_state
|
||||
|
@ -164,17 +167,33 @@ impl State {
|
|||
|
||||
fn update_aim(&mut self) {
|
||||
let camera = &self.world_state.camera;
|
||||
let chunk = &mut self.world_state.world.chunks[0][0][0];
|
||||
|
||||
let position = chunk
|
||||
.raycast(camera.position.to_vec(), camera.direction())
|
||||
.map(|(position, _)| position);
|
||||
let old = self.world_state.highlighted;
|
||||
let new = self
|
||||
.world_state
|
||||
.world
|
||||
.raycast(camera.position.to_vec(), camera.direction());
|
||||
|
||||
if position != chunk.highlighted {
|
||||
chunk.highlighted = position;
|
||||
println!("aiming at {:?}", position);
|
||||
self.world_state
|
||||
.update_chunk_geometry(&self.render_device, Vector3::zero());
|
||||
let old_chunk = old.map(|h| h.0 / CHUNK_SIZE);
|
||||
let new_chunk = new.map(|h| h.0 / CHUNK_SIZE);
|
||||
|
||||
if old != new {
|
||||
self.world_state.highlighted = new;
|
||||
|
||||
if let Some(old_chunk_) = old_chunk {
|
||||
self.world_state
|
||||
.update_chunk_geometry(&self.render_device, old_chunk_);
|
||||
}
|
||||
|
||||
if let Some(new_chunk_) = new_chunk {
|
||||
// Don't update the same chunk twice
|
||||
if old_chunk != new_chunk {
|
||||
self.world_state
|
||||
.update_chunk_geometry(&self.render_device, new_chunk_);
|
||||
}
|
||||
}
|
||||
|
||||
// println!("Aiming at {:?}", new);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,26 +216,30 @@ impl State {
|
|||
state: ElementState::Pressed,
|
||||
} if self.mouse_grabbed => {
|
||||
let camera = &self.world_state.camera;
|
||||
let chunk = &mut self.world_state.world.chunks[0][0][0];
|
||||
|
||||
let world = &mut self.world_state.world;
|
||||
if let Some((pos, axis)) =
|
||||
chunk.raycast(camera.position.to_vec(), camera.direction())
|
||||
world.raycast(camera.position.to_vec(), camera.direction())
|
||||
{
|
||||
dbg!(&pos);
|
||||
if *button == 1 {
|
||||
chunk.blocks[pos.y][pos.z][pos.x].take();
|
||||
dbg!(&pos);
|
||||
world.set_block(pos.x as isize, pos.y as isize, pos.z as isize, None);
|
||||
self.world_state
|
||||
.update_chunk_geometry(&self.render_device, Vector3::zero());
|
||||
.update_chunk_geometry(&self.render_device, pos / 16);
|
||||
} else if *button == 3 {
|
||||
let new_pos = pos.map(|x| x as i32) - axis;
|
||||
dbg!(&axis, &new_pos);
|
||||
chunk.blocks[new_pos.y as usize][new_pos.z as usize][new_pos.x as usize] =
|
||||
|
||||
world.set_block(
|
||||
new_pos.x as isize,
|
||||
new_pos.y as isize,
|
||||
new_pos.z as isize,
|
||||
Some(Block {
|
||||
block_type: BlockType::Cobblestone,
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
self.world_state
|
||||
.update_chunk_geometry(&self.render_device, Vector3::zero());
|
||||
.update_chunk_geometry(&self.render_device, pos / 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -231,13 +254,16 @@ impl State {
|
|||
let (yaw_sin, yaw_cos) = self.world_state.camera.yaw.0.sin_cos();
|
||||
|
||||
let forward = Vector3::new(yaw_cos, 0.0, yaw_sin).normalize();
|
||||
self.world_state.camera.position += forward * self.forward_speed * 30.0 * dt_secs;
|
||||
self.world_state.camera.position +=
|
||||
forward * self.forward_speed * 30.0 * (self.sprinting as i32 * 2 + 1) as f32 * dt_secs;
|
||||
|
||||
let right = Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize();
|
||||
self.world_state.camera.position += right * self.right_speed * 30.0 * dt_secs;
|
||||
self.world_state.camera.position +=
|
||||
right * self.right_speed * 30.0 * (self.sprinting as i32 * 2 + 1) as f32 * dt_secs;
|
||||
|
||||
let up = Vector3::new(0.0, 1.0, 0.0).normalize();
|
||||
self.world_state.camera.position += up * self.up_speed * 30.0 * dt_secs;
|
||||
self.world_state.camera.position +=
|
||||
up * self.up_speed * 30.0 * (self.sprinting as i32 * 2 + 1) as f32 * dt_secs;
|
||||
|
||||
self.world_state.update(dt, &self.render_queue);
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ pub struct WorldState {
|
|||
wireframe: bool,
|
||||
shader: wgpu::ShaderModule,
|
||||
render_pipeline_layout: wgpu::PipelineLayout,
|
||||
pub highlighted: Option<(Vector3<usize>, Vector3<i32>)>,
|
||||
}
|
||||
|
||||
impl WorldState {
|
||||
|
@ -201,7 +202,7 @@ impl WorldState {
|
|||
pub fn update_world_geometry(&mut self, render_device: &wgpu::Device) {
|
||||
let instant = Instant::now();
|
||||
|
||||
let world_geometry = self.world.to_geometry();
|
||||
let world_geometry = self.world.to_geometry(self.highlighted);
|
||||
self.chunk_buffers.clear();
|
||||
for (chunk_position, chunk_vertices, chunk_indices) in world_geometry {
|
||||
self.chunk_buffers.insert(
|
||||
|
@ -231,9 +232,13 @@ impl WorldState {
|
|||
render_device: &wgpu::Device,
|
||||
chunk_position: Vector3<usize>,
|
||||
) {
|
||||
// println!("Updating chunk {:?}", chunk_position);
|
||||
let chunk = &mut self.world.chunks[chunk_position.y][chunk_position.z][chunk_position.x];
|
||||
let offset = chunk_position.map(|f| (f * CHUNK_SIZE) as i32);
|
||||
let (vertices, indices) = chunk.to_geometry(offset);
|
||||
let (vertices, indices) = chunk.to_geometry(
|
||||
offset,
|
||||
World::highlighted_for_chunk(self.highlighted, chunk_position).as_ref(),
|
||||
);
|
||||
|
||||
self.chunk_buffers.insert(
|
||||
chunk_position,
|
||||
|
@ -333,6 +338,7 @@ impl WorldState {
|
|||
world,
|
||||
chunk_buffers: AHashMap::new(),
|
||||
wireframe: false,
|
||||
highlighted: None,
|
||||
};
|
||||
|
||||
world_state.update_world_geometry(render_device);
|
156
src/world.rs
156
src/world.rs
|
@ -1,5 +1,8 @@
|
|||
use crate::{chunk::Chunk, vertex::Vertex};
|
||||
use cgmath::Vector3;
|
||||
use crate::{
|
||||
chunk::{Block, Chunk, CHUNK_SIZE},
|
||||
vertex::Vertex,
|
||||
};
|
||||
use cgmath::{InnerSpace, Vector3};
|
||||
|
||||
pub struct World {
|
||||
pub chunks: Vec<Vec<Vec<Chunk>>>,
|
||||
|
@ -26,15 +29,42 @@ impl World {
|
|||
Self { chunks }
|
||||
}
|
||||
|
||||
pub fn to_geometry(&self) -> Vec<(Vector3<usize>, Vec<Vertex>, Vec<u16>)> {
|
||||
pub fn highlighted_for_chunk(
|
||||
highlighted: Option<(Vector3<usize>, Vector3<i32>)>,
|
||||
chunk_position: Vector3<usize>,
|
||||
) -> Option<(Vector3<usize>, Vector3<i32>)> {
|
||||
let position = chunk_position * 16;
|
||||
if let Some((pos, face)) = highlighted {
|
||||
if pos.x >= position.x
|
||||
&& pos.x < position.x + CHUNK_SIZE
|
||||
&& pos.y >= position.y
|
||||
&& pos.y < position.y + CHUNK_SIZE
|
||||
&& pos.z >= position.z
|
||||
&& pos.z < position.z + CHUNK_SIZE
|
||||
{
|
||||
Some((pos - position, face))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_geometry(
|
||||
&self,
|
||||
highlighted: Option<(Vector3<usize>, Vector3<i32>)>,
|
||||
) -> Vec<(Vector3<usize>, Vec<Vertex>, Vec<u16>)> {
|
||||
let instant = std::time::Instant::now();
|
||||
let mut geometry = Vec::new();
|
||||
|
||||
for (y, chunks_y) in self.chunks.iter().enumerate() {
|
||||
for (z, chunks_z) in chunks_y.iter().enumerate() {
|
||||
for (x, chunk) in chunks_z.iter().enumerate() {
|
||||
let offset = Vector3::new(x as i32 * 16, y as i32 * 16, z as i32 * 16);
|
||||
let (vertices, indices) = chunk.to_geometry(offset);
|
||||
let chunk_position = Vector3::new(x as usize, y as usize, z as usize);
|
||||
let offset = chunk_position.map(|x| x as i32 * 16);
|
||||
let h = Self::highlighted_for_chunk(highlighted, chunk_position);
|
||||
let (vertices, indices) = chunk.to_geometry(offset, h.as_ref());
|
||||
geometry.push((Vector3::new(x, y, z), vertices, indices));
|
||||
}
|
||||
}
|
||||
|
@ -45,4 +75,120 @@ impl World {
|
|||
|
||||
geometry
|
||||
}
|
||||
|
||||
pub fn get_block(&self, x: isize, y: isize, z: isize) -> Option<&Block> {
|
||||
if x < 0 || y < 0 || z < 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let chunk = match self
|
||||
.chunks
|
||||
.get(y as usize / CHUNK_SIZE)
|
||||
.and_then(|chunk_layer| chunk_layer.get(z as usize / CHUNK_SIZE))
|
||||
.and_then(|chunk_row| chunk_row.get(x as usize / CHUNK_SIZE))
|
||||
{
|
||||
Some(v) => v,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
chunk.blocks[y as usize % CHUNK_SIZE][z as usize % CHUNK_SIZE][x as usize % CHUNK_SIZE]
|
||||
.as_ref()
|
||||
}
|
||||
|
||||
pub fn set_block(&mut self, x: isize, y: isize, z: isize, block: Option<Block>) {
|
||||
if x < 0 || y < 0 || z < 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let chunk = match self
|
||||
.chunks
|
||||
.get_mut(y as usize / CHUNK_SIZE)
|
||||
.and_then(|chunk_layer| chunk_layer.get_mut(z as usize / CHUNK_SIZE))
|
||||
.and_then(|chunk_row| chunk_row.get_mut(x as usize / CHUNK_SIZE))
|
||||
{
|
||||
Some(v) => v,
|
||||
None => return,
|
||||
};
|
||||
|
||||
chunk.blocks[y as usize % CHUNK_SIZE][z as usize % CHUNK_SIZE][x as usize % CHUNK_SIZE] =
|
||||
block;
|
||||
}
|
||||
|
||||
fn calc_scale(vector: Vector3<f32>, scalar: f32) -> f32 {
|
||||
if scalar == 0.0 {
|
||||
f32::INFINITY
|
||||
} else {
|
||||
(vector / scalar).magnitude()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn raycast(
|
||||
&self,
|
||||
origin: Vector3<f32>,
|
||||
direction: Vector3<f32>,
|
||||
) -> Option<(Vector3<usize>, Vector3<i32>)> {
|
||||
let direction = direction.normalize();
|
||||
let scale = Vector3::new(
|
||||
Self::calc_scale(direction, direction.x),
|
||||
Self::calc_scale(direction, direction.y),
|
||||
Self::calc_scale(direction, direction.z),
|
||||
);
|
||||
|
||||
let mut position = origin.map(|x| x as i32);
|
||||
let step = direction.map(|x| x.signum() as i32);
|
||||
|
||||
// Truncate the origin
|
||||
let mut lengths = Vector3 {
|
||||
x: if direction.x < 0.0 {
|
||||
(origin.x - position.x as f32) * scale.x
|
||||
} else {
|
||||
(position.x as f32 + 1.0 - origin.x) * scale.x
|
||||
},
|
||||
y: if direction.y < 0.0 {
|
||||
(origin.y - position.y as f32) * scale.y
|
||||
} else {
|
||||
(position.y as f32 + 1.0 - origin.y) * scale.y
|
||||
},
|
||||
z: if direction.z < 0.0 {
|
||||
(origin.z - position.z as f32) * scale.z
|
||||
} else {
|
||||
(position.z as f32 + 1.0 - origin.z) * scale.z
|
||||
},
|
||||
};
|
||||
|
||||
let mut face;
|
||||
|
||||
while lengths.magnitude() < 100.0 {
|
||||
if lengths.x < lengths.y && lengths.x < lengths.z {
|
||||
lengths.x += scale.x;
|
||||
position.x += step.x;
|
||||
face = Vector3::unit_x() * step.x;
|
||||
} else if lengths.y < lengths.x && lengths.y < lengths.z {
|
||||
lengths.y += scale.y;
|
||||
position.y += step.y;
|
||||
face = Vector3::unit_y() * step.y;
|
||||
} else if lengths.z < lengths.x && lengths.z < lengths.y {
|
||||
lengths.z += scale.z;
|
||||
position.z += step.z;
|
||||
face = Vector3::unit_z() * step.z;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
|
||||
if self
|
||||
.get_block(
|
||||
position.x as isize,
|
||||
position.y as isize,
|
||||
position.z as isize,
|
||||
)
|
||||
.is_some()
|
||||
{
|
||||
// Intersection occurred
|
||||
return Some((position.map(|x| x as usize), face));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue