Add block highlighting
This commit is contained in:
parent
3674f1020f
commit
8bf15dc924
5 changed files with 87 additions and 60 deletions
44
src/chunk.rs
44
src/chunk.rs
|
@ -1,5 +1,5 @@
|
|||
use crate::instance::Instance;
|
||||
use cgmath::{Deg, InnerSpace, Quaternion, Rotation3, Vector3};
|
||||
use cgmath::{InnerSpace, Vector3};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
@ -8,15 +8,6 @@ pub enum BlockType {
|
|||
Cobblestone,
|
||||
}
|
||||
|
||||
impl BlockType {
|
||||
pub fn texture_index(self) -> u32 {
|
||||
match self {
|
||||
Self::Dirt => 0,
|
||||
Self::Cobblestone => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Block {
|
||||
pub block_type: BlockType,
|
||||
|
@ -26,6 +17,7 @@ const CHUNK_SIZE: usize = 16;
|
|||
|
||||
pub struct Chunk {
|
||||
pub blocks: [[[Option<Block>; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE],
|
||||
pub highlighted: Option<Vector3<usize>>,
|
||||
}
|
||||
|
||||
impl Chunk {
|
||||
|
@ -38,8 +30,10 @@ impl Chunk {
|
|||
if let Some(block) = block {
|
||||
let position = Vector3::new(x as f32, y as f32, z as f32);
|
||||
let instances = map.entry(block.block_type).or_default();
|
||||
|
||||
instances.push(Instance {
|
||||
position: position.into(),
|
||||
highlighted: (self.highlighted == Some(Vector3::new(x, y, z))) as i32,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +43,14 @@ impl Chunk {
|
|||
map.drain().collect()
|
||||
}
|
||||
|
||||
fn get_block(&self, x: usize, y: usize, z: usize) -> Option<Option<&Block>> {
|
||||
self.blocks
|
||||
.get(y)
|
||||
.and_then(|blocks| blocks.get(z))
|
||||
.and_then(|blocks| blocks.get(x))
|
||||
.map(|block| block.as_ref())
|
||||
}
|
||||
|
||||
fn calc_scale(a: Vector3<f32>, b: f32) -> f32 {
|
||||
if b == 0.0 {
|
||||
f32::INFINITY
|
||||
|
@ -57,8 +59,8 @@ impl Chunk {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn dda(&self, position: Vector3<f32>, direction: Vector3<f32>) -> Option<Vector3<usize>> {
|
||||
assert!(f32::abs(direction.magnitude() - 1.0) < f32::EPSILON);
|
||||
pub fn dda(&self, origin: Vector3<f32>, direction: Vector3<f32>) -> Option<Vector3<usize>> {
|
||||
let direction = direction.normalize();
|
||||
|
||||
let scale = Vector3::new(
|
||||
Self::calc_scale(direction, direction.x),
|
||||
|
@ -66,28 +68,24 @@ impl Chunk {
|
|||
Self::calc_scale(direction, direction.z),
|
||||
);
|
||||
|
||||
let mut new_position = position;
|
||||
let mut position = origin;
|
||||
let mut lengths = Vector3::new(0.0, 0.0, 0.0);
|
||||
loop {
|
||||
let new_lengths = lengths + scale;
|
||||
|
||||
if new_lengths.x < f32::min(new_lengths.y, new_lengths.z) {
|
||||
lengths.x = new_lengths.x;
|
||||
new_position += direction * scale.x;
|
||||
position += direction * scale.x;
|
||||
} else if new_lengths.y < f32::min(new_lengths.x, new_lengths.z) {
|
||||
lengths.y = new_lengths.y;
|
||||
new_position += direction * scale.y;
|
||||
position += direction * scale.y;
|
||||
} else if new_lengths.z < f32::min(new_lengths.x, new_lengths.y) {
|
||||
lengths.z = new_lengths.z;
|
||||
new_position += direction * scale.z;
|
||||
position += direction * scale.z;
|
||||
}
|
||||
|
||||
let pos_usize = new_position.map(|field| field.round() as usize);
|
||||
let block = self
|
||||
.blocks
|
||||
.get(pos_usize.y)
|
||||
.and_then(|a| a.get(pos_usize.z))
|
||||
.and_then(|a| a.get(pos_usize.x));
|
||||
let position_rounded = position.map(|field| field.round() as usize);
|
||||
let block = self.get_block(position_rounded.x, position_rounded.y, position_rounded.z);
|
||||
|
||||
match block {
|
||||
None => {
|
||||
|
@ -97,7 +95,7 @@ impl Chunk {
|
|||
Some(None) => (),
|
||||
Some(Some(_)) => {
|
||||
// Intersected with a block, round position to coordinates and return it.
|
||||
break Some(pos_usize);
|
||||
break Some(position_rounded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
pub struct Instance {
|
||||
pub position: [f32; 3],
|
||||
pub highlighted: i32,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
|
@ -10,11 +11,20 @@ impl Instance {
|
|||
wgpu::VertexBufferLayout {
|
||||
array_stride: mem::size_of::<Self>() as wgpu::BufferAddress,
|
||||
step_mode: wgpu::InputStepMode::Instance,
|
||||
attributes: &[wgpu::VertexAttribute {
|
||||
offset: 0,
|
||||
shader_location: 5,
|
||||
format: wgpu::VertexFormat::Float32x3,
|
||||
}],
|
||||
attributes: &[
|
||||
// position: [f32; 3]
|
||||
wgpu::VertexAttribute {
|
||||
offset: 0,
|
||||
shader_location: 5,
|
||||
format: wgpu::VertexFormat::Float32x3,
|
||||
},
|
||||
// highlighted: i32
|
||||
wgpu::VertexAttribute {
|
||||
offset: 12,
|
||||
shader_location: 6,
|
||||
format: wgpu::VertexFormat::Sint32,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,10 +27,12 @@ struct VertexOutput {
|
|||
[[location(0)]] texture_coordinates: vec2<f32>;
|
||||
[[location(1)]] world_normal: vec3<f32>;
|
||||
[[location(2)]] world_position: vec3<f32>;
|
||||
[[location(3)]] highlighted: i32;
|
||||
};
|
||||
|
||||
struct InstanceInput {
|
||||
[[location(5)]] position: vec3<f32>;
|
||||
[[location(6)]] highlighted: i32;
|
||||
};
|
||||
|
||||
|
||||
|
@ -41,6 +43,7 @@ fn main(model: VertexInput, instance: InstanceInput) -> VertexOutput {
|
|||
out.world_normal = model.normal;
|
||||
out.world_position = model.position + instance.position;
|
||||
out.clip_position = uniforms.view_projection * vec4<f32>(out.world_position, 1.0);
|
||||
out.highlighted = instance.highlighted;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -65,6 +68,10 @@ fn main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
|
|||
let specular_strength = pow(max(dot(in.world_normal, half_direction), 0.0), 32.0);
|
||||
let specular_color = specular_strength * light.color;
|
||||
|
||||
let result = (ambient_color + diffuse_color + specular_color) * object_color.xyz;
|
||||
var result: vec3<f32> = (ambient_color + diffuse_color + specular_color) * object_color.xyz;
|
||||
if (in.highlighted != 0) {
|
||||
result = result + 0.5;
|
||||
}
|
||||
|
||||
return vec4<f32>(result, object_color.a);
|
||||
}
|
||||
|
|
38
src/state.rs
38
src/state.rs
|
@ -1,6 +1,6 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use cgmath::{InnerSpace, Rad};
|
||||
use cgmath::{EuclideanSpace, InnerSpace, Rad};
|
||||
use wgpu::util::{BufferInitDescriptor, DeviceExt};
|
||||
use winit::{
|
||||
event::{DeviceEvent, ElementState, KeyboardInput, VirtualKeyCode},
|
||||
|
@ -21,12 +21,12 @@ pub const CROSSHAIR_VERTICES: &[Vertex] = &[
|
|||
},
|
||||
Vertex {
|
||||
position: [UI_SCALE_X * 8.0, UI_SCALE_Y * 8.0, 0.0],
|
||||
texture_coordinates: [256.0 / 256.0, 0.0 / 256.0],
|
||||
texture_coordinates: [1.0, 0.0 / 256.0],
|
||||
normal: [0.0, 0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [UI_SCALE_X * 8.0, -UI_SCALE_Y * 8.0, 0.0],
|
||||
texture_coordinates: [256.0 / 256.0, 16.0 / 256.0],
|
||||
texture_coordinates: [1.0, 16.0 / 256.0],
|
||||
normal: [0.0, 0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
|
@ -77,7 +77,6 @@ pub struct State {
|
|||
|
||||
world_state: WorldState,
|
||||
|
||||
ui_texture_bind_group_layout: wgpu::BindGroupLayout,
|
||||
ui_texture_bind_group: wgpu::BindGroup,
|
||||
ui_render_pipeline: wgpu::RenderPipeline,
|
||||
ui_crosshair_vertex_buffer: wgpu::Buffer,
|
||||
|
@ -302,7 +301,6 @@ impl State {
|
|||
|
||||
ui_render_pipeline,
|
||||
ui_texture_bind_group,
|
||||
ui_texture_bind_group_layout,
|
||||
ui_crosshair_vertex_buffer,
|
||||
ui_crosshair_index_buffer,
|
||||
|
||||
|
@ -346,17 +344,27 @@ impl State {
|
|||
}
|
||||
|
||||
fn update_camera(&mut self, dx: f64, dy: f64) {
|
||||
self.world_state.camera.yaw += Rad(dx as f32 * 0.003);
|
||||
self.world_state.camera.pitch -= Rad(dy as f32 * 0.003);
|
||||
let camera = &mut self.world_state.camera;
|
||||
camera.yaw += Rad(dx as f32 * 0.003);
|
||||
camera.pitch -= Rad(dy as f32 * 0.003);
|
||||
|
||||
if self.world_state.camera.pitch < Rad::from(cgmath::Deg(-80.0)) {
|
||||
self.world_state.camera.pitch = Rad::from(cgmath::Deg(-80.0));
|
||||
} else if self.world_state.camera.pitch > Rad::from(cgmath::Deg(89.9)) {
|
||||
self.world_state.camera.pitch = Rad::from(cgmath::Deg(89.9));
|
||||
if camera.pitch < Rad::from(cgmath::Deg(-80.0)) {
|
||||
camera.pitch = Rad::from(cgmath::Deg(-80.0));
|
||||
} else if camera.pitch > Rad::from(cgmath::Deg(89.9)) {
|
||||
camera.pitch = Rad::from(cgmath::Deg(89.9));
|
||||
}
|
||||
}
|
||||
|
||||
fn update_aim(&mut self) {}
|
||||
fn update_aim(&mut self) {
|
||||
let camera = &self.world_state.camera;
|
||||
let chunk = &mut self.world_state.chunk;
|
||||
|
||||
let coords = chunk.dda(camera.position.to_vec(), camera.direction());
|
||||
if coords != chunk.highlighted {
|
||||
chunk.highlighted = coords;
|
||||
self.world_state.update_chunk(&self.render_queue);
|
||||
}
|
||||
}
|
||||
|
||||
fn input_mouse(&mut self, dx: f64, dy: f64) {
|
||||
if self.mouse_grabbed {
|
||||
|
@ -443,10 +451,8 @@ impl State {
|
|||
wgpu::IndexFormat::Uint16,
|
||||
);
|
||||
|
||||
for (i, (block_type, instance_list)) in
|
||||
self.world_state.instance_lists.iter().enumerate()
|
||||
{
|
||||
let (_, instance_buffer) = &self.world_state.instance_buffers[i];
|
||||
for (block_type, instance_list) in &self.world_state.instance_lists {
|
||||
let instance_buffer = &self.world_state.instance_buffers[block_type];
|
||||
|
||||
let texture_bind_group = &self.world_state.texture_bind_groups[block_type];
|
||||
render_pass.set_bind_group(0, texture_bind_group, &[]);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use cgmath::EuclideanSpace;
|
||||
use wgpu::util::{BufferInitDescriptor, DeviceExt};
|
||||
use winit::dpi::PhysicalSize;
|
||||
|
||||
|
@ -26,9 +25,10 @@ pub struct WorldState {
|
|||
pub instance_lists: Vec<(BlockType, Vec<Instance>)>,
|
||||
pub vertex_buffer: wgpu::Buffer,
|
||||
pub index_buffer: wgpu::Buffer,
|
||||
pub instance_buffers: Vec<(BlockType, wgpu::Buffer)>,
|
||||
pub instance_buffers: HashMap<BlockType, wgpu::Buffer>,
|
||||
pub depth_texture: Texture,
|
||||
pub light_bind_group: wgpu::BindGroup,
|
||||
pub chunk: Chunk,
|
||||
}
|
||||
|
||||
impl WorldState {
|
||||
|
@ -294,7 +294,7 @@ impl WorldState {
|
|||
chunk: &Chunk,
|
||||
) -> (
|
||||
Vec<(BlockType, Vec<Instance>)>,
|
||||
Vec<(BlockType, wgpu::Buffer)>,
|
||||
HashMap<BlockType, wgpu::Buffer>,
|
||||
) {
|
||||
let instance_lists = chunk.to_instances();
|
||||
|
||||
|
@ -306,7 +306,7 @@ impl WorldState {
|
|||
render_device.create_buffer_init(&BufferInitDescriptor {
|
||||
label: Some("instance_buffer"),
|
||||
contents: bytemuck::cast_slice(&instance_list),
|
||||
usage: wgpu::BufferUsage::VERTEX,
|
||||
usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST,
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
@ -315,12 +315,24 @@ impl WorldState {
|
|||
(instance_lists, instance_buffers)
|
||||
}
|
||||
|
||||
pub fn update_chunk(&mut self, render_queue: &wgpu::Queue) {
|
||||
let instance_lists = self.chunk.to_instances();
|
||||
|
||||
for (block_type, instance_list) in instance_lists {
|
||||
if let Some(instance_buffer) = self.instance_buffers.get_mut(&block_type) {
|
||||
render_queue.write_buffer(instance_buffer, 0, bytemuck::cast_slice(&instance_list));
|
||||
} else {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
render_device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
swap_chain_descriptor: &wgpu::SwapChainDescriptor,
|
||||
) -> WorldState {
|
||||
let mut chunk = Chunk {
|
||||
let chunk = Chunk {
|
||||
blocks: [
|
||||
[[Some(Block {
|
||||
block_type: BlockType::Cobblestone,
|
||||
|
@ -343,6 +355,7 @@ impl WorldState {
|
|||
[[None; 16]; 16],
|
||||
[[None; 16]; 16],
|
||||
],
|
||||
highlighted: None,
|
||||
};
|
||||
|
||||
let (world_texture_layout, texture_bind_groups) =
|
||||
|
@ -350,14 +363,6 @@ impl WorldState {
|
|||
|
||||
let (camera, projection) = Self::create_camera(&swap_chain_descriptor);
|
||||
|
||||
let pointy_at = chunk
|
||||
.dda(camera.position.to_vec(), camera.direction())
|
||||
.unwrap();
|
||||
|
||||
chunk.blocks[pointy_at.y][pointy_at.z][pointy_at.x] = Some(Block {
|
||||
block_type: BlockType::Cobblestone,
|
||||
});
|
||||
|
||||
let (uniforms, uniform_buffer, world_uniform_layout, uniform_bind_group) =
|
||||
Self::create_uniforms(&camera, &projection, &render_device);
|
||||
|
||||
|
@ -398,12 +403,13 @@ impl WorldState {
|
|||
texture_bind_groups,
|
||||
camera,
|
||||
projection,
|
||||
light_bind_group,
|
||||
instance_lists,
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
instance_lists,
|
||||
instance_buffers,
|
||||
depth_texture,
|
||||
light_bind_group,
|
||||
chunk,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue